Merge branch 'for_david' of git://git.open-mesh.org/linux-merge
authorDavid S. Miller <davem@davemloft.net>
Sat, 26 Nov 2011 19:26:24 +0000 (14:26 -0500)
committerDavid S. Miller <davem@davemloft.net>
Sat, 26 Nov 2011 19:26:24 +0000 (14:26 -0500)
1071 files changed:
.mailmap
Documentation/ABI/testing/sysfs-block
Documentation/DocBook/drm.tmpl
Documentation/blockdev/cciss.txt
Documentation/cgroups/freezer-subsystem.txt
Documentation/cgroups/net_prio.txt [new file with mode: 0644]
Documentation/networking/ieee802154.txt
Documentation/networking/ip-sysctl.txt
Documentation/networking/team.txt [new file with mode: 0644]
Documentation/sound/alsa/HD-Audio-Models.txt
Documentation/sound/alsa/HD-Audio.txt
Kbuild
MAINTAINERS
Makefile
arch/alpha/include/asm/socket.h
arch/arm/boot/Makefile
arch/arm/boot/dts/tegra-ventana.dts
arch/arm/include/asm/hardware/cache-l2x0.h
arch/arm/include/asm/mach/arch.h
arch/arm/include/asm/socket.h
arch/arm/include/asm/unistd.h
arch/arm/kernel/calls.S
arch/arm/kernel/head.S
arch/arm/kernel/machine_kexec.c
arch/arm/kernel/setup.c
arch/arm/mach-at91/at91cap9_devices.c
arch/arm/mach-at91/at91rm9200_devices.c
arch/arm/mach-at91/at91sam9260_devices.c
arch/arm/mach-at91/at91sam9261_devices.c
arch/arm/mach-at91/at91sam9263_devices.c
arch/arm/mach-at91/at91sam9g45_devices.c
arch/arm/mach-at91/at91sam9rl_devices.c
arch/arm/mach-at91/board-yl-9200.c
arch/arm/mach-at91/include/mach/vmalloc.h
arch/arm/mach-bcmring/core.c
arch/arm/mach-bcmring/dma.c
arch/arm/mach-imx/Makefile.boot
arch/arm/mach-imx/clock-imx6q.c
arch/arm/mach-msm/Makefile
arch/arm/mach-msm/board-msm7x30.c
arch/arm/mach-msm/board-msm8960.c
arch/arm/mach-msm/board-msm8x60.c
arch/arm/mach-msm/scm.c
arch/arm/mach-mx5/clock-mx51-mx53.c
arch/arm/mach-mxs/mach-mx28evk.c
arch/arm/mach-picoxcell/include/mach/debug-macro.S
arch/arm/mach-shmobile/Makefile
arch/arm/mach-shmobile/board-ag5evm.c
arch/arm/mach-shmobile/board-ap4evb.c
arch/arm/mach-shmobile/board-kota2.c
arch/arm/mach-shmobile/clock-sh7372.c
arch/arm/mach-shmobile/cpuidle.c
arch/arm/mach-shmobile/include/mach/common.h
arch/arm/mach-shmobile/include/mach/sh73a0.h
arch/arm/mach-shmobile/pfc-sh7367.c
arch/arm/mach-shmobile/pfc-sh7372.c
arch/arm/mach-shmobile/pfc-sh7377.c
arch/arm/mach-shmobile/pfc-sh73a0.c
arch/arm/mach-shmobile/pm-sh7372.c
arch/arm/mach-tegra/board-dt.c
arch/arm/mach-tegra/board-harmony-pinmux.c
arch/arm/mach-tegra/board-paz00-pinmux.c
arch/arm/mach-tegra/board-seaboard-pinmux.c
arch/arm/mach-tegra/board-trimslice-pinmux.c
arch/arm/mach-w90x900/dev.c
arch/arm/mach-w90x900/include/mach/mfp.h
arch/arm/mach-w90x900/include/mach/nuc900_spi.h
arch/arm/mach-w90x900/mfp.c
arch/arm/plat-mxc/Kconfig
arch/arm/plat-mxc/avic.c
arch/arm/plat-mxc/gic.c
arch/arm/plat-mxc/include/mach/entry-macro.S
arch/arm/plat-mxc/tzic.c
arch/avr32/include/asm/socket.h
arch/blackfin/include/asm/bfin_serial.h
arch/blackfin/mach-bf518/boards/ezbrd.c
arch/blackfin/mach-bf518/boards/tcm-bf518.c
arch/blackfin/mach-bf527/boards/ad7160eval.c
arch/blackfin/mach-bf527/boards/cm_bf527.c
arch/blackfin/mach-bf527/boards/ezbrd.c
arch/blackfin/mach-bf527/boards/ezkit.c
arch/blackfin/mach-bf527/boards/tll6527m.c
arch/blackfin/mach-bf533/boards/H8606.c
arch/blackfin/mach-bf533/boards/blackstamp.c
arch/blackfin/mach-bf533/boards/cm_bf533.c
arch/blackfin/mach-bf533/boards/ezkit.c
arch/blackfin/mach-bf533/boards/ip0x.c
arch/blackfin/mach-bf533/boards/stamp.c
arch/blackfin/mach-bf537/boards/cm_bf537e.c
arch/blackfin/mach-bf537/boards/cm_bf537u.c
arch/blackfin/mach-bf537/boards/dnp5370.c
arch/blackfin/mach-bf537/boards/minotaur.c
arch/blackfin/mach-bf537/boards/pnav10.c
arch/blackfin/mach-bf537/boards/stamp.c
arch/blackfin/mach-bf537/boards/tcm_bf537.c
arch/blackfin/mach-bf538/boards/ezkit.c
arch/blackfin/mach-bf548/boards/cm_bf548.c
arch/blackfin/mach-bf548/boards/ezkit.c
arch/blackfin/mach-bf561/boards/acvilon.c
arch/blackfin/mach-bf561/boards/cm_bf561.c
arch/blackfin/mach-bf561/boards/ezkit.c
arch/blackfin/mach-bf561/boards/tepla.c
arch/cris/arch-v10/drivers/Kconfig
arch/cris/arch-v32/drivers/Kconfig
arch/cris/include/asm/socket.h
arch/frv/include/asm/socket.h
arch/h8300/include/asm/socket.h
arch/ia64/include/asm/socket.h
arch/m32r/include/asm/socket.h
arch/m68k/Kconfig
arch/m68k/Kconfig.bus
arch/m68k/Kconfig.devices
arch/m68k/amiga/amiints.c
arch/m68k/amiga/cia.c
arch/m68k/apollo/dn_ints.c
arch/m68k/atari/ataints.c
arch/m68k/bvme6000/config.c
arch/m68k/hp300/time.c
arch/m68k/include/asm/hardirq.h
arch/m68k/include/asm/irq.h
arch/m68k/include/asm/macintosh.h
arch/m68k/include/asm/q40ints.h
arch/m68k/include/asm/socket.h
arch/m68k/kernel/Makefile
arch/m68k/kernel/entry_mm.S
arch/m68k/kernel/ints.c
arch/m68k/mac/baboon.c
arch/m68k/mac/iop.c
arch/m68k/mac/macints.c
arch/m68k/mac/oss.c
arch/m68k/mac/psc.c
arch/m68k/mac/via.c
arch/m68k/mvme147/config.c
arch/m68k/mvme16x/config.c
arch/m68k/q40/q40ints.c
arch/m68k/sun3/sun3ints.c
arch/mips/Makefile
arch/mips/cavium-octeon/flash_setup.c
arch/mips/cavium-octeon/smp.c
arch/mips/emma/common/prom.c
arch/mips/include/asm/mach-bcm47xx/gpio.h
arch/mips/include/asm/socket.h
arch/mips/include/asm/unistd.h
arch/mips/kernel/cevt-r4k.c
arch/mips/kernel/cpufreq/loongson2_clock.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/traps.c
arch/mips/lantiq/clk.c
arch/mips/lantiq/devices.c
arch/mips/lantiq/prom.c
arch/mips/lantiq/setup.c
arch/mips/lantiq/xway/clk-ase.c
arch/mips/lantiq/xway/clk-xway.c
arch/mips/lantiq/xway/devices.c
arch/mips/lantiq/xway/dma.c
arch/mips/lantiq/xway/gpio.c
arch/mips/lantiq/xway/gpio_ebu.c
arch/mips/lantiq/xway/gpio_stp.c
arch/mips/lantiq/xway/prom-ase.c
arch/mips/lantiq/xway/prom-xway.c
arch/mips/lantiq/xway/reset.c
arch/mips/nxp/pnx8550/common/pci.c [deleted file]
arch/mips/nxp/pnx8550/common/setup.c [deleted file]
arch/mips/pci/pci-alchemy.c
arch/mips/pci/pci-lantiq.c
arch/mips/pmc-sierra/yosemite/prom.c
arch/mn10300/include/asm/socket.h
arch/parisc/include/asm/socket.h
arch/powerpc/Kconfig
arch/powerpc/Makefile
arch/powerpc/boot/dts/charon.dts [new file with mode: 0644]
arch/powerpc/configs/52xx/tqm5200_defconfig
arch/powerpc/configs/ppc64_defconfig
arch/powerpc/configs/pseries_defconfig
arch/powerpc/include/asm/atomic.h
arch/powerpc/include/asm/bitops.h
arch/powerpc/include/asm/floppy.h
arch/powerpc/include/asm/futex.h
arch/powerpc/include/asm/kvm.h
arch/powerpc/include/asm/kvm_book3s.h
arch/powerpc/include/asm/lv1call.h
arch/powerpc/include/asm/reg_booke.h
arch/powerpc/include/asm/sections.h
arch/powerpc/include/asm/socket.h
arch/powerpc/include/asm/synch.h
arch/powerpc/include/asm/xics.h
arch/powerpc/kernel/entry_32.S
arch/powerpc/kernel/exceptions-64s.S
arch/powerpc/kernel/jump_label.c
arch/powerpc/kernel/kvm.c
arch/powerpc/kernel/misc_32.S
arch/powerpc/kernel/process.c
arch/powerpc/kernel/prom_init.c
arch/powerpc/kernel/setup_32.c
arch/powerpc/kernel/setup_64.c
arch/powerpc/kernel/signal_32.c
arch/powerpc/kernel/smp.c
arch/powerpc/kernel/traps.c
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/book3s_hv_rmhandlers.S
arch/powerpc/kvm/book3s_pr.c
arch/powerpc/kvm/powerpc.c
arch/powerpc/lib/feature-fixups.c
arch/powerpc/mm/mem.c
arch/powerpc/mm/numa.c
arch/powerpc/platforms/52xx/mpc5200_simple.c
arch/powerpc/platforms/Kconfig
arch/powerpc/platforms/cell/beat.c
arch/powerpc/platforms/cell/celleb_scc_pciex.c
arch/powerpc/platforms/cell/iommu.c
arch/powerpc/platforms/cell/pmu.c
arch/powerpc/platforms/cell/spu_base.c
arch/powerpc/platforms/powermac/pic.c
arch/powerpc/platforms/powermac/smp.c
arch/powerpc/platforms/ps3/device-init.c
arch/powerpc/platforms/ps3/interrupt.c
arch/powerpc/platforms/ps3/platform.h
arch/powerpc/platforms/ps3/repository.c
arch/powerpc/platforms/ps3/smp.c
arch/powerpc/sysdev/fsl_rio.c
arch/powerpc/sysdev/mpic.c
arch/powerpc/sysdev/ppc4xx_soc.c
arch/powerpc/sysdev/xics/xics-common.c
arch/s390/Kconfig
arch/s390/crypto/crypt_s390.h
arch/s390/include/asm/kvm_host.h
arch/s390/include/asm/pgtable.h
arch/s390/include/asm/setup.h
arch/s390/include/asm/socket.h
arch/s390/include/asm/timex.h
arch/s390/include/asm/unistd.h
arch/s390/kernel/compat_wrapper.S
arch/s390/kernel/early.c
arch/s390/kernel/setup.c
arch/s390/kernel/syscalls.S
arch/s390/kernel/topology.c
arch/s390/kernel/vmlinux.lds.S
arch/s390/kvm/diag.c
arch/s390/kvm/intercept.c
arch/s390/kvm/interrupt.c
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/priv.c
arch/s390/kvm/sigp.c
arch/s390/mm/fault.c
arch/sh/include/asm/page.h
arch/sh/include/asm/unistd_32.h
arch/sh/include/asm/unistd_64.h
arch/sh/kernel/cpu/sh2a/setup-sh7203.c
arch/sh/kernel/syscalls_32.S
arch/sh/kernel/syscalls_64.S
arch/sparc/include/asm/pgtable_32.h
arch/sparc/include/asm/pgtable_64.h
arch/sparc/include/asm/socket.h
arch/sparc/include/asm/unistd.h
arch/sparc/kernel/entry.h
arch/sparc/kernel/module.c
arch/sparc/kernel/setup_64.c
arch/sparc/kernel/signal32.c
arch/sparc/kernel/signal_32.c
arch/sparc/kernel/signal_64.c
arch/sparc/kernel/sigutil_64.c
arch/sparc/kernel/systbls_32.S
arch/sparc/kernel/systbls_64.S
arch/sparc/mm/Makefile
arch/sparc/mm/generic_32.c [deleted file]
arch/sparc/mm/generic_64.c [deleted file]
arch/unicore32/Kconfig
arch/unicore32/Kconfig.debug
arch/unicore32/boot/compressed/Makefile
arch/unicore32/include/asm/bitops.h
arch/unicore32/include/asm/processor.h
arch/unicore32/kernel/ksyms.c
arch/unicore32/lib/findbit.S
arch/x86/include/asm/apic.h
arch/x86/include/asm/mach_traps.h
arch/x86/include/asm/mce.h
arch/x86/include/asm/mrst.h
arch/x86/include/asm/x86_init.h
arch/x86/kernel/alternative.c
arch/x86/kernel/apic/apic.c
arch/x86/kernel/apic/io_apic.c
arch/x86/kernel/cpu/mcheck/mce-inject.c
arch/x86/kernel/cpu/mcheck/mce.c
arch/x86/kernel/kvmclock.c
arch/x86/kernel/nmi.c
arch/x86/kernel/setup.c
arch/x86/kernel/x86_init.c
arch/x86/kvm/vmx.c
arch/x86/platform/ce4100/ce4100.c
arch/x86/platform/mrst/mrst.c
arch/x86/platform/mrst/vrtc.c
arch/x86/xen/enlighten.c
arch/x86/xen/grant-table.c
arch/xtensa/include/asm/socket.h
block/blk-core.c
block/blk-map.c
block/genhd.c
crypto/ablkcipher.c
crypto/aead.c
crypto/ahash.c
crypto/blkcipher.c
crypto/crypto_user.c
crypto/pcompress.c
crypto/rng.c
crypto/shash.c
drivers/acpi/processor_idle.c
drivers/ata/ahci.c
drivers/ata/ahci_platform.c
drivers/ata/libata-eh.c
drivers/ata/libata-pmp.c
drivers/ata/libata-scsi.c
drivers/ata/pata_of_platform.c
drivers/ata/sata_sis.c
drivers/base/core.c
drivers/base/power/clock_ops.c
drivers/base/power/main.c
drivers/base/power/opp.c
drivers/base/power/qos.c
drivers/block/cciss.c
drivers/block/cciss_scsi.c
drivers/block/loop.c
drivers/block/paride/pg.c
drivers/bluetooth/ath3k.c
drivers/bluetooth/bfusb.c
drivers/bluetooth/bluecard_cs.c
drivers/bluetooth/bt3c_cs.c
drivers/bluetooth/btuart_cs.c
drivers/bluetooth/btusb.c
drivers/bluetooth/dtl1_cs.c
drivers/bluetooth/hci_vhci.c
drivers/char/agp/intel-gtt.c
drivers/char/random.c
drivers/cpufreq/db8500-cpufreq.c
drivers/devfreq/Kconfig
drivers/devfreq/devfreq.c
drivers/firmware/dmi_scan.c
drivers/gpio/gpio-omap.c
drivers/gpio/gpio-pca953x.c
drivers/gpu/drm/Kconfig
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_crtc_helper.c
drivers/gpu/drm/drm_debugfs.c
drivers/gpu/drm/drm_drv.c
drivers/gpu/drm/drm_irq.c
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/nouveau/nouveau_bios.c
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_channel.c
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/nouveau/nouveau_fbcon.c
drivers/gpu/drm/nouveau/nouveau_fence.c
drivers/gpu/drm/nouveau/nouveau_i2c.c
drivers/gpu/drm/nouveau/nouveau_perf.c
drivers/gpu/drm/nouveau/nouveau_state.c
drivers/gpu/drm/nouveau/nv40_pm.c
drivers/gpu/drm/nouveau/nv50_graph.c
drivers/gpu/drm/nouveau/nv50_grctx.c
drivers/gpu/drm/nouveau/nv50_vram.c
drivers/gpu/drm/nouveau/nvc0_graph.c
drivers/gpu/drm/nouveau/nvc0_grctx.c
drivers/gpu/drm/nouveau/nvc0_vram.c
drivers/gpu/drm/radeon/atombios_crtc.c
drivers/gpu/drm/radeon/atombios_dp.c
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_asic.c
drivers/gpu/drm/radeon/radeon_asic.h
drivers/gpu/drm/radeon/radeon_atombios.c
drivers/gpu/drm/radeon/radeon_benchmark.c
drivers/gpu/drm/radeon/radeon_combios.c
drivers/gpu/drm/radeon/radeon_cs.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_legacy_crtc.c
drivers/gpu/drm/radeon/radeon_pm.c
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
drivers/gpu/vga/vgaarb.c
drivers/hwmon/Kconfig
drivers/hwspinlock/u8500_hsem.c
drivers/ide/cy82c693.c
drivers/ide/icside.c
drivers/ide/ide-cd.c
drivers/ide/ide-floppy.c
drivers/ide/ide-tape.c
drivers/ide/piix.c
drivers/ide/triflex.c
drivers/ieee802154/fakehard.c
drivers/infiniband/core/addr.c
drivers/infiniband/core/cma.c
drivers/infiniband/hw/nes/nes_nic.c
drivers/infiniband/ulp/ipoib/ipoib_main.c
drivers/iommu/omap-iommu-debug.c
drivers/iommu/omap-iovmm.c
drivers/leds/led-class.c
drivers/lguest/lguest_device.c
drivers/macintosh/via-macii.c
drivers/macintosh/via-maciisi.c
drivers/md/raid5.c
drivers/media/dvb/dvb-usb/mxl111sf-i2c.c
drivers/media/dvb/dvb-usb/mxl111sf-phy.c
drivers/media/video/s5k6aa.c
drivers/media/video/s5p-mfc/s5p_mfc_dec.c
drivers/media/video/s5p-mfc/s5p_mfc_enc.c
drivers/media/video/uvc/uvc_ctrl.c
drivers/media/video/v4l2-ctrls.c
drivers/media/video/v4l2-event.c
drivers/media/video/videobuf2-core.c
drivers/mfd/ab5500-core.c
drivers/mfd/ab5500-debugfs.c
drivers/misc/carma/carma-fpga-program.c
drivers/misc/carma/carma-fpga.c
drivers/misc/eeprom/Kconfig
drivers/misc/sgi-xp/xpnet.c
drivers/mmc/host/sdhci-esdhc-imx.c
drivers/mtd/maps/bcm963xx-flash.c
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/bonding/bond_ipv6.c
drivers/net/bonding/bond_main.c
drivers/net/bonding/bond_sysfs.c
drivers/net/can/dev.c
drivers/net/can/mscan/mscan.c
drivers/net/can/slcan.c
drivers/net/dummy.c
drivers/net/ethernet/3com/3c589_cs.c
drivers/net/ethernet/3com/3c59x.c
drivers/net/ethernet/3com/typhoon.c
drivers/net/ethernet/8390/8390.h
drivers/net/ethernet/8390/apne.c
drivers/net/ethernet/8390/ax88796.c
drivers/net/ethernet/8390/es3210.c
drivers/net/ethernet/8390/hp-plus.c
drivers/net/ethernet/8390/hp.c
drivers/net/ethernet/8390/hydra.c
drivers/net/ethernet/8390/lne390.c
drivers/net/ethernet/8390/ne-h8300.c
drivers/net/ethernet/8390/ne.c
drivers/net/ethernet/8390/ne2.c
drivers/net/ethernet/8390/ne2k-pci.c
drivers/net/ethernet/8390/ne3210.c
drivers/net/ethernet/8390/stnic.c
drivers/net/ethernet/8390/zorro8390.c
drivers/net/ethernet/adaptec/starfire.c
drivers/net/ethernet/amd/amd8111e.c
drivers/net/ethernet/amd/amd8111e.h
drivers/net/ethernet/amd/nmclan_cs.c
drivers/net/ethernet/amd/pcnet32.c
drivers/net/ethernet/atheros/atl1c/atl1c_ethtool.c
drivers/net/ethernet/atheros/atl1c/atl1c_main.c
drivers/net/ethernet/atheros/atl1e/atl1e_ethtool.c
drivers/net/ethernet/atheros/atl1e/atl1e_main.c
drivers/net/ethernet/atheros/atlx/atl1.c
drivers/net/ethernet/atheros/atlx/atl2.c
drivers/net/ethernet/atheros/atlx/atlx.c
drivers/net/ethernet/broadcom/bnx2.c
drivers/net/ethernet/broadcom/bnx2.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
drivers/net/ethernet/broadcom/cnic.c
drivers/net/ethernet/broadcom/sb1250-mac.c
drivers/net/ethernet/broadcom/tg3.c
drivers/net/ethernet/broadcom/tg3.h
drivers/net/ethernet/brocade/bna/bnad_ethtool.c
drivers/net/ethernet/brocade/bna/cna.h
drivers/net/ethernet/cadence/Kconfig
drivers/net/ethernet/chelsio/cxgb/cxgb2.c
drivers/net/ethernet/chelsio/cxgb/sge.c
drivers/net/ethernet/chelsio/cxgb/sge.h
drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
drivers/net/ethernet/chelsio/cxgb4/sge.c
drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
drivers/net/ethernet/chelsio/cxgb4vf/sge.c
drivers/net/ethernet/cisco/enic/enic_main.c
drivers/net/ethernet/davicom/dm9000.c
drivers/net/ethernet/dec/tulip/de2104x.c
drivers/net/ethernet/dec/tulip/dmfe.c
drivers/net/ethernet/dec/tulip/tulip_core.c
drivers/net/ethernet/dec/tulip/uli526x.c
drivers/net/ethernet/dec/tulip/winbond-840.c
drivers/net/ethernet/dlink/sundance.c
drivers/net/ethernet/dnet.c
drivers/net/ethernet/emulex/benet/be.h
drivers/net/ethernet/emulex/benet/be_cmds.c
drivers/net/ethernet/emulex/benet/be_cmds.h
drivers/net/ethernet/emulex/benet/be_ethtool.c
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/fealnx.c
drivers/net/ethernet/freescale/fsl_pq_mdio.c
drivers/net/ethernet/freescale/gianfar.c
drivers/net/ethernet/freescale/gianfar.h
drivers/net/ethernet/freescale/gianfar_ethtool.c
drivers/net/ethernet/freescale/ucc_geth.c
drivers/net/ethernet/freescale/ucc_geth.h
drivers/net/ethernet/fujitsu/fmvj18x_cs.c
drivers/net/ethernet/i825xx/eepro.c
drivers/net/ethernet/ibm/emac/core.c
drivers/net/ethernet/ibm/ibmveth.c
drivers/net/ethernet/intel/e100.c
drivers/net/ethernet/intel/e1000/e1000_ethtool.c
drivers/net/ethernet/intel/e1000/e1000_hw.h
drivers/net/ethernet/intel/e1000/e1000_main.c
drivers/net/ethernet/intel/e1000e/ethtool.c
drivers/net/ethernet/intel/e1000e/netdev.c
drivers/net/ethernet/intel/igb/e1000_82575.c
drivers/net/ethernet/intel/igb/igb_ethtool.c
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/igbvf/ethtool.c
drivers/net/ethernet/intel/igbvf/netdev.c
drivers/net/ethernet/intel/ixgb/ixgb_ethtool.c
drivers/net/ethernet/intel/ixgb/ixgb_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
drivers/net/ethernet/intel/ixgbevf/defines.h
drivers/net/ethernet/intel/ixgbevf/ethtool.c
drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
drivers/net/ethernet/intel/ixgbevf/vf.c
drivers/net/ethernet/jme.c
drivers/net/ethernet/lantiq_etop.c
drivers/net/ethernet/marvell/mv643xx_eth.c
drivers/net/ethernet/marvell/skge.c
drivers/net/ethernet/marvell/sky2.c
drivers/net/ethernet/marvell/sky2.h
drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
drivers/net/ethernet/mellanox/mlx4/en_rx.c
drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
drivers/net/ethernet/micrel/ks8851_mll.c
drivers/net/ethernet/micrel/ksz884x.c
drivers/net/ethernet/myricom/myri10ge/myri10ge.c
drivers/net/ethernet/natsemi/natsemi.c
drivers/net/ethernet/natsemi/ns83820.c
drivers/net/ethernet/neterion/s2io.c
drivers/net/ethernet/neterion/vxge/vxge-main.c
drivers/net/ethernet/nvidia/forcedeth.c
drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_ethtool.c
drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_param.c
drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c
drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
drivers/net/ethernet/qlogic/qla3xxx.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
drivers/net/ethernet/qlogic/qlge/qlge_ethtool.c
drivers/net/ethernet/qlogic/qlge/qlge_main.c
drivers/net/ethernet/rdc/r6040.c
drivers/net/ethernet/realtek/8139cp.c
drivers/net/ethernet/realtek/8139too.c
drivers/net/ethernet/realtek/r8169.c
drivers/net/ethernet/sfc/efx.c
drivers/net/ethernet/sfc/net_driver.h
drivers/net/ethernet/sis/sis190.c
drivers/net/ethernet/sis/sis900.c
drivers/net/ethernet/smsc/epic100.c
drivers/net/ethernet/smsc/smc91c92_cs.c
drivers/net/ethernet/smsc/smsc911x.c
drivers/net/ethernet/smsc/smsc9420.c
drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
drivers/net/ethernet/stmicro/stmmac/stmmac.h
drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/sun/cassini.c
drivers/net/ethernet/sun/niu.c
drivers/net/ethernet/sun/sungem.c
drivers/net/ethernet/sun/sunhme.c
drivers/net/ethernet/via/via-rhine.c
drivers/net/ethernet/via/via-velocity.c
drivers/net/ethernet/xilinx/ll_temac_main.c
drivers/net/ethernet/xircom/xirc2ps_cs.c
drivers/net/hippi/Kconfig
drivers/net/ifb.c
drivers/net/loopback.c
drivers/net/macvtap.c
drivers/net/mii.c
drivers/net/phy/mdio-bitbang.c
drivers/net/phy/mdio-gpio.c
drivers/net/phy/phy_device.c
drivers/net/ppp/pptp.c
drivers/net/team/Kconfig [new file with mode: 0644]
drivers/net/team/Makefile [new file with mode: 0644]
drivers/net/team/team.c [new file with mode: 0644]
drivers/net/team/team_mode_activebackup.c [new file with mode: 0644]
drivers/net/team/team_mode_roundrobin.c [new file with mode: 0644]
drivers/net/tun.c
drivers/net/usb/asix.c
drivers/net/usb/cdc-phonet.c
drivers/net/usb/cdc_ether.c
drivers/net/usb/cdc_ncm.c
drivers/net/usb/lg-vl600.c
drivers/net/usb/smsc75xx.c
drivers/net/usb/smsc95xx.c
drivers/net/veth.c
drivers/net/virtio_net.c
drivers/net/vmxnet3/vmxnet3_ethtool.c
drivers/net/vmxnet3/vmxnet3_int.h
drivers/net/wireless/Makefile
drivers/net/wireless/ath/ath.h
drivers/net/wireless/ath/ath6kl/cfg80211.c
drivers/net/wireless/ath/ath6kl/init.c
drivers/net/wireless/ath/ath9k/Kconfig
drivers/net/wireless/ath/ath9k/Makefile
drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
drivers/net/wireless/ath/ath9k/ar9003_phy.c
drivers/net/wireless/ath/ath9k/ar9003_phy.h
drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/eeprom.h
drivers/net/wireless/ath/ath9k/gpio.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/init.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/mci.c [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/mci.h [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/carl9170/main.c
drivers/net/wireless/ath/regd.c
drivers/net/wireless/b43/xmit.c
drivers/net/wireless/b43/xmit.h
drivers/net/wireless/brcm80211/brcmfmac/Makefile
drivers/net/wireless/brcm80211/brcmfmac/bcmchip.h
drivers/net/wireless/brcm80211/brcmfmac/dhd.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c [new file with mode: 0644]
drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.h [new file with mode: 0644]
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
drivers/net/wireless/brcm80211/brcmsmac/aiutils.h
drivers/net/wireless/brcm80211/brcmsmac/ampdu.c
drivers/net/wireless/brcm80211/brcmsmac/channel.c
drivers/net/wireless/brcm80211/brcmsmac/dma.c
drivers/net/wireless/brcm80211/brcmsmac/dma.h
drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h
drivers/net/wireless/brcm80211/brcmsmac/main.c
drivers/net/wireless/brcm80211/brcmsmac/main.h
drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c
drivers/net/wireless/brcm80211/brcmsmac/phy/phy_int.h
drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
drivers/net/wireless/brcm80211/brcmsmac/pmu.c
drivers/net/wireless/brcm80211/brcmsmac/pub.h
drivers/net/wireless/brcm80211/brcmsmac/rate.h
drivers/net/wireless/brcm80211/brcmsmac/srom.c
drivers/net/wireless/brcm80211/brcmsmac/srom.h
drivers/net/wireless/brcm80211/brcmutil/utils.c
drivers/net/wireless/brcm80211/include/brcmu_utils.h
drivers/net/wireless/brcm80211/include/defs.h
drivers/net/wireless/brcm80211/include/soc.h
drivers/net/wireless/ipw2x00/ipw2200.c
drivers/net/wireless/ipw2x00/libipw.h
drivers/net/wireless/iwlwifi/Makefile
drivers/net/wireless/iwlwifi/iwl-2000.c
drivers/net/wireless/iwlwifi/iwl-6000.c
drivers/net/wireless/iwlwifi/iwl-agn-lib.c
drivers/net/wireless/iwlwifi/iwl-agn-rs.c
drivers/net/wireless/iwlwifi/iwl-agn-rx.c
drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
drivers/net/wireless/iwlwifi/iwl-agn-sta.c
drivers/net/wireless/iwlwifi/iwl-agn-tx.c
drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-agn.h
drivers/net/wireless/iwlwifi/iwl-cfg.h
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-csr.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-devtrace.c
drivers/net/wireless/iwlwifi/iwl-devtrace.h
drivers/net/wireless/iwlwifi/iwl-eeprom.c
drivers/net/wireless/iwlwifi/iwl-mac80211.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-pci.c
drivers/net/wireless/iwlwifi/iwl-scan.c
drivers/net/wireless/iwlwifi/iwl-sv-open.c
drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h
drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
drivers/net/wireless/iwlwifi/iwl-trans.h
drivers/net/wireless/iwmc3200wifi/cfg80211.c
drivers/net/wireless/libertas/cfg.c
drivers/net/wireless/libertas/if_spi.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/mwifiex/11n_rxreorder.c
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/fw.h
drivers/net/wireless/mwifiex/init.c
drivers/net/wireless/mwifiex/join.c
drivers/net/wireless/mwifiex/pcie.c
drivers/net/wireless/mwifiex/scan.c
drivers/net/wireless/mwifiex/sdio.c
drivers/net/wireless/mwifiex/sta_rx.c
drivers/net/wireless/orinoco/scan.c
drivers/net/wireless/rndis_wlan.c
drivers/net/wireless/rt2x00/rt2800usb.c
drivers/net/wireless/rt2x00/rt2x00.h
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
drivers/net/wireless/wl12xx/scan.c
drivers/net/xen-netback/interface.c
drivers/net/xen-netfront.c
drivers/pinctrl/Kconfig
drivers/platform/x86/Kconfig
drivers/platform/x86/dell-laptop.c
drivers/ps3/ps3-vuart.c
drivers/ps3/ps3stor_lib.c
drivers/rtc/rtc-mrst.c
drivers/rtc/rtc-puv3.c
drivers/s390/char/zcore.c
drivers/s390/crypto/ap_bus.c
drivers/s390/kvm/kvm_virtio.c
drivers/s390/net/Kconfig
drivers/s390/net/lcs.c
drivers/s390/net/netiucv.c
drivers/s390/net/qeth_core.h
drivers/s390/net/qeth_core_main.c
drivers/s390/net/qeth_l3_main.c
drivers/s390/net/qeth_l3_sys.c
drivers/scsi/aacraid/linit.c
drivers/scsi/hpsa.c
drivers/scsi/mpt2sas/mpt2sas_scsih.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_scan.c
drivers/sh/Makefile
drivers/sh/clk/core.c
drivers/sh/pm_runtime.c [moved from arch/arm/mach-shmobile/pm_runtime.c with 94% similarity]
drivers/spi/spi-atmel.c
drivers/spi/spi-pl022.c
drivers/staging/media/as102/as102_drv.c
drivers/staging/media/as102/as102_drv.h
drivers/staging/octeon/ethernet-tx.c
drivers/tty/n_gsm.c
drivers/tty/serial/sh-sci.c
drivers/usb/gadget/f_phonet.c
drivers/usb/gadget/fsl_udc_core.c
drivers/virtio/virtio_mmio.c
drivers/virtio/virtio_pci.c
drivers/xen/balloon.c
drivers/xen/gntalloc.c
drivers/xen/gntdev.c
drivers/xen/xenbus/xenbus_client.c
fs/bio.c
fs/btrfs/btrfs_inode.h
fs/btrfs/delayed-inode.c
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/free-space-cache.c
fs/btrfs/inode-map.c
fs/btrfs/inode.c
fs/btrfs/relocation.c
fs/btrfs/scrub.c
fs/btrfs/super.c
fs/btrfs/transaction.c
fs/btrfs/volumes.c
fs/dlm/lowcomms.c
fs/hfs/trans.c
fs/namespace.c
fs/nfs/super.c
fs/proc/base.c
fs/xfs/xfs_aops.c
fs/xfs/xfs_buf_item.c
fs/xfs/xfs_dquot_item.c
fs/xfs/xfs_extfree_item.c
fs/xfs/xfs_inode_item.c
fs/xfs/xfs_log.c
fs/xfs/xfs_log.h
fs/xfs/xfs_qm.c
fs/xfs/xfs_trans.h
fs/xfs/xfs_vnodeops.c
include/asm-generic/socket.h
include/drm/drmP.h
include/drm/drm_pciids.h
include/drm/exynos_drm.h
include/linux/Kbuild
include/linux/atmdev.h
include/linux/bio.h
include/linux/cgroup_subsys.h
include/linux/devfreq.h
include/linux/device.h
include/linux/errqueue.h
include/linux/ethtool.h
include/linux/fs.h
include/linux/genhd.h
include/linux/hugetlb.h
include/linux/hwspinlock.h
include/linux/ieee80211.h
include/linux/if.h
include/linux/if_team.h [new file with mode: 0644]
include/linux/inet_diag.h
include/linux/kvm.h
include/linux/mdio-bitbang.h
include/linux/mdio-gpio.h
include/linux/mfd/wm8994/registers.h
include/linux/mii.h
include/linux/neighbour.h
include/linux/netdev_features.h [new file with mode: 0644]
include/linux/netdevice.h
include/linux/netfilter.h
include/linux/nl80211.h
include/linux/pci_ids.h
include/linux/phonet.h
include/linux/pinctrl/pinctrl.h
include/linux/pm.h
include/linux/pm_runtime.h
include/linux/serial_sci.h
include/linux/sh_clk.h
include/linux/sh_pfc.h
include/linux/skbuff.h
include/linux/sunrpc/clnt.h
include/linux/virtio_config.h
include/linux/vmalloc.h
include/net/bluetooth/bluetooth.h
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
include/net/bluetooth/l2cap.h
include/net/bluetooth/mgmt.h
include/net/cfg80211.h
include/net/icmp.h
include/net/ieee80211_radiotap.h
include/net/ieee802154.h
include/net/inet_connection_sock.h
include/net/inetpeer.h
include/net/ip.h
include/net/ip_vs.h
include/net/ipv6.h
include/net/mac80211.h
include/net/neighbour.h
include/net/netns/mib.h
include/net/netprio_cgroup.h [new file with mode: 0644]
include/net/nfc/nci.h
include/net/nfc/nci_core.h
include/net/protocol.h
include/net/sctp/structs.h
include/net/snmp.h
include/net/sock.h
include/net/tcp.h
include/net/udp.h
include/net/xfrm.h
include/xen/platform_pci.h
kernel/irq/spurious.c
kernel/power/hibernate.c
kernel/power/main.c
kernel/power/qos.c
lib/vsprintf.c
mm/backing-dev.c
mm/hugetlb.c
mm/nommu.c
mm/oom_kill.c
mm/vmalloc.c
net/8021q/vlan_dev.c
net/Kconfig
net/atm/br2684.c
net/atm/clip.c
net/atm/common.c
net/atm/common.h
net/atm/pppoatm.c
net/bluetooth/bnep/core.c
net/bluetooth/cmtp/core.c
net/bluetooth/hci_conn.c
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/hci_sysfs.c
net/bluetooth/hidp/core.c
net/bluetooth/l2cap_core.c
net/bluetooth/l2cap_sock.c
net/bluetooth/mgmt.c
net/bluetooth/rfcomm/core.c
net/bluetooth/rfcomm/sock.c
net/bluetooth/rfcomm/tty.c
net/bluetooth/smp.c
net/bridge/br_device.c
net/bridge/br_fdb.c
net/bridge/br_if.c
net/bridge/br_multicast.c
net/bridge/br_private.h
net/core/Makefile
net/core/dev.c
net/core/ethtool.c
net/core/neighbour.c
net/core/net-sysfs.c
net/core/netpoll.c
net/core/netprio_cgroup.c [new file with mode: 0644]
net/core/pktgen.c
net/core/skbuff.c
net/core/sock.c
net/core/sysctl_net_core.c
net/dccp/ipv6.c
net/dccp/minisocks.c
net/decnet/dn_neigh.c
net/econet/af_econet.c
net/ieee802154/6lowpan.c
net/ieee802154/6lowpan.h
net/ieee802154/dgram.c
net/ieee802154/raw.c
net/ipv4/af_inet.c
net/ipv4/ah4.c
net/ipv4/arp.c
net/ipv4/igmp.c
net/ipv4/inet_connection_sock.c
net/ipv4/inet_diag.c
net/ipv4/ip_gre.c
net/ipv4/ip_options.c
net/ipv4/ip_sockglue.c
net/ipv4/ipconfig.c
net/ipv4/ipip.c
net/ipv4/ping.c
net/ipv4/proc.c
net/ipv4/raw.c
net/ipv4/route.c
net/ipv4/tcp.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_minisocks.c
net/ipv4/tcp_output.c
net/ipv4/udp.c
net/ipv6/addrconf.c
net/ipv6/af_inet6.c
net/ipv6/ah6.c
net/ipv6/anycast.c
net/ipv6/datagram.c
net/ipv6/exthdrs.c
net/ipv6/fib6_rules.c
net/ipv6/icmp.c
net/ipv6/inet6_connection_sock.c
net/ipv6/ip6_fib.c
net/ipv6/ip6_flowlabel.c
net/ipv6/ip6_input.c
net/ipv6/ip6_output.c
net/ipv6/ip6_tunnel.c
net/ipv6/ip6mr.c
net/ipv6/ipv6_sockglue.c
net/ipv6/mcast.c
net/ipv6/mip6.c
net/ipv6/ndisc.c
net/ipv6/netfilter/ip6t_REJECT.c
net/ipv6/proc.c
net/ipv6/raw.c
net/ipv6/reassembly.c
net/ipv6/route.c
net/ipv6/sit.c
net/ipv6/syncookies.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c
net/ipv6/xfrm6_mode_beet.c
net/ipv6/xfrm6_mode_tunnel.c
net/ipv6/xfrm6_output.c
net/ipv6/xfrm6_policy.c
net/ipv6/xfrm6_state.c
net/irda/irttp.c
net/key/af_key.c
net/l2tp/l2tp_core.c
net/mac80211/agg-rx.c
net/mac80211/agg-tx.c
net/mac80211/cfg.c
net/mac80211/debugfs.c
net/mac80211/driver-ops.h
net/mac80211/ht.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/mesh_hwmp.c
net/mac80211/mesh_pathtbl.c
net/mac80211/mesh_plink.c
net/mac80211/mlme.c
net/mac80211/pm.c
net/mac80211/rc80211_minstrel.c
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/mac80211/status.c
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/wme.c
net/mac80211/work.c
net/mac80211/wpa.c
net/netfilter/core.c
net/netfilter/ipset/ip_set_hash_ip.c
net/netfilter/ipset/ip_set_hash_net.c
net/netfilter/ipvs/ip_vs_core.c
net/netfilter/ipvs/ip_vs_sync.c
net/netfilter/ipvs/ip_vs_xmit.c
net/netfilter/nf_conntrack_h323_main.c
net/netfilter/xt_TCPMSS.c
net/netfilter/xt_addrtype.c
net/netlabel/netlabel_kapi.c
net/netlabel/netlabel_mgmt.c
net/netlabel/netlabel_unlabeled.c
net/nfc/nci/core.c
net/nfc/nci/data.c
net/nfc/nci/lib.c
net/nfc/nci/ntf.c
net/nfc/nci/rsp.c
net/packet/af_packet.c
net/phonet/pep.c
net/rds/Kconfig
net/rfkill/core.c
net/rxrpc/ar-key.c
net/sched/sch_choke.c
net/sched/sch_generic.c
net/sctp/ipv6.c
net/sctp/sm_make_chunk.c
net/sctp/sm_sideeffect.c
net/sctp/socket.c
net/sctp/transport.c
net/socket.c
net/sunrpc/svcauth_unix.c
net/sunrpc/svcsock.c
net/wireless/core.c
net/wireless/core.h
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/nl80211.h
net/wireless/reg.c
net/wireless/scan.c
net/wireless/wext-compat.c
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_state.c
security/keys/encrypted-keys/Makefile
security/keys/encrypted-keys/encrypted.c
security/keys/encrypted-keys/encrypted.h
security/keys/user_defined.c
security/lsm_audit.c
security/selinux/hooks.c
security/selinux/netnode.c
security/smack/smackfs.c
sound/core/vmaster.c
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_eld.c
sound/pci/hda/hda_local.h
sound/pci/hda/patch_cirrus.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/intel8x0.c
sound/ppc/snd_ps3.c
sound/soc/codecs/wm8994.c
sound/usb/mixer.c
sound/usb/quirks.c
tools/testing/ktest/ktest.pl
tools/testing/ktest/sample.conf

index a4806f0..9b0d026 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -68,6 +68,7 @@ Juha Yrjola <juha.yrjola@solidboot.com>
 Kay Sievers <kay.sievers@vrfy.org>
 Kenneth W Chen <kenneth.w.chen@intel.com>
 Koushik <raghavendra.koushik@neterion.com>
+Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
 Leonid I Ananiev <leonid.i.ananiev@intel.com>
 Linas Vepstas <linas@austin.ibm.com>
 Mark Brown <broonie@sirena.org.uk>
@@ -111,3 +112,4 @@ Uwe Kleine-König <ukl@pengutronix.de>
 Uwe Kleine-König <Uwe.Kleine-Koenig@digi.com>
 Valdis Kletnieks <Valdis.Kletnieks@vt.edu>
 Takashi YOSHII <takashi.yoshii.zj@renesas.com>
+Yusuke Goda <goda.yusuke@renesas.com>
index 2b5d561..c1eb41c 100644 (file)
@@ -206,16 +206,3 @@ Description:
                when a discarded area is read the discard_zeroes_data
                parameter will be set to one. Otherwise it will be 0 and
                the result of reading a discarded area is undefined.
-What:          /sys/block/<disk>/alias
-Date:          Aug 2011
-Contact:       Nao Nishijima <nao.nishijima.xt@hitachi.com>
-Description:
-               A raw device name of a disk does not always point a same disk
-               each boot-up time. Therefore, users have to use persistent
-               device names, which udev creates when the kernel finds a disk,
-               instead of raw device name. However, kernel doesn't show those
-               persistent names on its messages (e.g. dmesg).
-               This file can store an alias of the disk and it would be
-               appeared in kernel messages if it is set. A disk can have an
-               alias which length is up to 255bytes. Users can use alphabets,
-               numbers, "-" and "_" in alias name. This file is writeonce.
index c279158..196b8b9 100644 (file)
@@ -32,7 +32,7 @@
       The Linux DRM layer contains code intended to support the needs
       of complex graphics devices, usually containing programmable
       pipelines well suited to 3D graphics acceleration.  Graphics
-      drivers in the kernel can make use of DRM functions to make
+      drivers in the kernel may make use of DRM functions to make
       tasks like memory management, interrupt handling and DMA easier,
       and provide a uniform interface to applications.
     </para>
       existing drivers.
     </para>
     <para>
-      First, we'll go over some typical driver initialization
+      First, we go over some typical driver initialization
       requirements, like setting up command buffers, creating an
       initial output configuration, and initializing core services.
-      Subsequent sections will cover core internals in more detail,
+      Subsequent sections cover core internals in more detail,
       providing implementation notes and examples.
     </para>
     <para>
@@ -74,7 +74,7 @@
     </para>
     <para>
       The core of every DRM driver is struct drm_driver.  Drivers
-      will typically statically initialize a drm_driver structure,
+      typically statically initialize a drm_driver structure,
       then pass it to drm_init() at load time.
     </para>
 
@@ -88,8 +88,8 @@
     </para>
     <programlisting>
       static struct drm_driver driver = {
-       /* don't use mtrr's here, the Xserver or user space app should
-        * deal with them for intel hardware.
+       /* Don't use MTRRs here; the Xserver or userspace app should
+        * deal with them for Intel hardware.
         */
        .driver_features =
            DRIVER_USE_AGP | DRIVER_REQUIRE_AGP |
     </programlisting>
     <para>
       In the example above, taken from the i915 DRM driver, the driver
-      sets several flags indicating what core features it supports.
-      We'll go over the individual callbacks in later sections.  Since
+      sets several flags indicating what core features it supports;
+      we go over the individual callbacks in later sections.  Since
       flags indicate which features your driver supports to the DRM
       core, you need to set most of them prior to calling drm_init().  Some,
       like DRIVER_MODESET can be set later based on user supplied parameters,
        <term>DRIVER_HAVE_IRQ</term><term>DRIVER_IRQ_SHARED</term>
        <listitem>
          <para>
-           DRIVER_HAVE_IRQ indicates whether the driver has a IRQ
-           handler, DRIVER_IRQ_SHARED indicates whether the device &amp;
+           DRIVER_HAVE_IRQ indicates whether the driver has an IRQ
+           handler DRIVER_IRQ_SHARED indicates whether the device &amp;
            handler support shared IRQs (note that this is required of
            PCI drivers).
          </para>
        <term>DRIVER_DMA_QUEUE</term>
        <listitem>
          <para>
-           If the driver queues DMA requests and completes them
-           asynchronously, this flag should be set.  Deprecated.
+           Should be set if the driver queues DMA requests and completes them
+           asynchronously.  Deprecated.
          </para>
        </listitem>
       </varlistentry>
     </variablelist>
     <para>
       In this specific case, the driver requires AGP and supports
-      IRQs.  DMA, as we'll see, is handled by device specific ioctls
+      IRQs.  DMA, as discussed later, is handled by device-specific ioctls
       in this case.  It also supports the kernel mode setting APIs, though
       unlike in the actual i915 driver source, this example unconditionally
       exports KMS capability.
       initial output configuration.
     </para>
     <para>
-      Note that the tasks performed at driver load time must not
-      conflict with DRM client requirements.  For instance, if user
+      If compatibility is a concern (e.g. with drivers converted over
+      to the new interfaces from the old ones), care must be taken to
+      prevent device initialization and control that is incompatible with
+      currently active userspace drivers.  For instance, if user
       level mode setting drivers are in use, it would be problematic
       to perform output discovery &amp; configuration at load time.
-      Likewise, if pre-memory management aware user level drivers are
+      Likewise, if user-level drivers unaware of memory management are
       in use, memory management and command buffer setup may need to
-      be omitted.  These requirements are driver specific, and care
+      be omitted.  These requirements are driver-specific, and care
       needs to be taken to keep both old and new applications and
       libraries working.  The i915 driver supports the "modeset"
       module parameter to control whether advanced features are
-      enabled at load time or in legacy fashion.  If compatibility is
-      a concern (e.g. with drivers converted over to the new interfaces
-      from the old ones), care must be taken to prevent incompatible
-      device initialization and control with the currently active
-      userspace drivers.
+      enabled at load time or in legacy fashion.
     </para>
 
     <sect2>
       <title>Driver private &amp; performance counters</title>
       <para>
        The driver private hangs off the main drm_device structure and
-       can be used for tracking various device specific bits of
+       can be used for tracking various device-specific bits of
        information, like register offsets, command buffer status,
        register state for suspend/resume, etc.  At load time, a
-       driver can simply allocate one and set drm_device.dev_priv
-       appropriately; at unload the driver can free it and set
-       drm_device.dev_priv to NULL.
+       driver may simply allocate one and set drm_device.dev_priv
+       appropriately; it should be freed and drm_device.dev_priv set
+       to NULL when the driver is unloaded.
       </para>
       <para>
-       The DRM supports several counters which can be used for rough
+       The DRM supports several counters which may be used for rough
        performance characterization.  Note that the DRM stat counter
        system is not often used by applications, and supporting
        additional counters is completely optional.
        These interfaces are deprecated and should not be used.  If performance
        monitoring is desired, the developer should investigate and
        potentially enhance the kernel perf and tracing infrastructure to export
-       GPU related performance information to performance monitoring
-       tools and applications.
+       GPU related performance information for consumption by performance
+       monitoring tools and applications.
       </para>
     </sect2>
 
     <sect2>
       <title>Configuring the device</title>
       <para>
-       Obviously, device configuration will be device specific.
+       Obviously, device configuration is device-specific.
        However, there are several common operations: finding a
        device's PCI resources, mapping them, and potentially setting
        up an IRQ handler.
       <para>
        Finding &amp; mapping resources is fairly straightforward.  The
        DRM wrapper functions, drm_get_resource_start() and
-       drm_get_resource_len() can be used to find BARs on the given
+       drm_get_resource_len(), may be used to find BARs on the given
        drm_device struct.  Once those values have been retrieved, the
        driver load function can call drm_addmap() to create a new
-       mapping for the BAR in question.  Note you'll probably want a
+       mapping for the BAR in question.  Note that you probably want a
        drm_local_map_t in your driver private structure to track any
        mappings you create.
 <!-- !Fdrivers/gpu/drm/drm_bufs.c drm_get_resource_* -->
       <para>
        if compatibility with other operating systems isn't a concern
        (DRM drivers can run under various BSD variants and OpenSolaris),
-       native Linux calls can be used for the above, e.g. pci_resource_*
+       native Linux calls may be used for the above, e.g. pci_resource_*
        and iomap*/iounmap.  See the Linux device driver book for more
        info.
       </para>
       <para>
-       Once you have a register map, you can use the DRM_READn() and
+       Once you have a register map, you may use the DRM_READn() and
        DRM_WRITEn() macros to access the registers on your device, or
-       use driver specific versions to offset into your MMIO space
-       relative to a driver specific base pointer (see I915_READ for
-       example).
+       use driver-specific versions to offset into your MMIO space
+       relative to a driver-specific base pointer (see I915_READ for
+       an example).
       </para>
       <para>
        If your device supports interrupt generation, you may want to
-       setup an interrupt handler at driver load time as well.  This
+       set up an interrupt handler when the driver is loaded.  This
        is done using the drm_irq_install() function.  If your device
        supports vertical blank interrupts, it should call
        drm_vblank_init() to initialize the core vblank handling code before
       </para>
 <!--!Fdrivers/char/drm/drm_irq.c drm_irq_install-->
       <para>
-       Once your interrupt handler is registered (it'll use your
+       Once your interrupt handler is registered (it uses your
        drm_driver.irq_handler as the actual interrupt handling
        function), you can safely enable interrupts on your device,
        assuming any other state your interrupt handler uses is also
        using the pci_map_rom() call, a convenience function that
        takes care of mapping the actual ROM, whether it has been
        shadowed into memory (typically at address 0xc0000) or exists
-       on the PCI device in the ROM BAR.  Note that once you've
-       mapped the ROM and extracted any necessary information, be
-       sure to unmap it; on many devices the ROM address decoder is
-       shared with other BARs, so leaving it mapped can cause
+       on the PCI device in the ROM BAR.  Note that after the ROM
+       has been mapped and any necessary information has been extracted,
+       it should be unmapped; on many devices, the ROM address decoder is
+       shared with other BARs, so leaving it mapped could cause
        undesired behavior like hangs or memory corruption.
 <!--!Fdrivers/pci/rom.c pci_map_rom-->
       </para>
        should support a memory manager.
       </para>
       <para>
-       If your driver supports memory management (it should!), you'll
+       If your driver supports memory management (it should!), you
        need to set that up at load time as well.  How you initialize
-       it depends on which memory manager you're using, TTM or GEM.
+       it depends on which memory manager you're using: TTM or GEM.
       </para>
       <sect3>
        <title>TTM initialization</title>
          and devices with dedicated video RAM (VRAM), i.e. most discrete
          graphics devices.  If your device has dedicated RAM, supporting
          TTM is desirable.  TTM also integrates tightly with your
-         driver specific buffer execution function.  See the radeon
+         driver-specific buffer execution function.  See the radeon
          driver for examples.
        </para>
        <para>
          created by the memory manager at runtime.  Your global TTM should
          have a type of TTM_GLOBAL_TTM_MEM.  The size field for the global
          object should be sizeof(struct ttm_mem_global), and the init and
-         release hooks should point at your driver specific init and
-         release routines, which will probably eventually call
-         ttm_mem_global_init and ttm_mem_global_release respectively.
+         release hooks should point at your driver-specific init and
+         release routines, which probably eventually call
+         ttm_mem_global_init and ttm_mem_global_release, respectively.
        </para>
        <para>
          Once your global TTM accounting structure is set up and initialized
-         (done by calling ttm_global_item_ref on the global object you
-         just created), you'll need to create a buffer object TTM to
+         by calling ttm_global_item_ref() on it,
+         you need to create a buffer object TTM to
          provide a pool for buffer object allocation by clients and the
          kernel itself.  The type of this object should be TTM_GLOBAL_TTM_BO,
          and its size should be sizeof(struct ttm_bo_global).  Again,
-         driver specific init and release functions can be provided,
-         likely eventually calling ttm_bo_global_init and
-         ttm_bo_global_release, respectively.  Also like the previous
-         object, ttm_global_item_ref is used to create an initial reference
+         driver-specific init and release functions may be provided,
+         likely eventually calling ttm_bo_global_init() and
+         ttm_bo_global_release(), respectively.  Also, like the previous
+         object, ttm_global_item_ref() is used to create an initial reference
          count for the TTM, which will call your initialization function.
        </para>
       </sect3>
          GEM is an alternative to TTM, designed specifically for UMA
          devices.  It has simpler initialization and execution requirements
          than TTM, but has no VRAM management capability.  Core GEM
-         initialization is comprised of a basic drm_mm_init call to create
+         is initialized by calling drm_mm_init() to create
          a GTT DRM MM object, which provides an address space pool for
-         object allocation.  In a KMS configuration, the driver will
-         need to allocate and initialize a command ring buffer following
-         basic GEM initialization.  Most UMA devices have a so-called
+         object allocation.  In a KMS configuration, the driver
+         needs to allocate and initialize a command ring buffer following
+         core GEM initialization.  A UMA device usually has what is called a
          "stolen" memory region, which provides space for the initial
          framebuffer and large, contiguous memory regions required by the
-         device.  This space is not typically managed by GEM, and must
+         device.  This space is not typically managed by GEM, and it must
          be initialized separately into its own DRM MM object.
        </para>
        <para>
-         Initialization will be driver specific, and will depend on
-         the architecture of the device.  In the case of Intel
+         Initialization is driver-specific. In the case of Intel
          integrated graphics chips like 965GM, GEM initialization can
          be done by calling the internal GEM init function,
          i915_gem_do_init().  Since the 965GM is a UMA device
-         (i.e. it doesn't have dedicated VRAM), GEM will manage
+         (i.e. it doesn't have dedicated VRAM), GEM manages
          making regular RAM available for GPU operations.  Memory set
          aside by the BIOS (called "stolen" memory by the i915
-         driver) will be managed by the DRM memrange allocator; the
-         rest of the aperture will be managed by GEM.
+         driver) is managed by the DRM memrange allocator; the
+         rest of the aperture is managed by GEM.
          <programlisting>
            /* Basic memrange allocator for stolen space (aka vram) */
            drm_memrange_init(&amp;dev_priv->vram, 0, prealloc_size);
 <!--!Edrivers/char/drm/drm_memrange.c-->
        </para>
        <para>
-         Once the memory manager has been set up, we can allocate the
+         Once the memory manager has been set up, we may allocate the
          command buffer.  In the i915 case, this is also done with a
          GEM function, i915_gem_init_ringbuffer().
        </para>
     <sect2>
       <title>Output configuration</title>
       <para>
-       The final initialization task is output configuration.  This involves
-       finding and initializing the CRTCs, encoders and connectors
-       for your device, creating an initial configuration and
-       registering a framebuffer console driver.
+       The final initialization task is output configuration.  This involves:
+       <itemizedlist>
+         <listitem>
+           Finding and initializing the CRTCs, encoders, and connectors
+           for the device.
+         </listitem>
+         <listitem>
+           Creating an initial configuration.
+         </listitem>
+         <listitem>
+           Registering a framebuffer console driver.
+         </listitem>
+       </itemizedlist>
       </para>
       <sect3>
        <title>Output discovery and initialization</title>
        <para>
-         Several core functions exist to create CRTCs, encoders and
-         connectors, namely drm_crtc_init(), drm_connector_init() and
+         Several core functions exist to create CRTCs, encoders, and
+         connectors, namely: drm_crtc_init(), drm_connector_init(), and
          drm_encoder_init(), along with several "helper" functions to
          perform common tasks.
        </para>
@@ -555,10 +561,10 @@ void intel_crt_init(struct drm_device *dev)
        </programlisting>
        <para>
          In the example above (again, taken from the i915 driver), a
-         CRT connector and encoder combination is created.  A device
-         specific i2c bus is also created, for fetching EDID data and
+         CRT connector and encoder combination is created.  A device-specific
+         i2c bus is also created for fetching EDID data and
          performing monitor detection.  Once the process is complete,
-         the new connector is registered with sysfs, to make its
+         the new connector is registered with sysfs to make its
          properties available to applications.
        </para>
        <sect4>
@@ -567,12 +573,12 @@ void intel_crt_init(struct drm_device *dev)
            Since many PC-class graphics devices have similar display output
            designs, the DRM provides a set of helper functions to make
            output management easier.  The core helper routines handle
-           encoder re-routing and disabling of unused functions following
-           mode set.  Using the helpers is optional, but recommended for
+           encoder re-routing and the disabling of unused functions following
+           mode setting.  Using the helpers is optional, but recommended for
            devices with PC-style architectures (i.e. a set of display planes
            for feeding pixels to encoders which are in turn routed to
            connectors).  Devices with more complex requirements needing
-           finer grained management can opt to use the core callbacks
+           finer grained management may opt to use the core callbacks
            directly.
          </para>
          <para>
@@ -580,17 +586,25 @@ void intel_crt_init(struct drm_device *dev)
          </para>
        </sect4>
        <para>
-         For each encoder, CRTC and connector, several functions must
-         be provided, depending on the object type.  Encoder objects
-         need to provide a DPMS (basically on/off) function, mode fixup
-         (for converting requested modes into native hardware timings),
-         and prepare, set and commit functions for use by the core DRM
-         helper functions.  Connector helpers need to provide mode fetch and
-         validity functions as well as an encoder matching function for
-         returning an ideal encoder for a given connector.  The core
-         connector functions include a DPMS callback, (deprecated)
-         save/restore routines, detection, mode probing, property handling,
-         and cleanup functions.
+         Each encoder object needs to provide:
+         <itemizedlist>
+           <listitem>
+             A DPMS (basically on/off) function.
+           </listitem>
+           <listitem>
+             A mode-fixup function (for converting requested modes into
+             native hardware timings).
+           </listitem>
+           <listitem>
+             Functions (prepare, set, and commit) for use by the core DRM
+             helper functions.
+           </listitem>
+         </itemizedlist>
+         Connector helpers need to provide functions (mode-fetch, validity,
+         and encoder-matching) for returning an ideal encoder for a given
+         connector.  The core connector functions include a DPMS callback,
+         save/restore routines (deprecated), detection, mode probing,
+         property handling, and cleanup functions.
        </para>
 <!--!Edrivers/char/drm/drm_crtc.h-->
 <!--!Edrivers/char/drm/drm_crtc.c-->
@@ -605,23 +619,34 @@ void intel_crt_init(struct drm_device *dev)
     <title>VBlank event handling</title>
     <para>
       The DRM core exposes two vertical blank related ioctls:
-      DRM_IOCTL_WAIT_VBLANK and DRM_IOCTL_MODESET_CTL.
+      <variablelist>
+        <varlistentry>
+          <term>DRM_IOCTL_WAIT_VBLANK</term>
+          <listitem>
+            <para>
+              This takes a struct drm_wait_vblank structure as its argument,
+              and it is used to block or request a signal when a specified
+              vblank event occurs.
+            </para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term>DRM_IOCTL_MODESET_CTL</term>
+          <listitem>
+            <para>
+              This should be called by application level drivers before and
+              after mode setting, since on many devices the vertical blank
+              counter is reset at that time.  Internally, the DRM snapshots
+              the last vblank count when the ioctl is called with the
+              _DRM_PRE_MODESET command, so that the counter won't go backwards
+              (which is dealt with when _DRM_POST_MODESET is used).
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
 <!--!Edrivers/char/drm/drm_irq.c-->
     </para>
     <para>
-      DRM_IOCTL_WAIT_VBLANK takes a struct drm_wait_vblank structure
-      as its argument, and is used to block or request a signal when a
-      specified vblank event occurs.
-    </para>
-    <para>
-      DRM_IOCTL_MODESET_CTL should be called by application level
-      drivers before and after mode setting, since on many devices the
-      vertical blank counter will be reset at that time.  Internally,
-      the DRM snapshots the last vblank count when the ioctl is called
-      with the _DRM_PRE_MODESET command so that the counter won't go
-      backwards (which is dealt with when _DRM_POST_MODESET is used).
-    </para>
-    <para>
       To support the functions above, the DRM core provides several
       helper functions for tracking vertical blank counters, and
       requires drivers to provide several callbacks:
@@ -632,24 +657,24 @@ void intel_crt_init(struct drm_device *dev)
       register.  The enable and disable vblank callbacks should enable
       and disable vertical blank interrupts, respectively.  In the
       absence of DRM clients waiting on vblank events, the core DRM
-      code will use the disable_vblank() function to disable
-      interrupts, which saves power.  They'll be re-enabled again when
+      code uses the disable_vblank() function to disable
+      interrupts, which saves power.  They are re-enabled again when
       a client calls the vblank wait ioctl above.
     </para>
     <para>
-      Devices that don't provide a count register can simply use an
+      A device that doesn't provide a count register may simply use an
       internal atomic counter incremented on every vertical blank
-      interrupt, and can make their enable and disable vblank
-      functions into no-ops.
+      interrupt (and then treat the enable_vblank() and disable_vblank()
+      callbacks as no-ops).
     </para>
   </sect1>
 
   <sect1>
     <title>Memory management</title>
     <para>
-      The memory manager lies at the heart of many DRM operations, and
-      is also required to support advanced client features like OpenGL
-      pbuffers.  The DRM currently contains two memory managers, TTM
+      The memory manager lies at the heart of many DRM operations; it
+      is required to support advanced client features like OpenGL
+      pbuffers.  The DRM currently contains two memory managers: TTM
       and GEM.
     </para>
 
@@ -679,41 +704,46 @@ void intel_crt_init(struct drm_device *dev)
       <para>
        GEM-enabled drivers must provide gem_init_object() and
        gem_free_object() callbacks to support the core memory
-       allocation routines.  They should also provide several driver
-       specific ioctls to support command execution, pinning, buffer
+       allocation routines.  They should also provide several driver-specific
+       ioctls to support command execution, pinning, buffer
        read &amp; write, mapping, and domain ownership transfers.
       </para>
       <para>
-       On a fundamental level, GEM involves several operations: memory
-       allocation and freeing, command execution, and aperture management
-       at command execution time.  Buffer object allocation is relatively
+       On a fundamental level, GEM involves several operations:
+       <itemizedlist>
+         <listitem>Memory allocation and freeing</listitem>
+         <listitem>Command execution</listitem>
+         <listitem>Aperture management at command execution time</listitem>
+       </itemizedlist>
+       Buffer object allocation is relatively
        straightforward and largely provided by Linux's shmem layer, which
        provides memory to back each object.  When mapped into the GTT
        or used in a command buffer, the backing pages for an object are
        flushed to memory and marked write combined so as to be coherent
-       with the GPU.  Likewise, when the GPU finishes rendering to an object,
-       if the CPU accesses it, it must be made coherent with the CPU's view
+       with the GPU.  Likewise, if the CPU accesses an object after the GPU
+       has finished rendering to the object, then the object must be made
+       coherent with the CPU's view
        of memory, usually involving GPU cache flushing of various kinds.
-       This core CPU&lt;-&gt;GPU coherency management is provided by the GEM
-       set domain function, which evaluates an object's current domain and
+       This core CPU&lt;-&gt;GPU coherency management is provided by a
+       device-specific ioctl, which evaluates an object's current domain and
        performs any necessary flushing or synchronization to put the object
        into the desired coherency domain (note that the object may be busy,
-       i.e. an active render target; in that case the set domain function
-       will block the client and wait for rendering to complete before
+       i.e. an active render target; in that case, setting the domain
+       blocks the client and waits for rendering to complete before
        performing any necessary flushing operations).
       </para>
       <para>
        Perhaps the most important GEM function is providing a command
        execution interface to clients.  Client programs construct command
-       buffers containing references to previously allocated memory objects
-       and submit them to GEM.  At that point, GEM will take care to bind
+       buffers containing references to previously allocated memory objects,
+       and then submit them to GEM.  At that point, GEM takes care to bind
        all the objects into the GTT, execute the buffer, and provide
        necessary synchronization between clients accessing the same buffers.
        This often involves evicting some objects from the GTT and re-binding
        others (a fairly expensive operation), and providing relocation
        support which hides fixed GTT offsets from clients.  Clients must
        take care not to submit command buffers that reference more objects
-       than can fit in the GTT or GEM will reject them and no rendering
+       than can fit in the GTT; otherwise, GEM will reject them and no rendering
        will occur.  Similarly, if several objects in the buffer require
        fence registers to be allocated for correct rendering (e.g. 2D blits
        on pre-965 chips), care must be taken not to require more fence
@@ -729,7 +759,7 @@ void intel_crt_init(struct drm_device *dev)
     <title>Output management</title>
     <para>
       At the core of the DRM output management code is a set of
-      structures representing CRTCs, encoders and connectors.
+      structures representing CRTCs, encoders, and connectors.
     </para>
     <para>
       A CRTC is an abstraction representing a part of the chip that
@@ -765,21 +795,19 @@ void intel_crt_init(struct drm_device *dev)
   <sect1>
     <title>Framebuffer management</title>
     <para>
-      In order to set a mode on a given CRTC, encoder and connector
-      configuration, clients need to provide a framebuffer object which
-      will provide a source of pixels for the CRTC to deliver to the encoder(s)
-      and ultimately the connector(s) in the configuration.  A framebuffer
-      is fundamentally a driver specific memory object, made into an opaque
-      handle by the DRM addfb function.  Once an fb has been created this
-      way it can be passed to the KMS mode setting routines for use in
-      a configuration.
+      Clients need to provide a framebuffer object which provides a source
+      of pixels for a CRTC to deliver to the encoder(s) and ultimately the
+      connector(s). A framebuffer is fundamentally a driver-specific memory
+      object, made into an opaque handle by the DRM's addfb() function.
+      Once a framebuffer has been created this way, it may be passed to the
+      KMS mode setting routines for use in a completed configuration.
     </para>
   </sect1>
 
   <sect1>
     <title>Command submission &amp; fencing</title>
     <para>
-      This should cover a few device specific command submission
+      This should cover a few device-specific command submission
       implementations.
     </para>
   </sect1>
@@ -789,7 +817,7 @@ void intel_crt_init(struct drm_device *dev)
     <para>
       The DRM core provides some suspend/resume code, but drivers
       wanting full suspend/resume support should provide save() and
-      restore() functions.  These will be called at suspend,
+      restore() functions.  These are called at suspend,
       hibernate, or resume time, and should perform any state save or
       restore required by your device across suspend or hibernate
       states.
@@ -812,8 +840,8 @@ void intel_crt_init(struct drm_device *dev)
     <para>
       The DRM core exports several interfaces to applications,
       generally intended to be used through corresponding libdrm
-      wrapper functions.  In addition, drivers export device specific
-      interfaces for use by userspace drivers &amp; device aware
+      wrapper functions.  In addition, drivers export device-specific
+      interfaces for use by userspace drivers &amp; device-aware
       applications through ioctls and sysfs files.
     </para>
     <para>
@@ -822,8 +850,8 @@ void intel_crt_init(struct drm_device *dev)
       management, memory management, and output management.
     </para>
     <para>
-      Cover generic ioctls and sysfs layout here.  Only need high
-      level info, since man pages will cover the rest.
+      Cover generic ioctls and sysfs layout here.  We only need high-level
+      info, since man pages should cover the rest.
     </para>
   </chapter>
 
index 71464e0..b79d0a1 100644 (file)
@@ -98,14 +98,12 @@ You must enable "SCSI tape drive support for Smart Array 5xxx" and
 "SCSI support" in your kernel configuration to be able to use SCSI
 tape drives with your Smart Array 5xxx controller.
 
-Additionally, note that the driver will not engage the SCSI core at init 
-time.  The driver must be directed to dynamically engage the SCSI core via 
-the /proc filesystem entry which the "block" side of the driver creates as 
-/proc/driver/cciss/cciss* at runtime.  This is because at driver init time, 
-the SCSI core may not yet be initialized (because the driver is a block 
-driver) and attempting to register it with the SCSI core in such a case 
-would cause a hang.  This is best done via an initialization script 
-(typically in /etc/init.d, but could vary depending on distribution). 
+Additionally, note that the driver will engage the SCSI core at init
+time if any tape drives or medium changers are detected.  The driver may
+also be directed to dynamically engage the SCSI core via the /proc filesystem
+entry which the "block" side of the driver creates as
+/proc/driver/cciss/cciss* at runtime.  This is best done via a script.
+
 For example:
 
        for x in /proc/driver/cciss/cciss[0-9]*
index c21d777..7e62de1 100644 (file)
@@ -33,9 +33,9 @@ demonstrate this problem using nested bash shells:
 
        From a second, unrelated bash shell:
        $ kill -SIGSTOP 16690
-       $ kill -SIGCONT 16990
+       $ kill -SIGCONT 16690
 
-       <at this point 16990 exits and causes 16644 to exit too>
+       <at this point 16690 exits and causes 16644 to exit too>
 
 This happens because bash can observe both signals and choose how it
 responds to them.
diff --git a/Documentation/cgroups/net_prio.txt b/Documentation/cgroups/net_prio.txt
new file mode 100644 (file)
index 0000000..01b3226
--- /dev/null
@@ -0,0 +1,53 @@
+Network priority cgroup
+-------------------------
+
+The Network priority cgroup provides an interface to allow an administrator to
+dynamically set the priority of network traffic generated by various
+applications
+
+Nominally, an application would set the priority of its traffic via the
+SO_PRIORITY socket option.  This however, is not always possible because:
+
+1) The application may not have been coded to set this value
+2) The priority of application traffic is often a site-specific administrative
+   decision rather than an application defined one.
+
+This cgroup allows an administrator to assign a process to a group which defines
+the priority of egress traffic on a given interface. Network priority groups can
+be created by first mounting the cgroup filesystem.
+
+# mount -t cgroup -onet_prio none /sys/fs/cgroup/net_prio
+
+With the above step, the initial group acting as the parent accounting group
+becomes visible at '/sys/fs/cgroup/net_prio'.  This group includes all tasks in
+the system. '/sys/fs/cgroup/net_prio/tasks' lists the tasks in this cgroup.
+
+Each net_prio cgroup contains two files that are subsystem specific
+
+net_prio.prioidx
+This file is read-only, and is simply informative.  It contains a unique integer
+value that the kernel uses as an internal representation of this cgroup.
+
+net_prio.ifpriomap
+This file contains a map of the priorities assigned to traffic originating from
+processes in this group and egressing the system on various interfaces. It
+contains a list of tuples in the form <ifname priority>.  Contents of this file
+can be modified by echoing a string into the file using the same tuple format.
+for example:
+
+echo "eth0 5" > /sys/fs/cgroups/net_prio/iscsi/net_prio.ifpriomap
+
+This command would force any traffic originating from processes belonging to the
+iscsi net_prio cgroup and egressing on interface eth0 to have the priority of
+said traffic set to the value 5. The parent accounting group also has a
+writeable 'net_prio.ifpriomap' file that can be used to set a system default
+priority.
+
+Priorities are set immediately prior to queueing a frame to the device
+queueing discipline (qdisc) so priorities will be assigned prior to the hardware
+queue selection being made.
+
+One usage for the net_prio cgroup is with mqprio qdisc allowing application
+traffic to be steered to hardware/driver based traffic classes. These mappings
+can then be managed by administrators or other networking protocols such as
+DCBX.
index f41ea24..1dc1c24 100644 (file)
@@ -78,3 +78,30 @@ in software. This is currently WIP.
 
 See header include/net/mac802154.h and several drivers in drivers/ieee802154/.
 
+6LoWPAN Linux implementation
+============================
+
+The IEEE 802.15.4 standard specifies an MTU of 128 bytes, yielding about 80
+octets of actual MAC payload once security is turned on, on a wireless link
+with a link throughput of 250 kbps or less.  The 6LoWPAN adaptation format
+[RFC4944] was specified to carry IPv6 datagrams over such constrained links,
+taking into account limited bandwidth, memory, or energy resources that are
+expected in applications such as wireless Sensor Networks.  [RFC4944] defines
+a Mesh Addressing header to support sub-IP forwarding, a Fragmentation header
+to support the IPv6 minimum MTU requirement [RFC2460], and stateless header
+compression for IPv6 datagrams (LOWPAN_HC1 and LOWPAN_HC2) to reduce the
+relatively large IPv6 and UDP headers down to (in the best case) several bytes.
+
+In Semptember 2011 the standard update was published - [RFC6282].
+It deprecates HC1 and HC2 compression and defines IPHC encoding format which is
+used in this Linux implementation.
+
+All the code related to 6lowpan you may find in files: net/ieee802154/6lowpan.*
+
+To setup 6lowpan interface you need (busybox release > 1.17.0):
+1. Add IEEE802.15.4 interface and initialize PANid;
+2. Add 6lowpan interface by command like:
+   # ip link add link wpan0 name lowpan0 type lowpan
+3. Set MAC (if needs):
+   # ip link set lowpan0 address de:ad:be:ef:ca:fe:ba:be
+4. Bring up 'lowpan0' interface
index cb7f314..b886706 100644 (file)
@@ -20,7 +20,7 @@ ip_no_pmtu_disc - BOOLEAN
        default FALSE
 
 min_pmtu - INTEGER
-       default 562 - minimum discovered Path MTU
+       default 552 - minimum discovered Path MTU
 
 route/max_size - INTEGER
        Maximum number of routes allowed in the kernel.  Increase
@@ -31,6 +31,16 @@ neigh/default/gc_thresh3 - INTEGER
        when using large numbers of interfaces and when communicating
        with large numbers of directly-connected peers.
 
+neigh/default/unres_qlen_bytes - INTEGER
+       The maximum number of bytes which may be used by packets
+       queued for each unresolved address by other network layers.
+       (added in linux 3.3)
+
+neigh/default/unres_qlen - INTEGER
+       The maximum number of packets which may be queued for each
+       unresolved address by other network layers.
+       (deprecated in linux 3.3) : use unres_qlen_bytes instead.
+
 mtu_expires - INTEGER
        Time, in seconds, that cached PMTU information is kept.
 
diff --git a/Documentation/networking/team.txt b/Documentation/networking/team.txt
new file mode 100644 (file)
index 0000000..5a01368
--- /dev/null
@@ -0,0 +1,2 @@
+Team devices are driven from userspace via libteam library which is here:
+       https://github.com/jpirko/libteam
index 4f34432..edad99a 100644 (file)
@@ -349,6 +349,7 @@ STAC92HD83*
   ref          Reference board
   mic-ref      Reference board with power management for ports
   dell-s14     Dell laptop
+  dell-vostro-3500     Dell Vostro 3500 laptop
   hp           HP laptops with (inverted) mute-LED
   hp-dv7-4000  HP dv-7 4000
   auto         BIOS setup (default)
index 03e2771..91fee3b 100644 (file)
@@ -579,7 +579,7 @@ Development Tree
 ~~~~~~~~~~~~~~~~
 The latest development codes for HD-audio are found on sound git tree:
 
-- git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6.git
+- git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
 
 The master branch or for-next branches can be used as the main
 development branches in general while the HD-audio specific patches
@@ -594,7 +594,7 @@ is, installed via the usual spells: configure, make and make
 install(-modules).  See INSTALL in the package.  The snapshot tarballs
 are found at:
 
-- ftp://ftp.kernel.org/pub/linux/kernel/people/tiwai/snapshot/
+- ftp://ftp.suse.com/pub/people/tiwai/snapshot/
 
 
 Sending a Bug Report
@@ -696,7 +696,7 @@ via hda-verb won't change the mixer value.
 
 The hda-verb program is found in the ftp directory:
 
-- ftp://ftp.kernel.org/pub/linux/kernel/people/tiwai/misc/
+- ftp://ftp.suse.com/pub/people/tiwai/misc/
 
 Also a git repository is available:
 
@@ -764,7 +764,7 @@ operation, the jack plugging simulation, etc.
 
 The package is found in:
 
-- ftp://ftp.kernel.org/pub/linux/kernel/people/tiwai/misc/
+- ftp://ftp.suse.com/pub/people/tiwai/misc/
 
 A git repository is available:
 
diff --git a/Kbuild b/Kbuild
index 4caab4f..b8b708a 100644 (file)
--- a/Kbuild
+++ b/Kbuild
@@ -92,7 +92,7 @@ always += missing-syscalls
 targets += missing-syscalls
 
 quiet_cmd_syscalls = CALL    $<
-      cmd_syscalls = $(CONFIG_SHELL) $< $(CC) $(c_flags)
+      cmd_syscalls = $(CONFIG_SHELL) $< $(CC) $(c_flags) $(missing_syscalls_flags)
 
 missing-syscalls: scripts/checksyscalls.sh $(offsets-file) FORCE
        $(call cmd,syscalls)
index 4808256..717d9e9 100644 (file)
@@ -1106,6 +1106,7 @@ F:        drivers/media/video/s5p-fimc/
 ARM/SAMSUNG S5P SERIES Multi Format Codec (MFC) SUPPORT
 M:     Kyungmin Park <kyungmin.park@samsung.com>
 M:     Kamil Debski <k.debski@samsung.com>
+M:     Jeongtae Park <jtp.park@samsung.com>
 L:     linux-arm-kernel@lists.infradead.org
 L:     linux-media@vger.kernel.org
 S:     Maintained
@@ -1926,9 +1927,11 @@ S:       Maintained
 F:     drivers/connector/
 
 CONTROL GROUPS (CGROUPS)
-M:     Paul Menage <paul@paulmenage.org>
+M:     Tejun Heo <tj@kernel.org>
 M:     Li Zefan <lizf@cn.fujitsu.com>
 L:     containers@lists.linux-foundation.org
+L:     cgroups@vger.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git
 S:     Maintained
 F:     include/linux/cgroup*
 F:     kernel/cgroup*
@@ -2342,6 +2345,13 @@ S:       Supported
 F:     drivers/gpu/drm/i915
 F:     include/drm/i915*
 
+DRM DRIVERS FOR EXYNOS
+M:     Inki Dae <inki.dae@samsung.com>
+L:     dri-devel@lists.freedesktop.org
+S:     Supported
+F:     drivers/gpu/drm/exynos
+F:     include/drm/exynos*
+
 DSCC4 DRIVER
 M:     Francois Romieu <romieu@fr.zoreil.com>
 L:     netdev@vger.kernel.org
@@ -2576,7 +2586,7 @@ S:        Maintained
 F:     drivers/net/ethernet/i825xx/eexpress.*
 
 ETHERNET BRIDGE
-M:     Stephen Hemminger <shemminger@linux-foundation.org>
+M:     Stephen Hemminger <shemminger@vyatta.com>
 L:     bridge@lists.linux-foundation.org
 L:     netdev@vger.kernel.org
 W:     http://www.linuxfoundation.org/en/Net:Bridge
@@ -4296,6 +4306,7 @@ MEMORY RESOURCE CONTROLLER
 M:     Balbir Singh <bsingharora@gmail.com>
 M:     Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp>
 M:     KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
+L:     cgroups@vger.kernel.org
 L:     linux-mm@kvack.org
 S:     Maintained
 F:     mm/memcontrol.c
@@ -4329,7 +4340,7 @@ MIPS
 M:     Ralf Baechle <ralf@linux-mips.org>
 L:     linux-mips@linux-mips.org
 W:     http://www.linux-mips.org/
-T:     git git://git.linux-mips.org/pub/scm/linux.git
+T:     git git://git.linux-mips.org/pub/scm/ralf/linux.git
 Q:     http://patchwork.linux-mips.org/project/linux-mips/list/
 S:     Supported
 F:     Documentation/mips/
@@ -4462,7 +4473,7 @@ S:        Supported
 F:     drivers/infiniband/hw/nes/
 
 NETEM NETWORK EMULATOR
-M:     Stephen Hemminger <shemminger@linux-foundation.org>
+M:     Stephen Hemminger <shemminger@vyatta.com>
 L:     netem@lists.linux-foundation.org
 S:     Maintained
 F:     net/sched/sch_netem.c
@@ -4939,7 +4950,7 @@ F:        drivers/char/ppdev.c
 F:     include/linux/ppdev.h
 
 PARAVIRT_OPS INTERFACE
-M:     Jeremy Fitzhardinge <jeremy@xensource.com>
+M:     Jeremy Fitzhardinge <jeremy@goop.org>
 M:     Chris Wright <chrisw@sous-sol.org>
 M:     Alok Kataria <akataria@vmware.com>
 M:     Rusty Russell <rusty@rustcorp.com.au>
@@ -5977,7 +5988,7 @@ S:        Maintained
 F:     drivers/usb/misc/sisusbvga/
 
 SKGE, SKY2 10/100/1000 GIGABIT ETHERNET DRIVERS
-M:     Stephen Hemminger <shemminger@linux-foundation.org>
+M:     Stephen Hemminger <shemminger@vyatta.com>
 L:     netdev@vger.kernel.org
 S:     Maintained
 F:     drivers/net/ethernet/marvell/sk*
@@ -6122,7 +6133,7 @@ F:        sound/
 SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT (ASoC)
 M:     Liam Girdwood <lrg@ti.com>
 M:     Mark Brown <broonie@opensource.wolfsonmicro.com>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 W:     http://alsa-project.org/main/index.php/ASoC
 S:     Supported
@@ -6484,6 +6495,13 @@ W:       http://tcp-lp-mod.sourceforge.net/
 S:     Maintained
 F:     net/ipv4/tcp_lp.c
 
+TEAM DRIVER
+M:     Jiri Pirko <jpirko@redhat.com>
+L:     netdev@vger.kernel.org
+S:     Supported
+F:     drivers/net/team/
+F:     include/linux/if_team.h
+
 TEGRA SUPPORT
 M:     Colin Cross <ccross@android.com>
 M:     Olof Johansson <olof@lixom.net>
@@ -7391,8 +7409,8 @@ S:        Maintained
 F:     arch/x86/kernel/cpu/mcheck/*
 
 XEN HYPERVISOR INTERFACE
-M:     Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
 M:     Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
+M:     Jeremy Fitzhardinge <jeremy@goop.org>
 L:     xen-devel@lists.xensource.com (moderated for non-subscribers)
 L:     virtualization@lists.linux-foundation.org
 S:     Supported
@@ -7425,7 +7443,8 @@ F:        drivers/xen/*swiotlb*
 
 XFS FILESYSTEM
 P:     Silicon Graphics Inc
-M:     Alex Elder <aelder@sgi.com>
+M:     Ben Myers <bpm@sgi.com>
+M:     Alex Elder <elder@kernel.org>
 M:     xfs-masters@oss.sgi.com
 L:     xfs@oss.sgi.com
 W:     http://oss.sgi.com/projects/xfs
index 361e4f0..dab8610 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 3
 PATCHLEVEL = 2
 SUBLEVEL = 0
-EXTRAVERSION = -rc1
+EXTRAVERSION = -rc2
 NAME = Saber-toothed Squirrel
 
 # *DOCUMENTATION*
index 06edfef..082355f 100644 (file)
@@ -69,6 +69,9 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 /* O_NONBLOCK clashes with the bits used for socket types.  Therefore we
  * have to define SOCK_NONBLOCK to a different value here.
  */
index 176062a..5df26a9 100644 (file)
@@ -65,6 +65,8 @@ $(obj)/%.dtb: $(src)/dts/%.dts
 
 $(obj)/dtbs: $(addprefix $(obj)/, $(dtb-y))
 
+clean-files := *.dtb
+
 quiet_cmd_uimage = UIMAGE  $@
       cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A arm -O linux -T kernel \
                   -C none -a $(LOADADDR) -e $(STARTADDR) \
index 9b29a62..3f9abd6 100644 (file)
        sdhci@c8000400 {
                cd-gpios = <&gpio 69 0>; /* gpio PI5 */
                wp-gpios = <&gpio 57 0>; /* gpio PH1 */
-               power-gpios = <&gpio 155 0>; /* gpio PT3 */
+               power-gpios = <&gpio 70 0>; /* gpio PI6 */
        };
 
        sdhci@c8000600 {
-               power-gpios = <&gpio 70 0>; /* gpio PI6 */
                support-8bit;
        };
 };
index 1db1143..7df239b 100644 (file)
@@ -20,6 +20,8 @@
 #ifndef __ASM_ARM_HARDWARE_L2X0_H
 #define __ASM_ARM_HARDWARE_L2X0_H
 
+#include <linux/errno.h>
+
 #define L2X0_CACHE_ID                  0x000
 #define L2X0_CACHE_TYPE                        0x004
 #define L2X0_CTRL                      0x100
index 7d19425..2b0efc3 100644 (file)
@@ -13,6 +13,7 @@
 struct tag;
 struct meminfo;
 struct sys_timer;
+struct pt_regs;
 
 struct machine_desc {
        unsigned int            nr;             /* architecture number  */
index 90ffd04..dec6f9a 100644 (file)
@@ -62,4 +62,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #endif /* _ASM_SOCKET_H */
index c60a294..4a11237 100644 (file)
 #define __NR_syncfs                    (__NR_SYSCALL_BASE+373)
 #define __NR_sendmmsg                  (__NR_SYSCALL_BASE+374)
 #define __NR_setns                     (__NR_SYSCALL_BASE+375)
+#define __NR_process_vm_readv          (__NR_SYSCALL_BASE+376)
+#define __NR_process_vm_writev         (__NR_SYSCALL_BASE+377)
 
 /*
  * The following SWIs are ARM private.
index 9943e9e..463ff4a 100644 (file)
                CALL(sys_syncfs)
                CALL(sys_sendmmsg)
 /* 375 */      CALL(sys_setns)
+               CALL(sys_process_vm_readv)
+               CALL(sys_process_vm_writev)
 #ifndef syscalls_counted
 .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
 #define syscalls_counted
index 566c54c..08c82fd 100644 (file)
@@ -360,7 +360,7 @@ __secondary_data:
  *  r13 = *virtual* address to jump to upon completion
  */
 __enable_mmu:
-#ifdef CONFIG_ALIGNMENT_TRAP
+#if defined(CONFIG_ALIGNMENT_TRAP) && __LINUX_ARM_ARCH__ < 6
        orr     r0, r0, #CR_A
 #else
        bic     r0, r0, #CR_A
index c1b4463..e59bbd4 100644 (file)
@@ -32,24 +32,6 @@ static atomic_t waiting_for_crash_ipi;
 
 int machine_kexec_prepare(struct kimage *image)
 {
-       unsigned long page_list;
-       void *reboot_code_buffer;
-       page_list = image->head & PAGE_MASK;
-
-       reboot_code_buffer = page_address(image->control_code_page);
-
-       /* Prepare parameters for reboot_code_buffer*/
-       kexec_start_address = image->start;
-       kexec_indirection_page = page_list;
-       kexec_mach_type = machine_arch_type;
-       kexec_boot_atags = image->start - KEXEC_ARM_ZIMAGE_OFFSET + KEXEC_ARM_ATAGS_OFFSET;
-
-       /* copy our kernel relocation code to the control code page */
-       memcpy(reboot_code_buffer,
-              relocate_new_kernel, relocate_new_kernel_size);
-
-       flush_icache_range((unsigned long) reboot_code_buffer,
-                          (unsigned long) reboot_code_buffer + KEXEC_CONTROL_PAGE_SIZE);
        return 0;
 }
 
@@ -100,14 +82,31 @@ void (*kexec_reinit)(void);
 
 void machine_kexec(struct kimage *image)
 {
+       unsigned long page_list;
        unsigned long reboot_code_buffer_phys;
        void *reboot_code_buffer;
 
+
+       page_list = image->head & PAGE_MASK;
+
        /* we need both effective and real address here */
        reboot_code_buffer_phys =
            page_to_pfn(image->control_code_page) << PAGE_SHIFT;
        reboot_code_buffer = page_address(image->control_code_page);
 
+       /* Prepare parameters for reboot_code_buffer*/
+       kexec_start_address = image->start;
+       kexec_indirection_page = page_list;
+       kexec_mach_type = machine_arch_type;
+       kexec_boot_atags = image->start - KEXEC_ARM_ZIMAGE_OFFSET + KEXEC_ARM_ATAGS_OFFSET;
+
+       /* copy our kernel relocation code to the control code page */
+       memcpy(reboot_code_buffer,
+              relocate_new_kernel, relocate_new_kernel_size);
+
+
+       flush_icache_range((unsigned long) reboot_code_buffer,
+                          (unsigned long) reboot_code_buffer + KEXEC_CONTROL_PAGE_SIZE);
        printk(KERN_INFO "Bye!\n");
 
        if (kexec_reinit)
index 7e7977a..3448a3f 100644 (file)
@@ -461,8 +461,10 @@ static void __init setup_processor(void)
               cpu_name, read_cpuid_id(), read_cpuid_id() & 15,
               proc_arch[cpu_architecture()], cr_alignment);
 
-       sprintf(init_utsname()->machine, "%s%c", list->arch_name, ENDIANNESS);
-       sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS);
+       snprintf(init_utsname()->machine, __NEW_UTS_LEN + 1, "%s%c",
+                list->arch_name, ENDIANNESS);
+       snprintf(elf_platform, ELF_PLATFORM_SIZE, "%s%c",
+                list->elf_name, ENDIANNESS);
        elf_hwcap = list->elf_hwcap;
 #ifndef CONFIG_ARM_THUMB
        elf_hwcap &= ~HWCAP_THUMB;
index a4401d6..adad70d 100644 (file)
@@ -98,7 +98,7 @@ void __init at91_add_device_usbh(struct at91_usbh_data *data) {}
  *  USB HS Device (Gadget)
  * -------------------------------------------------------------------- */
 
-#if defined(CONFIG_USB_GADGET_ATMEL_USBA) || defined(CONFIG_USB_GADGET_ATMEL_USBA_MODULE)
+#if defined(CONFIG_USB_ATMEL_USBA) || defined(CONFIG_USB_ATMEL_USBA_MODULE)
 
 static struct resource usba_udc_resources[] = {
        [0] = {
@@ -1021,8 +1021,8 @@ void __init at91_add_device_ssc(unsigned id, unsigned pins) {}
 #if defined(CONFIG_SERIAL_ATMEL)
 static struct resource dbgu_resources[] = {
        [0] = {
-               .start  = AT91_VA_BASE_SYS + AT91_DBGU,
-               .end    = AT91_VA_BASE_SYS + AT91_DBGU + SZ_512 - 1,
+               .start  = AT91_BASE_SYS + AT91_DBGU,
+               .end    = AT91_BASE_SYS + AT91_DBGU + SZ_512 - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -1035,7 +1035,6 @@ static struct resource dbgu_resources[] = {
 static struct atmel_uart_data dbgu_data = {
        .use_dma_tx     = 0,
        .use_dma_rx     = 0,            /* DBGU not capable of receive DMA */
-       .regs           = (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU),
 };
 
 static u64 dbgu_dmamask = DMA_BIT_MASK(32);
index 01d8bbd..66591fa 100644 (file)
@@ -877,8 +877,8 @@ void __init at91_add_device_ssc(unsigned id, unsigned pins) {}
 #if defined(CONFIG_SERIAL_ATMEL)
 static struct resource dbgu_resources[] = {
        [0] = {
-               .start  = AT91_VA_BASE_SYS + AT91_DBGU,
-               .end    = AT91_VA_BASE_SYS + AT91_DBGU + SZ_512 - 1,
+               .start  = AT91_BASE_SYS + AT91_DBGU,
+               .end    = AT91_BASE_SYS + AT91_DBGU + SZ_512 - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -891,7 +891,6 @@ static struct resource dbgu_resources[] = {
 static struct atmel_uart_data dbgu_data = {
        .use_dma_tx     = 0,
        .use_dma_rx     = 0,            /* DBGU not capable of receive DMA */
-       .regs           = (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU),
 };
 
 static u64 dbgu_dmamask = DMA_BIT_MASK(32);
index 24b6f8c..25e3464 100644 (file)
@@ -837,8 +837,8 @@ void __init at91_add_device_ssc(unsigned id, unsigned pins) {}
 #if defined(CONFIG_SERIAL_ATMEL)
 static struct resource dbgu_resources[] = {
        [0] = {
-               .start  = AT91_VA_BASE_SYS + AT91_DBGU,
-               .end    = AT91_VA_BASE_SYS + AT91_DBGU + SZ_512 - 1,
+               .start  = AT91_BASE_SYS + AT91_DBGU,
+               .end    = AT91_BASE_SYS + AT91_DBGU + SZ_512 - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -851,7 +851,6 @@ static struct resource dbgu_resources[] = {
 static struct atmel_uart_data dbgu_data = {
        .use_dma_tx     = 0,
        .use_dma_rx     = 0,            /* DBGU not capable of receive DMA */
-       .regs           = (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU),
 };
 
 static u64 dbgu_dmamask = DMA_BIT_MASK(32);
index 3b70b38..ae78f4d 100644 (file)
@@ -816,8 +816,8 @@ void __init at91_add_device_ssc(unsigned id, unsigned pins) {}
 #if defined(CONFIG_SERIAL_ATMEL)
 static struct resource dbgu_resources[] = {
        [0] = {
-               .start  = AT91_VA_BASE_SYS + AT91_DBGU,
-               .end    = AT91_VA_BASE_SYS + AT91_DBGU + SZ_512 - 1,
+               .start  = AT91_BASE_SYS + AT91_DBGU,
+               .end    = AT91_BASE_SYS + AT91_DBGU + SZ_512 - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -830,7 +830,6 @@ static struct resource dbgu_resources[] = {
 static struct atmel_uart_data dbgu_data = {
        .use_dma_tx     = 0,
        .use_dma_rx     = 0,            /* DBGU not capable of receive DMA */
-       .regs           = (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU),
 };
 
 static u64 dbgu_dmamask = DMA_BIT_MASK(32);
index 3faa1fd..ad017eb 100644 (file)
@@ -1196,8 +1196,8 @@ void __init at91_add_device_ssc(unsigned id, unsigned pins) {}
 
 static struct resource dbgu_resources[] = {
        [0] = {
-               .start  = AT91_VA_BASE_SYS + AT91_DBGU,
-               .end    = AT91_VA_BASE_SYS + AT91_DBGU + SZ_512 - 1,
+               .start  = AT91_BASE_SYS + AT91_DBGU,
+               .end    = AT91_BASE_SYS + AT91_DBGU + SZ_512 - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -1210,7 +1210,6 @@ static struct resource dbgu_resources[] = {
 static struct atmel_uart_data dbgu_data = {
        .use_dma_tx     = 0,
        .use_dma_rx     = 0,            /* DBGU not capable of receive DMA */
-       .regs           = (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU),
 };
 
 static u64 dbgu_dmamask = DMA_BIT_MASK(32);
index 000b5e1..09a16d6 100644 (file)
@@ -197,7 +197,7 @@ void __init at91_add_device_usbh_ehci(struct at91_usbh_data *data) {}
  *  USB HS Device (Gadget)
  * -------------------------------------------------------------------- */
 
-#if defined(CONFIG_USB_GADGET_ATMEL_USBA) || defined(CONFIG_USB_GADGET_ATMEL_USBA_MODULE)
+#if defined(CONFIG_USB_ATMEL_USBA) || defined(CONFIG_USB_ATMEL_USBA_MODULE)
 static struct resource usba_udc_resources[] = {
        [0] = {
                .start  = AT91SAM9G45_UDPHS_FIFO,
@@ -1332,8 +1332,8 @@ void __init at91_add_device_ssc(unsigned id, unsigned pins) {}
 #if defined(CONFIG_SERIAL_ATMEL)
 static struct resource dbgu_resources[] = {
        [0] = {
-               .start  = AT91_VA_BASE_SYS + AT91_DBGU,
-               .end    = AT91_VA_BASE_SYS + AT91_DBGU + SZ_512 - 1,
+               .start  = AT91_BASE_SYS + AT91_DBGU,
+               .end    = AT91_BASE_SYS + AT91_DBGU + SZ_512 - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -1346,7 +1346,6 @@ static struct resource dbgu_resources[] = {
 static struct atmel_uart_data dbgu_data = {
        .use_dma_tx     = 0,
        .use_dma_rx     = 0,
-       .regs           = (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU),
 };
 
 static u64 dbgu_dmamask = DMA_BIT_MASK(32);
index 305a851..628eb56 100644 (file)
@@ -75,7 +75,7 @@ void __init at91_add_device_hdmac(void) {}
  *  USB HS Device (Gadget)
  * -------------------------------------------------------------------- */
 
-#if defined(CONFIG_USB_GADGET_ATMEL_USBA) || defined(CONFIG_USB_GADGET_ATMEL_USBA_MODULE)
+#if defined(CONFIG_USB_ATMEL_USBA) || defined(CONFIG_USB_ATMEL_USBA_MODULE)
 
 static struct resource usba_udc_resources[] = {
        [0] = {
@@ -908,8 +908,8 @@ void __init at91_add_device_ssc(unsigned id, unsigned pins) {}
 #if defined(CONFIG_SERIAL_ATMEL)
 static struct resource dbgu_resources[] = {
        [0] = {
-               .start  = AT91_VA_BASE_SYS + AT91_DBGU,
-               .end    = AT91_VA_BASE_SYS + AT91_DBGU + SZ_512 - 1,
+               .start  = AT91_BASE_SYS + AT91_DBGU,
+               .end    = AT91_BASE_SYS + AT91_DBGU + SZ_512 - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -922,7 +922,6 @@ static struct resource dbgu_resources[] = {
 static struct atmel_uart_data dbgu_data = {
        .use_dma_tx     = 0,
        .use_dma_rx     = 0,            /* DBGU not capable of receive DMA */
-       .regs           = (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU),
 };
 
 static u64 dbgu_dmamask = DMA_BIT_MASK(32);
index 649b052..12a3f95 100644 (file)
@@ -384,7 +384,7 @@ static struct spi_board_info yl9200_spi_devices[] = {
 #include <video/s1d13xxxfb.h>
 
 
-static void __init yl9200_init_video(void)
+static void yl9200_init_video(void)
 {
        /* NWAIT Signal */
        at91_set_A_periph(AT91_PIN_PC6, 0);
index 8eb459f..8e4a1bd 100644 (file)
@@ -21,6 +21,8 @@
 #ifndef __ASM_ARCH_VMALLOC_H
 #define __ASM_ARCH_VMALLOC_H
 
+#include <mach/hardware.h>
+
 #define VMALLOC_END            (AT91_VIRT_BASE & PGDIR_MASK)
 
 #endif
index 43eadbc..430da12 100644 (file)
@@ -235,7 +235,7 @@ void __init bcmring_init_timer(void)
         */
        bcmring_clocksource_init();
 
-       sp804_clockevents_register(TIMER0_VA_BASE, IRQ_TIMER0, "timer0");
+       sp804_clockevents_init(TIMER0_VA_BASE, IRQ_TIMER0, "timer0");
 }
 
 struct sys_timer bcmring_timer = {
index b52b8de..f4d4d6d 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/mm.h>
 #include <linux/pfn.h>
 #include <linux/atomic.h>
+#include <linux/sched.h>
 #include <mach/dma.h>
 
 /* I don't quite understand why dc4 fails when this is set to 1 and DMA is enabled */
index 22d8588..cfede57 100644 (file)
@@ -1,22 +1,26 @@
-zreladdr-$(CONFIG_ARCH_MX1)    += 0x08008000
-params_phys-$(CONFIG_ARCH_MX1) := 0x08000100
-initrd_phys-$(CONFIG_ARCH_MX1) := 0x08800000
+zreladdr-$(CONFIG_SOC_IMX1)    += 0x08008000
+params_phys-$(CONFIG_SOC_IMX1) := 0x08000100
+initrd_phys-$(CONFIG_SOC_IMX1) := 0x08800000
 
-zreladdr-$(CONFIG_MACH_MX21)   += 0xC0008000
-params_phys-$(CONFIG_MACH_MX21)        := 0xC0000100
-initrd_phys-$(CONFIG_MACH_MX21)        := 0xC0800000
+zreladdr-$(CONFIG_SOC_IMX21)   += 0xC0008000
+params_phys-$(CONFIG_SOC_IMX21)        := 0xC0000100
+initrd_phys-$(CONFIG_SOC_IMX21)        := 0xC0800000
 
-zreladdr-$(CONFIG_ARCH_MX25)   += 0x80008000
-params_phys-$(CONFIG_ARCH_MX25)        := 0x80000100
-initrd_phys-$(CONFIG_ARCH_MX25)        := 0x80800000
+zreladdr-$(CONFIG_SOC_IMX25)   += 0x80008000
+params_phys-$(CONFIG_SOC_IMX25)        := 0x80000100
+initrd_phys-$(CONFIG_SOC_IMX25)        := 0x80800000
 
-zreladdr-$(CONFIG_MACH_MX27)   += 0xA0008000
-params_phys-$(CONFIG_MACH_MX27)        := 0xA0000100
-initrd_phys-$(CONFIG_MACH_MX27)        := 0xA0800000
+zreladdr-$(CONFIG_SOC_IMX27)   += 0xA0008000
+params_phys-$(CONFIG_SOC_IMX27)        := 0xA0000100
+initrd_phys-$(CONFIG_SOC_IMX27)        := 0xA0800000
 
-zreladdr-$(CONFIG_ARCH_MX3)    += 0x80008000
-params_phys-$(CONFIG_ARCH_MX3) := 0x80000100
-initrd_phys-$(CONFIG_ARCH_MX3) := 0x80800000
+zreladdr-$(CONFIG_SOC_IMX31)   += 0x80008000
+params_phys-$(CONFIG_SOC_IMX31)        := 0x80000100
+initrd_phys-$(CONFIG_SOC_IMX31)        := 0x80800000
+
+zreladdr-$(CONFIG_SOC_IMX35)   += 0x80008000
+params_phys-$(CONFIG_SOC_IMX35)        := 0x80000100
+initrd_phys-$(CONFIG_SOC_IMX35)        := 0x80800000
 
 zreladdr-$(CONFIG_SOC_IMX6Q)   += 0x10008000
 params_phys-$(CONFIG_SOC_IMX6Q)        := 0x10000100
index e0b926d..613a1b9 100644 (file)
@@ -1139,7 +1139,7 @@ static int _clk_set_rate(struct clk *clk, unsigned long rate)
                return -EINVAL;
 
        max_div = ((d->bm_pred >> d->bp_pred) + 1) *
-                 ((d->bm_pred >> d->bp_pred) + 1);
+                 ((d->bm_podf >> d->bp_podf) + 1);
 
        div = parent_rate / rate;
        if (div == 0)
@@ -2002,6 +2002,21 @@ int __init mx6q_clocks_init(void)
        clk_set_rate(&asrc_serial_clk, 1500000);
        clk_set_rate(&enfc_clk, 11000000);
 
+       /*
+        * Before pinctrl API is available, we have to rely on the pad
+        * configuration set up by bootloader.  For usdhc example here,
+        * u-boot sets up the pads for 49.5 MHz case, and we have to lower
+        * the usdhc clock from 198 to 49.5 MHz to match the pad configuration.
+        *
+        * FIXME: This is should be removed after pinctrl API is available.
+        * At that time, usdhc driver can call pinctrl API to change pad
+        * configuration dynamically per different usdhc clock settings.
+        */
+       clk_set_rate(&usdhc1_clk, 49500000);
+       clk_set_rate(&usdhc2_clk, 49500000);
+       clk_set_rate(&usdhc3_clk, 49500000);
+       clk_set_rate(&usdhc4_clk, 49500000);
+
        np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpt");
        base = of_iomap(np, 0);
        WARN_ON(!base);
index 4285dfd..4ad3969 100644 (file)
@@ -15,6 +15,8 @@ obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o
 obj-$(CONFIG_MSM_SMD) += last_radio_log.o
 obj-$(CONFIG_MSM_SCM) += scm.o scm-boot.o
 
+CFLAGS_scm.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1)
+
 obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
 obj-$(CONFIG_SMP) += headsmp.o platsmp.o
 
index 71de506..db81ed5 100644 (file)
@@ -42,8 +42,8 @@
 
 extern struct sys_timer msm_timer;
 
-static void __init msm7x30_fixup(struct machine_desc *desc, struct tag *tag,
-                        char **cmdline, struct meminfo *mi)
+static void __init msm7x30_fixup(struct tag *tag, char **cmdline,
+               struct meminfo *mi)
 {
        for (; tag->hdr.size; tag = tag_next(tag))
                if (tag->hdr.tag == ATAG_MEM && tag->u.mem.start == 0x200000) {
index b04468e..6dc1cbd 100644 (file)
@@ -32,8 +32,8 @@
 
 #include "devices.h"
 
-static void __init msm8960_fixup(struct machine_desc *desc, struct tag *tag,
-                        char **cmdline, struct meminfo *mi)
+static void __init msm8960_fixup(struct tag *tag, char **cmdline,
+               struct meminfo *mi)
 {
        for (; tag->hdr.size; tag = tag_next(tag))
                if (tag->hdr.tag == ATAG_MEM &&
index cf38e22..44bf716 100644 (file)
@@ -28,8 +28,8 @@
 #include <mach/board.h>
 #include <mach/msm_iomap.h>
 
-static void __init msm8x60_fixup(struct machine_desc *desc, struct tag *tag,
-                        char **cmdline, struct meminfo *mi)
+static void __init msm8x60_fixup(struct tag *tag, char **cmdline,
+               struct meminfo *mi)
 {
        for (; tag->hdr.size; tag = tag_next(tag))
                if (tag->hdr.tag == ATAG_MEM &&
index 232f97a..bafabb5 100644 (file)
@@ -180,6 +180,9 @@ static u32 smc(u32 cmd_addr)
                        __asmeq("%1", "r0")
                        __asmeq("%2", "r1")
                        __asmeq("%3", "r2")
+#ifdef REQUIRES_SEC
+                       ".arch_extension sec\n"
+#endif
                        "smc    #0      @ switch to secure world\n"
                        : "=r" (r0)
                        : "r" (r0), "r" (r1), "r" (r2)
index 2aacf41..4cb2769 100644 (file)
@@ -1281,9 +1281,9 @@ DEFINE_CLOCK(gpt_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG9_OFFSET,
        NULL,  NULL, &ipg_clk, &gpt_ipg_clk);
 
 DEFINE_CLOCK(pwm1_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG6_OFFSET,
-       NULL, NULL, &ipg_clk, NULL);
+       NULL, NULL, &ipg_perclk, NULL);
 DEFINE_CLOCK(pwm2_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG8_OFFSET,
-       NULL, NULL, &ipg_clk, NULL);
+       NULL, NULL, &ipg_perclk, NULL);
 
 /* I2C */
 DEFINE_CLOCK(i2c1_clk, 0, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG9_OFFSET,
@@ -1634,6 +1634,7 @@ int __init mx53_clocks_init(unsigned long ckil, unsigned long osc,
        return 0;
 }
 
+#ifdef CONFIG_OF
 static void __init clk_get_freq_dt(unsigned long *ckil, unsigned long *osc,
                                   unsigned long *ckih1, unsigned long *ckih2)
 {
@@ -1671,3 +1672,4 @@ int __init mx53_clocks_init_dt(void)
        clk_get_freq_dt(&ckil, &osc, &ckih1, &ckih2);
        return mx53_clocks_init(ckil, osc, ckih1, ckih2);
 }
+#endif
index ac2316d..064ec5a 100644 (file)
@@ -471,7 +471,8 @@ static void __init mx28evk_init(void)
                               "mmc0-slot-power");
        if (ret)
                pr_warn("failed to request gpio mmc0-slot-power: %d\n", ret);
-       mx28_add_mxs_mmc(0, &mx28evk_mmc_pdata[0]);
+       else
+               mx28_add_mxs_mmc(0, &mx28evk_mmc_pdata[0]);
 
        ret = gpio_request_one(MX28EVK_MMC1_SLOT_POWER, GPIOF_OUT_INIT_LOW,
                               "mmc1-slot-power");
@@ -480,7 +481,6 @@ static void __init mx28evk_init(void)
        else
                mx28_add_mxs_mmc(1, &mx28evk_mmc_pdata[1]);
 
-       mx28_add_mxs_mmc(1, &mx28evk_mmc_pdata[1]);
        mx28_add_rtc_stmp3xxx();
 
        gpio_led_register_device(0, &mx28evk_led_data);
index 8f2c234..58d4ee3 100644 (file)
@@ -14,7 +14,7 @@
 
 #define UART_SHIFT 2
 
-               .macro  addruart, rp, rv
+               .macro  addruart, rp, rv, tmp
                ldr     \rv, =PHYS_TO_IO(PICOXCELL_UART1_BASE)
                ldr     \rp, =PICOXCELL_UART1_BASE
                .endm
index 2aec2f7..737bdc6 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 # Common objects
-obj-y                          := timer.o console.o clock.o pm_runtime.o
+obj-y                          := timer.o console.o clock.o
 
 # CPU objects
 obj-$(CONFIG_ARCH_SH7367)      += setup-sh7367.o clock-sh7367.o intc-sh7367.o
index 83624e2..b862e9f 100644 (file)
@@ -515,14 +515,14 @@ static void __init ag5evm_init(void)
        /* enable MMCIF */
        gpio_request(GPIO_FN_MMCCLK0, NULL);
        gpio_request(GPIO_FN_MMCCMD0_PU, NULL);
-       gpio_request(GPIO_FN_MMCD0_0, NULL);
-       gpio_request(GPIO_FN_MMCD0_1, NULL);
-       gpio_request(GPIO_FN_MMCD0_2, NULL);
-       gpio_request(GPIO_FN_MMCD0_3, NULL);
-       gpio_request(GPIO_FN_MMCD0_4, NULL);
-       gpio_request(GPIO_FN_MMCD0_5, NULL);
-       gpio_request(GPIO_FN_MMCD0_6, NULL);
-       gpio_request(GPIO_FN_MMCD0_7, NULL);
+       gpio_request(GPIO_FN_MMCD0_0_PU, NULL);
+       gpio_request(GPIO_FN_MMCD0_1_PU, NULL);
+       gpio_request(GPIO_FN_MMCD0_2_PU, NULL);
+       gpio_request(GPIO_FN_MMCD0_3_PU, NULL);
+       gpio_request(GPIO_FN_MMCD0_4_PU, NULL);
+       gpio_request(GPIO_FN_MMCD0_5_PU, NULL);
+       gpio_request(GPIO_FN_MMCD0_6_PU, NULL);
+       gpio_request(GPIO_FN_MMCD0_7_PU, NULL);
        gpio_request(GPIO_PORT208, NULL); /* Reset */
        gpio_direction_output(GPIO_PORT208, 1);
 
index a3aa0f6..4c865ec 100644 (file)
@@ -201,7 +201,7 @@ static struct physmap_flash_data nor_flash_data = {
 static struct resource nor_flash_resources[] = {
        [0]     = {
                .start  = 0x20000000, /* CS0 shadow instead of regular CS0 */
-               .end    = 0x28000000 - 1, /* needed by USB MASK ROM boot */             
+               .end    = 0x28000000 - 1, /* needed by USB MASK ROM boot */
                .flags  = IORESOURCE_MEM,
        }
 };
index adc7312..bd9a784 100644 (file)
@@ -48,6 +48,7 @@
 #include <asm/hardware/cache-l2x0.h>
 #include <asm/traps.h>
 
+/* SMSC 9220 */
 static struct resource smsc9220_resources[] = {
        [0] = {
                .start          = 0x14000000, /* CS5A */
@@ -77,6 +78,7 @@ static struct platform_device eth_device = {
        .num_resources  = ARRAY_SIZE(smsc9220_resources),
 };
 
+/* KEYSC */
 static struct sh_keysc_info keysc_platdata = {
        .mode           = SH_KEYSC_MODE_6,
        .scan_timing    = 3,
@@ -120,6 +122,7 @@ static struct platform_device keysc_device = {
        },
 };
 
+/* GPIO KEY */
 #define GPIO_KEY(c, g, d) { .code = c, .gpio = g, .desc = d, .active_low = 1 }
 
 static struct gpio_keys_button gpio_buttons[] = {
@@ -150,6 +153,7 @@ static struct platform_device gpio_keys_device = {
        },
 };
 
+/* GPIO LED */
 #define GPIO_LED(n, g) { .name = n, .gpio = g }
 
 static struct gpio_led gpio_leds[] = {
@@ -175,6 +179,7 @@ static struct platform_device gpio_leds_device = {
        },
 };
 
+/* MMCIF */
 static struct resource mmcif_resources[] = {
        [0] = {
                .name   = "MMCIF",
@@ -207,6 +212,7 @@ static struct platform_device mmcif_device = {
        .resource       = mmcif_resources,
 };
 
+/* SDHI0 */
 static struct sh_mobile_sdhi_info sdhi0_info = {
        .tmio_caps      = MMC_CAP_SD_HIGHSPEED,
        .tmio_flags     = TMIO_MMC_WRPROTECT_DISABLE | TMIO_MMC_HAS_IDLE_WAIT,
@@ -243,6 +249,7 @@ static struct platform_device sdhi0_device = {
        },
 };
 
+/* SDHI1 */
 static struct sh_mobile_sdhi_info sdhi1_info = {
        .tmio_caps      = MMC_CAP_NONREMOVABLE | MMC_CAP_SDIO_IRQ,
        .tmio_flags     = TMIO_MMC_WRPROTECT_DISABLE | TMIO_MMC_HAS_IDLE_WAIT,
index 6697592..995a9c3 100644 (file)
@@ -476,7 +476,7 @@ static struct clk_ops fsidiv_clk_ops = {
        .disable        = fsidiv_disable,
 };
 
-static struct clk_mapping sh7372_fsidiva_clk_mapping = {
+static struct clk_mapping fsidiva_clk_mapping = {
        .phys   = FSIDIVA,
        .len    = 8,
 };
@@ -484,10 +484,10 @@ static struct clk_mapping sh7372_fsidiva_clk_mapping = {
 struct clk sh7372_fsidiva_clk = {
        .ops            = &fsidiv_clk_ops,
        .parent         = &div6_reparent_clks[DIV6_FSIA], /* late install */
-       .mapping        = &sh7372_fsidiva_clk_mapping,
+       .mapping        = &fsidiva_clk_mapping,
 };
 
-static struct clk_mapping sh7372_fsidivb_clk_mapping = {
+static struct clk_mapping fsidivb_clk_mapping = {
        .phys   = FSIDIVB,
        .len    = 8,
 };
@@ -495,7 +495,7 @@ static struct clk_mapping sh7372_fsidivb_clk_mapping = {
 struct clk sh7372_fsidivb_clk = {
        .ops            = &fsidiv_clk_ops,
        .parent         = &div6_reparent_clks[DIV6_FSIB],  /* late install */
-       .mapping        = &sh7372_fsidivb_clk_mapping,
+       .mapping        = &fsidivb_clk_mapping,
 };
 
 static struct clk *late_main_clks[] = {
index 2e44f11..1b23342 100644 (file)
@@ -26,65 +26,59 @@ void (*shmobile_cpuidle_modes[CPUIDLE_STATE_MAX])(void) = {
 };
 
 static int shmobile_cpuidle_enter(struct cpuidle_device *dev,
-                                 struct cpuidle_state *state)
+                                 struct cpuidle_driver *drv,
+                                 int index)
 {
        ktime_t before, after;
-       int requested_state = state - &dev->states[0];
 
-       dev->last_state = &dev->states[requested_state];
        before = ktime_get();
 
        local_irq_disable();
        local_fiq_disable();
 
-       shmobile_cpuidle_modes[requested_state]();
+       shmobile_cpuidle_modes[index]();
 
        local_irq_enable();
        local_fiq_enable();
 
        after = ktime_get();
-       return ktime_to_ns(ktime_sub(after, before)) >> 10;
+       dev->last_residency = ktime_to_ns(ktime_sub(after, before)) >> 10;
+
+       return index;
 }
 
 static struct cpuidle_device shmobile_cpuidle_dev;
 static struct cpuidle_driver shmobile_cpuidle_driver = {
        .name =         "shmobile_cpuidle",
        .owner =        THIS_MODULE,
+       .states[0] = {
+               .name = "C1",
+               .desc = "WFI",
+               .exit_latency = 1,
+               .target_residency = 1 * 2,
+               .flags = CPUIDLE_FLAG_TIME_VALID,
+       },
+       .safe_state_index = 0, /* C1 */
+       .state_count = 1,
 };
 
-void (*shmobile_cpuidle_setup)(struct cpuidle_device *dev);
+void (*shmobile_cpuidle_setup)(struct cpuidle_driver *drv);
 
 static int shmobile_cpuidle_init(void)
 {
        struct cpuidle_device *dev = &shmobile_cpuidle_dev;
-       struct cpuidle_state *state;
+       struct cpuidle_driver *drv = &shmobile_cpuidle_driver;
        int i;
 
-       cpuidle_register_driver(&shmobile_cpuidle_driver);
-
-       for (i = 0; i < CPUIDLE_STATE_MAX; i++) {
-               dev->states[i].name[0] = '\0';
-               dev->states[i].desc[0] = '\0';
-               dev->states[i].enter = shmobile_cpuidle_enter;
-       }
-
-       i = CPUIDLE_DRIVER_STATE_START;
-
-       state = &dev->states[i++];
-       snprintf(state->name, CPUIDLE_NAME_LEN, "C1");
-       strncpy(state->desc, "WFI", CPUIDLE_DESC_LEN);
-       state->exit_latency = 1;
-       state->target_residency = 1 * 2;
-       state->power_usage = 3;
-       state->flags = 0;
-       state->flags |= CPUIDLE_FLAG_TIME_VALID;
-
-       dev->safe_state = state;
-       dev->state_count = i;
+       for (i = 0; i < CPUIDLE_STATE_MAX; i++)
+               drv->states[i].enter = shmobile_cpuidle_enter;
 
        if (shmobile_cpuidle_setup)
-               shmobile_cpuidle_setup(dev);
+               shmobile_cpuidle_setup(drv);
+
+       cpuidle_register_driver(drv);
 
+       dev->state_count = drv->state_count;
        cpuidle_register_device(dev);
 
        return 0;
index c0cdbf9..834bd6c 100644 (file)
@@ -9,9 +9,9 @@ extern int clk_init(void);
 extern void shmobile_handle_irq_intc(struct pt_regs *);
 extern void shmobile_handle_irq_gic(struct pt_regs *);
 extern struct platform_suspend_ops shmobile_suspend_ops;
-struct cpuidle_device;
+struct cpuidle_driver;
 extern void (*shmobile_cpuidle_modes[])(void);
-extern void (*shmobile_cpuidle_setup)(struct cpuidle_device *dev);
+extern void (*shmobile_cpuidle_setup)(struct cpuidle_driver *drv);
 
 extern void sh7367_init_irq(void);
 extern void sh7367_add_early_devices(void);
index 18ae6a9..881d515 100644 (file)
@@ -470,6 +470,14 @@ enum {
        GPIO_FN_SDHICMD2_PU,
        GPIO_FN_MMCCMD0_PU,
        GPIO_FN_MMCCMD1_PU,
+       GPIO_FN_MMCD0_0_PU,
+       GPIO_FN_MMCD0_1_PU,
+       GPIO_FN_MMCD0_2_PU,
+       GPIO_FN_MMCD0_3_PU,
+       GPIO_FN_MMCD0_4_PU,
+       GPIO_FN_MMCD0_5_PU,
+       GPIO_FN_MMCD0_6_PU,
+       GPIO_FN_MMCD0_7_PU,
        GPIO_FN_FSIACK_PU,
        GPIO_FN_FSIAILR_PU,
        GPIO_FN_FSIAIBT_PU,
index 128555e..e6e5246 100644 (file)
 #include <linux/gpio.h>
 #include <mach/sh7367.h>
 
-#define _1(fn, pfx, sfx) fn(pfx, sfx)
-
-#define _10(fn, pfx, sfx)                              \
-       _1(fn, pfx##0, sfx), _1(fn, pfx##1, sfx),       \
-       _1(fn, pfx##2, sfx), _1(fn, pfx##3, sfx),       \
-       _1(fn, pfx##4, sfx), _1(fn, pfx##5, sfx),       \
-       _1(fn, pfx##6, sfx), _1(fn, pfx##7, sfx),       \
-       _1(fn, pfx##8, sfx), _1(fn, pfx##9, sfx)
-
-#define _90(fn, pfx, sfx)                              \
-       _10(fn, pfx##1, sfx), _10(fn, pfx##2, sfx),     \
-       _10(fn, pfx##3, sfx), _10(fn, pfx##4, sfx),     \
-       _10(fn, pfx##5, sfx), _10(fn, pfx##6, sfx),     \
-       _10(fn, pfx##7, sfx), _10(fn, pfx##8, sfx),     \
-       _10(fn, pfx##9, sfx)
-
-#define _273(fn, pfx, sfx)             \
-       _10(fn, pfx, sfx), _90(fn, pfx, sfx),           \
-       _10(fn, pfx##10, sfx), _90(fn, pfx##1, sfx),    \
-       _10(fn, pfx##20, sfx), _10(fn, pfx##21, sfx),   \
-       _10(fn, pfx##22, sfx), _10(fn, pfx##23, sfx),   \
-       _10(fn, pfx##24, sfx), _10(fn, pfx##25, sfx),   \
-       _10(fn, pfx##26, sfx), _1(fn, pfx##270, sfx),   \
-       _1(fn, pfx##271, sfx), _1(fn, pfx##272, sfx)
-
-#define _PORT(pfx, sfx) pfx##_##sfx
-#define PORT_273(str) _273(_PORT, PORT, str)
+#define CPU_ALL_PORT(fn, pfx, sfx)                             \
+       PORT_10(fn, pfx, sfx), PORT_90(fn, pfx, sfx),           \
+       PORT_10(fn, pfx##10, sfx), PORT_90(fn, pfx##1, sfx),    \
+       PORT_10(fn, pfx##20, sfx), PORT_10(fn, pfx##21, sfx),   \
+       PORT_10(fn, pfx##22, sfx), PORT_10(fn, pfx##23, sfx),   \
+       PORT_10(fn, pfx##24, sfx), PORT_10(fn, pfx##25, sfx),   \
+       PORT_10(fn, pfx##26, sfx), PORT_1(fn, pfx##270, sfx),   \
+       PORT_1(fn, pfx##271, sfx), PORT_1(fn, pfx##272, sfx)
 
 enum {
        PINMUX_RESERVED = 0,
 
        PINMUX_DATA_BEGIN,
-       PORT_273(DATA), /* PORT0_DATA -> PORT272_DATA */
+       PORT_ALL(DATA), /* PORT0_DATA -> PORT272_DATA */
        PINMUX_DATA_END,
 
        PINMUX_INPUT_BEGIN,
-       PORT_273(IN), /* PORT0_IN -> PORT272_IN */
+       PORT_ALL(IN), /* PORT0_IN -> PORT272_IN */
        PINMUX_INPUT_END,
 
        PINMUX_INPUT_PULLUP_BEGIN,
-       PORT_273(IN_PU), /* PORT0_IN_PU -> PORT272_IN_PU */
+       PORT_ALL(IN_PU), /* PORT0_IN_PU -> PORT272_IN_PU */
        PINMUX_INPUT_PULLUP_END,
 
        PINMUX_INPUT_PULLDOWN_BEGIN,
-       PORT_273(IN_PD), /* PORT0_IN_PD -> PORT272_IN_PD */
+       PORT_ALL(IN_PD), /* PORT0_IN_PD -> PORT272_IN_PD */
        PINMUX_INPUT_PULLDOWN_END,
 
        PINMUX_OUTPUT_BEGIN,
-       PORT_273(OUT), /* PORT0_OUT -> PORT272_OUT */
+       PORT_ALL(OUT), /* PORT0_OUT -> PORT272_OUT */
        PINMUX_OUTPUT_END,
 
        PINMUX_FUNCTION_BEGIN,
-       PORT_273(FN_IN), /* PORT0_FN_IN -> PORT272_FN_IN */
-       PORT_273(FN_OUT), /* PORT0_FN_OUT -> PORT272_FN_OUT */
-       PORT_273(FN0), /* PORT0_FN0 -> PORT272_FN0 */
-       PORT_273(FN1), /* PORT0_FN1 -> PORT272_FN1 */
-       PORT_273(FN2), /* PORT0_FN2 -> PORT272_FN2 */
-       PORT_273(FN3), /* PORT0_FN3 -> PORT272_FN3 */
-       PORT_273(FN4), /* PORT0_FN4 -> PORT272_FN4 */
-       PORT_273(FN5), /* PORT0_FN5 -> PORT272_FN5 */
-       PORT_273(FN6), /* PORT0_FN6 -> PORT272_FN6 */
-       PORT_273(FN7), /* PORT0_FN7 -> PORT272_FN7 */
+       PORT_ALL(FN_IN), /* PORT0_FN_IN -> PORT272_FN_IN */
+       PORT_ALL(FN_OUT), /* PORT0_FN_OUT -> PORT272_FN_OUT */
+       PORT_ALL(FN0), /* PORT0_FN0 -> PORT272_FN0 */
+       PORT_ALL(FN1), /* PORT0_FN1 -> PORT272_FN1 */
+       PORT_ALL(FN2), /* PORT0_FN2 -> PORT272_FN2 */
+       PORT_ALL(FN3), /* PORT0_FN3 -> PORT272_FN3 */
+       PORT_ALL(FN4), /* PORT0_FN4 -> PORT272_FN4 */
+       PORT_ALL(FN5), /* PORT0_FN5 -> PORT272_FN5 */
+       PORT_ALL(FN6), /* PORT0_FN6 -> PORT272_FN6 */
+       PORT_ALL(FN7), /* PORT0_FN7 -> PORT272_FN7 */
 
        MSELBCR_MSEL2_1, MSELBCR_MSEL2_0,
        PINMUX_FUNCTION_END,
@@ -327,41 +308,6 @@ enum {
        PINMUX_MARK_END,
 };
 
-#define PORT_DATA_I(nr) \
-       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0, PORT##nr##_IN)
-
-#define PORT_DATA_I_PD(nr) \
-       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0, \
-                   PORT##nr##_IN, PORT##nr##_IN_PD)
-
-#define PORT_DATA_I_PU(nr) \
-       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0, \
-                   PORT##nr##_IN, PORT##nr##_IN_PU)
-
-#define PORT_DATA_I_PU_PD(nr) \
-       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0, \
-                   PORT##nr##_IN, PORT##nr##_IN_PD, PORT##nr##_IN_PU)
-
-#define PORT_DATA_O(nr) \
-       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0, PORT##nr##_OUT)
-
-#define PORT_DATA_IO(nr) \
-       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0, PORT##nr##_OUT, \
-                   PORT##nr##_IN)
-
-#define PORT_DATA_IO_PD(nr) \
-       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0, PORT##nr##_OUT, \
-                   PORT##nr##_IN, PORT##nr##_IN_PD)
-
-#define PORT_DATA_IO_PU(nr) \
-       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0, PORT##nr##_OUT, \
-                   PORT##nr##_IN, PORT##nr##_IN_PU)
-
-#define PORT_DATA_IO_PU_PD(nr) \
-       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0, PORT##nr##_OUT, \
-                   PORT##nr##_IN, PORT##nr##_IN_PD, PORT##nr##_IN_PU)
-
-
 static pinmux_enum_t pinmux_data[] = {
 
        /* specify valid pin states for each pin in GPIO mode */
@@ -1098,13 +1044,9 @@ static pinmux_enum_t pinmux_data[] = {
        PINMUX_DATA(DIVLOCK_MARK, PORT272_FN1),
 };
 
-#define _GPIO_PORT(pfx, sfx) PINMUX_GPIO(GPIO_PORT##pfx, PORT##pfx##_DATA)
-#define GPIO_PORT_273() _273(_GPIO_PORT, , unused)
-#define GPIO_FN(str) PINMUX_GPIO(GPIO_FN_##str, str##_MARK)
-
 static struct pinmux_gpio pinmux_gpios[] = {
        /* 49-1 -> 49-6 (GPIO) */
-       GPIO_PORT_273(),
+       GPIO_PORT_ALL(),
 
        /* Special Pull-up / Pull-down Functions */
        GPIO_FN(PORT48_KEYIN0_PU), GPIO_FN(PORT49_KEYIN1_PU),
@@ -1345,22 +1287,6 @@ static struct pinmux_gpio pinmux_gpios[] = {
        GPIO_FN(DIVLOCK),
 };
 
-/* helper for top 4 bits in PORTnCR */
-#define PCRH(in, in_pd, in_pu, out)            \
-       0, (out), (in), 0,                      \
-       0, 0, 0, 0,                             \
-       0, 0, (in_pd), 0,                       \
-       0, 0, (in_pu), 0
-
-#define PORTCR(nr, reg)                                                \
-       { PINMUX_CFG_REG("PORT" nr "CR", reg, 8, 4) {           \
-               PCRH(PORT##nr##_IN, PORT##nr##_IN_PD,           \
-                    PORT##nr##_IN_PU, PORT##nr##_OUT),         \
-               PORT##nr##_FN0, PORT##nr##_FN1, PORT##nr##_FN2, \
-               PORT##nr##_FN3, PORT##nr##_FN4, PORT##nr##_FN5, \
-               PORT##nr##_FN6, PORT##nr##_FN7 }                \
-       }
-
 static struct pinmux_cfg_reg pinmux_config_regs[] = {
        PORTCR(0, 0xe6050000), /* PORT0CR */
        PORTCR(1, 0xe6050001), /* PORT1CR */
index 9c265da..1bd6585 100644 (file)
 #include <linux/gpio.h>
 #include <mach/sh7372.h>
 
-#define _1(fn, pfx, sfx) fn(pfx, sfx)
-
-#define _10(fn, pfx, sfx)                              \
-       _1(fn, pfx##0, sfx), _1(fn, pfx##1, sfx),       \
-       _1(fn, pfx##2, sfx), _1(fn, pfx##3, sfx),       \
-       _1(fn, pfx##4, sfx), _1(fn, pfx##5, sfx),       \
-       _1(fn, pfx##6, sfx), _1(fn, pfx##7, sfx),       \
-       _1(fn, pfx##8, sfx), _1(fn, pfx##9, sfx)
-
-#define _80(fn, pfx, sfx)                              \
-       _10(fn, pfx##1, sfx),   _10(fn, pfx##2, sfx),   \
-       _10(fn, pfx##3, sfx),   _10(fn, pfx##4, sfx),   \
-       _10(fn, pfx##5, sfx),   _10(fn, pfx##6, sfx),   \
-       _10(fn, pfx##7, sfx),   _10(fn, pfx##8, sfx)
-
-#define _190(fn, pfx, sfx) \
-       _10(fn, pfx, sfx), _80(fn, pfx, sfx), _10(fn, pfx##9, sfx), \
-       _10(fn, pfx##10, sfx), _80(fn, pfx##1, sfx), _1(fn, pfx##190, sfx)
-
-#define _PORT(pfx, sfx) pfx##_##sfx
-#define PORT_ALL(str) _190(_PORT, PORT, str)
+#define CPU_ALL_PORT(fn, pfx, sfx) \
+       PORT_10(fn, pfx, sfx),          PORT_90(fn, pfx, sfx), \
+       PORT_10(fn, pfx##10, sfx),      PORT_10(fn, pfx##11, sfx), \
+       PORT_10(fn, pfx##12, sfx),      PORT_10(fn, pfx##13, sfx), \
+       PORT_10(fn, pfx##14, sfx),      PORT_10(fn, pfx##15, sfx), \
+       PORT_10(fn, pfx##16, sfx),      PORT_10(fn, pfx##17, sfx), \
+       PORT_10(fn, pfx##18, sfx),      PORT_1(fn, pfx##190, sfx)
 
 enum {
        PINMUX_RESERVED = 0,
@@ -381,108 +367,124 @@ enum {
        PINMUX_MARK_END,
 };
 
-/* PORT_DATA_I_PD(nr) */
-#define _I___D(nr)                          \
-       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0, \
-                   PORT##nr##_IN, PORT##nr##_IN_PD)
-
-/* PORT_DATA_I_PU(nr) */
-#define _I__U_(nr)                          \
-       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0, \
-                   PORT##nr##_IN, PORT##nr##_IN_PU)
-
-/* PORT_DATA_I_PU_PD(nr) */
-#define _I__UD(nr)                          \
-       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0, \
-                   PORT##nr##_IN, PORT##nr##_IN_PD, PORT##nr##_IN_PU)
-
-/* PORT_DATA_O(nr) */
-#define __O___(nr)                                                     \
-       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0, PORT##nr##_OUT)
-
-/* PORT_DATA_IO(nr) */
-#define _IO___(nr)                                  \
-       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0, PORT##nr##_OUT, \
-                   PORT##nr##_IN)
-
-/* PORT_DATA_IO_PD(nr) */
-#define _IO__D(nr)                                          \
-       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0, PORT##nr##_OUT, \
-                   PORT##nr##_IN, PORT##nr##_IN_PD)
-
-/* PORT_DATA_IO_PU(nr) */
-#define _IO_U_(nr)                                          \
-       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0, PORT##nr##_OUT, \
-                   PORT##nr##_IN, PORT##nr##_IN_PU)
-
-/* PORT_DATA_IO_PU_PD(nr) */
-#define _IO_UD(nr)                                          \
-       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0, PORT##nr##_OUT, \
-                   PORT##nr##_IN, PORT##nr##_IN_PD, PORT##nr##_IN_PU)
-
-
 static pinmux_enum_t pinmux_data[] = {
 
        /* specify valid pin states for each pin in GPIO mode */
-
-       _IO__D(0), _IO__D(1), __O___(2), _I___D(3), _I___D(4),
-       _I___D(5), _IO_UD(6), _I___D(7), _IO__D(8), __O___(9),
-
-       __O___(10), __O___(11), _IO_UD(12), _IO__D(13), _IO__D(14),
-       __O___(15), _IO__D(16), _IO__D(17), _I___D(18), _IO___(19),
-
-       _IO___(20), _IO___(21), _IO___(22), _IO___(23), _IO___(24),
-       _IO___(25), _IO___(26), _IO___(27), _IO___(28), _IO___(29),
-
-       _IO___(30), _IO___(31), _IO___(32), _IO___(33), _IO___(34),
-       _IO___(35), _IO___(36), _IO___(37), _IO___(38), _IO___(39),
-
-       _IO___(40), _IO___(41), _IO___(42), _IO___(43), _IO___(44),
-       _IO___(45), _IO_U_(46), _IO_U_(47), _IO_U_(48), _IO_U_(49),
-
-       _IO_U_(50), _IO_U_(51), _IO_U_(52), _IO_U_(53), _IO_U_(54),
-       _IO_U_(55), _IO_U_(56), _IO_U_(57), _IO_U_(58), _IO_U_(59),
-
-       _IO_U_(60), _IO_U_(61), _IO___(62), __O___(63), __O___(64),
-       _IO_U_(65), __O___(66), _IO_U_(67), __O___(68), _IO___(69), /*66?*/
-
-       _IO___(70), _IO___(71), __O___(72), _I__U_(73), _I__UD(74),
-       _IO_UD(75), _IO_UD(76), _IO_UD(77), _IO_UD(78), _IO_UD(79),
-
-       _IO_UD(80), _IO_UD(81), _IO_UD(82), _IO_UD(83), _IO_UD(84),
-       _IO_UD(85), _IO_UD(86), _IO_UD(87), _IO_UD(88), _IO_UD(89),
-
-       _IO_UD(90), _IO_UD(91), _IO_UD(92), _IO_UD(93), _IO_UD(94),
-       _IO_UD(95), _IO_U_(96), _IO_UD(97), _IO_UD(98), __O___(99), /*99?*/
-
-       _IO__D(100), _IO__D(101), _IO__D(102), _IO__D(103), _IO__D(104),
-       _IO__D(105), _IO_U_(106), _IO_U_(107), _IO_U_(108), _IO_U_(109),
-
-       _IO_U_(110), _IO_U_(111), _IO__D(112), _IO__D(113), _IO_U_(114),
-       _IO_U_(115), _IO_U_(116), _IO_U_(117), _IO_U_(118), _IO_U_(119),
-
-       _IO_U_(120), _IO__D(121), _IO__D(122), _IO__D(123), _IO__D(124),
-       _IO__D(125), _IO__D(126), _IO__D(127), _IO__D(128), _IO_UD(129),
-
-       _IO_UD(130), _IO_UD(131), _IO_UD(132), _IO_UD(133), _IO_UD(134),
-       _IO_UD(135), _IO__D(136), _IO__D(137), _IO__D(138), _IO__D(139),
-
-       _IO__D(140), _IO__D(141), _IO__D(142), _IO_UD(143), _IO__D(144),
-       _IO__D(145), _IO__D(146), _IO__D(147), _IO__D(148), _IO__D(149),
-
-       _IO__D(150), _IO__D(151), _IO_UD(152), _I___D(153), _IO_UD(154),
-       _I___D(155), _IO__D(156), _IO__D(157), _I___D(158), _IO__D(159),
-
-       __O___(160), _IO__D(161), _IO__D(162), _IO__D(163), _I___D(164),
-       _IO__D(165), _I___D(166), _I___D(167), _I___D(168), _I___D(169),
-
-       _I___D(170), __O___(171), _IO_UD(172), _IO_UD(173), _IO_UD(174),
-       _IO_UD(175), _IO_UD(176), _IO_UD(177), _IO_UD(178), __O___(179),
-
-       _IO_UD(180), _IO_UD(181), _IO_UD(182), _IO_UD(183), _IO_UD(184),
-       __O___(185), _IO_UD(186), _IO_UD(187), _IO_UD(188), _IO_UD(189),
-
-       _IO_UD(190),
+       PORT_DATA_IO_PD(0),             PORT_DATA_IO_PD(1),
+       PORT_DATA_O(2),                 PORT_DATA_I_PD(3),
+       PORT_DATA_I_PD(4),              PORT_DATA_I_PD(5),
+       PORT_DATA_IO_PU_PD(6),          PORT_DATA_I_PD(7),
+       PORT_DATA_IO_PD(8),             PORT_DATA_O(9),
+
+       PORT_DATA_O(10),                PORT_DATA_O(11),
+       PORT_DATA_IO_PU_PD(12),         PORT_DATA_IO_PD(13),
+       PORT_DATA_IO_PD(14),            PORT_DATA_O(15),
+       PORT_DATA_IO_PD(16),            PORT_DATA_IO_PD(17),
+       PORT_DATA_I_PD(18),             PORT_DATA_IO(19),
+
+       PORT_DATA_IO(20),               PORT_DATA_IO(21),
+       PORT_DATA_IO(22),               PORT_DATA_IO(23),
+       PORT_DATA_IO(24),               PORT_DATA_IO(25),
+       PORT_DATA_IO(26),               PORT_DATA_IO(27),
+       PORT_DATA_IO(28),               PORT_DATA_IO(29),
+
+       PORT_DATA_IO(30),               PORT_DATA_IO(31),
+       PORT_DATA_IO(32),               PORT_DATA_IO(33),
+       PORT_DATA_IO(34),               PORT_DATA_IO(35),
+       PORT_DATA_IO(36),               PORT_DATA_IO(37),
+       PORT_DATA_IO(38),               PORT_DATA_IO(39),
+
+       PORT_DATA_IO(40),               PORT_DATA_IO(41),
+       PORT_DATA_IO(42),               PORT_DATA_IO(43),
+       PORT_DATA_IO(44),               PORT_DATA_IO(45),
+       PORT_DATA_IO_PU(46),            PORT_DATA_IO_PU(47),
+       PORT_DATA_IO_PU(48),            PORT_DATA_IO_PU(49),
+
+       PORT_DATA_IO_PU(50),            PORT_DATA_IO_PU(51),
+       PORT_DATA_IO_PU(52),            PORT_DATA_IO_PU(53),
+       PORT_DATA_IO_PU(54),            PORT_DATA_IO_PU(55),
+       PORT_DATA_IO_PU(56),            PORT_DATA_IO_PU(57),
+       PORT_DATA_IO_PU(58),            PORT_DATA_IO_PU(59),
+
+       PORT_DATA_IO_PU(60),            PORT_DATA_IO_PU(61),
+       PORT_DATA_IO(62),               PORT_DATA_O(63),
+       PORT_DATA_O(64),                PORT_DATA_IO_PU(65),
+       PORT_DATA_O(66),                PORT_DATA_IO_PU(67),  /*66?*/
+       PORT_DATA_O(68),                PORT_DATA_IO(69),
+
+       PORT_DATA_IO(70),               PORT_DATA_IO(71),
+       PORT_DATA_O(72),                PORT_DATA_I_PU(73),
+       PORT_DATA_I_PU_PD(74),          PORT_DATA_IO_PU_PD(75),
+       PORT_DATA_IO_PU_PD(76),         PORT_DATA_IO_PU_PD(77),
+       PORT_DATA_IO_PU_PD(78),         PORT_DATA_IO_PU_PD(79),
+
+       PORT_DATA_IO_PU_PD(80),         PORT_DATA_IO_PU_PD(81),
+       PORT_DATA_IO_PU_PD(82),         PORT_DATA_IO_PU_PD(83),
+       PORT_DATA_IO_PU_PD(84),         PORT_DATA_IO_PU_PD(85),
+       PORT_DATA_IO_PU_PD(86),         PORT_DATA_IO_PU_PD(87),
+       PORT_DATA_IO_PU_PD(88),         PORT_DATA_IO_PU_PD(89),
+
+       PORT_DATA_IO_PU_PD(90),         PORT_DATA_IO_PU_PD(91),
+       PORT_DATA_IO_PU_PD(92),         PORT_DATA_IO_PU_PD(93),
+       PORT_DATA_IO_PU_PD(94),         PORT_DATA_IO_PU_PD(95),
+       PORT_DATA_IO_PU(96),            PORT_DATA_IO_PU_PD(97),
+       PORT_DATA_IO_PU_PD(98),         PORT_DATA_O(99), /*99?*/
+
+       PORT_DATA_IO_PD(100),           PORT_DATA_IO_PD(101),
+       PORT_DATA_IO_PD(102),           PORT_DATA_IO_PD(103),
+       PORT_DATA_IO_PD(104),           PORT_DATA_IO_PD(105),
+       PORT_DATA_IO_PU(106),           PORT_DATA_IO_PU(107),
+       PORT_DATA_IO_PU(108),           PORT_DATA_IO_PU(109),
+
+       PORT_DATA_IO_PU(110),           PORT_DATA_IO_PU(111),
+       PORT_DATA_IO_PD(112),           PORT_DATA_IO_PD(113),
+       PORT_DATA_IO_PU(114),           PORT_DATA_IO_PU(115),
+       PORT_DATA_IO_PU(116),           PORT_DATA_IO_PU(117),
+       PORT_DATA_IO_PU(118),           PORT_DATA_IO_PU(119),
+
+       PORT_DATA_IO_PU(120),           PORT_DATA_IO_PD(121),
+       PORT_DATA_IO_PD(122),           PORT_DATA_IO_PD(123),
+       PORT_DATA_IO_PD(124),           PORT_DATA_IO_PD(125),
+       PORT_DATA_IO_PD(126),           PORT_DATA_IO_PD(127),
+       PORT_DATA_IO_PD(128),           PORT_DATA_IO_PU_PD(129),
+
+       PORT_DATA_IO_PU_PD(130),        PORT_DATA_IO_PU_PD(131),
+       PORT_DATA_IO_PU_PD(132),        PORT_DATA_IO_PU_PD(133),
+       PORT_DATA_IO_PU_PD(134),        PORT_DATA_IO_PU_PD(135),
+       PORT_DATA_IO_PD(136),           PORT_DATA_IO_PD(137),
+       PORT_DATA_IO_PD(138),           PORT_DATA_IO_PD(139),
+
+       PORT_DATA_IO_PD(140),           PORT_DATA_IO_PD(141),
+       PORT_DATA_IO_PD(142),           PORT_DATA_IO_PU_PD(143),
+       PORT_DATA_IO_PD(144),           PORT_DATA_IO_PD(145),
+       PORT_DATA_IO_PD(146),           PORT_DATA_IO_PD(147),
+       PORT_DATA_IO_PD(148),           PORT_DATA_IO_PD(149),
+
+       PORT_DATA_IO_PD(150),           PORT_DATA_IO_PD(151),
+       PORT_DATA_IO_PU_PD(152),        PORT_DATA_I_PD(153),
+       PORT_DATA_IO_PU_PD(154),        PORT_DATA_I_PD(155),
+       PORT_DATA_IO_PD(156),           PORT_DATA_IO_PD(157),
+       PORT_DATA_I_PD(158),            PORT_DATA_IO_PD(159),
+
+       PORT_DATA_O(160),               PORT_DATA_IO_PD(161),
+       PORT_DATA_IO_PD(162),           PORT_DATA_IO_PD(163),
+       PORT_DATA_I_PD(164),            PORT_DATA_IO_PD(165),
+       PORT_DATA_I_PD(166),            PORT_DATA_I_PD(167),
+       PORT_DATA_I_PD(168),            PORT_DATA_I_PD(169),
+
+       PORT_DATA_I_PD(170),            PORT_DATA_O(171),
+       PORT_DATA_IO_PU_PD(172),        PORT_DATA_IO_PU_PD(173),
+       PORT_DATA_IO_PU_PD(174),        PORT_DATA_IO_PU_PD(175),
+       PORT_DATA_IO_PU_PD(176),        PORT_DATA_IO_PU_PD(177),
+       PORT_DATA_IO_PU_PD(178),        PORT_DATA_O(179),
+
+       PORT_DATA_IO_PU_PD(180),        PORT_DATA_IO_PU_PD(181),
+       PORT_DATA_IO_PU_PD(182),        PORT_DATA_IO_PU_PD(183),
+       PORT_DATA_IO_PU_PD(184),        PORT_DATA_O(185),
+       PORT_DATA_IO_PU_PD(186),        PORT_DATA_IO_PU_PD(187),
+       PORT_DATA_IO_PU_PD(188),        PORT_DATA_IO_PU_PD(189),
+
+       PORT_DATA_IO_PU_PD(190),
 
        /* IRQ */
        PINMUX_DATA(IRQ0_6_MARK,        PORT6_FN0,      MSEL1CR_0_0),
@@ -926,10 +928,6 @@ static pinmux_enum_t pinmux_data[] = {
        PINMUX_DATA(MFIv4_MARK,         MSEL4CR_6_1),
 };
 
-#define _GPIO_PORT(pfx, sfx) PINMUX_GPIO(GPIO_PORT##pfx, PORT##pfx##_DATA)
-#define GPIO_PORT_ALL() _190(_GPIO_PORT, , unused)
-#define GPIO_FN(str) PINMUX_GPIO(GPIO_FN_##str, str##_MARK)
-
 static struct pinmux_gpio pinmux_gpios[] = {
 
        /* PORT */
@@ -1201,22 +1199,6 @@ static struct pinmux_gpio pinmux_gpios[] = {
        GPIO_FN(SDENC_DV_CLKI),
 };
 
-/* helper for top 4 bits in PORTnCR */
-#define PCRH(in, in_pd, in_pu, out)            \
-       0, (out), (in), 0,                      \
-       0, 0, 0, 0,                             \
-       0, 0, (in_pd), 0,                       \
-       0, 0, (in_pu), 0
-
-#define PORTCR(nr, reg)                                                \
-       { PINMUX_CFG_REG("PORT" nr "CR", reg, 8, 4) {           \
-               PCRH(PORT##nr##_IN, PORT##nr##_IN_PD,           \
-                    PORT##nr##_IN_PU, PORT##nr##_OUT),         \
-               PORT##nr##_FN0, PORT##nr##_FN1, PORT##nr##_FN2, \
-               PORT##nr##_FN3, PORT##nr##_FN4, PORT##nr##_FN5, \
-               PORT##nr##_FN6, PORT##nr##_FN7 }                \
-       }
-
 static struct pinmux_cfg_reg pinmux_config_regs[] = {
        PORTCR(0,       0xE6051000), /* PORT0CR */
        PORTCR(1,       0xE6051001), /* PORT1CR */
index 613e684..2f10511 100644 (file)
 #include <linux/gpio.h>
 #include <mach/sh7377.h>
 
-#define _1(fn, pfx, sfx) fn(pfx, sfx)
-
-#define _10(fn, pfx, sfx)                              \
-       _1(fn, pfx##0, sfx), _1(fn, pfx##1, sfx),       \
-       _1(fn, pfx##2, sfx), _1(fn, pfx##3, sfx),       \
-       _1(fn, pfx##4, sfx), _1(fn, pfx##5, sfx),       \
-       _1(fn, pfx##6, sfx), _1(fn, pfx##7, sfx),       \
-       _1(fn, pfx##8, sfx), _1(fn, pfx##9, sfx)
-
-#define _90(fn, pfx, sfx)                              \
-       _10(fn, pfx##1, sfx), _10(fn, pfx##2, sfx),     \
-       _10(fn, pfx##3, sfx), _10(fn, pfx##4, sfx),     \
-       _10(fn, pfx##5, sfx), _10(fn, pfx##6, sfx),     \
-       _10(fn, pfx##7, sfx), _10(fn, pfx##8, sfx),     \
-       _10(fn, pfx##9, sfx)
-
-#define _265(fn, pfx, sfx)                             \
-       _10(fn, pfx, sfx), _90(fn, pfx, sfx),           \
-       _10(fn, pfx##10, sfx),                          \
-       _1(fn, pfx##110, sfx), _1(fn, pfx##111, sfx),   \
-       _1(fn, pfx##112, sfx), _1(fn, pfx##113, sfx),   \
-       _1(fn, pfx##114, sfx), _1(fn, pfx##115, sfx),   \
-       _1(fn, pfx##116, sfx), _1(fn, pfx##117, sfx),   \
-       _1(fn, pfx##118, sfx),                          \
-       _1(fn, pfx##128, sfx), _1(fn, pfx##129, sfx),   \
-       _10(fn, pfx##13, sfx), _10(fn, pfx##14, sfx),   \
-       _10(fn, pfx##15, sfx),                          \
-       _1(fn, pfx##160, sfx), _1(fn, pfx##161, sfx),   \
-       _1(fn, pfx##162, sfx), _1(fn, pfx##163, sfx),   \
-       _1(fn, pfx##164, sfx),                          \
-       _1(fn, pfx##192, sfx), _1(fn, pfx##193, sfx),   \
-       _1(fn, pfx##194, sfx), _1(fn, pfx##195, sfx),   \
-       _1(fn, pfx##196, sfx), _1(fn, pfx##197, sfx),   \
-       _1(fn, pfx##198, sfx), _1(fn, pfx##199, sfx),   \
-       _10(fn, pfx##20, sfx), _10(fn, pfx##21, sfx),   \
-       _10(fn, pfx##22, sfx), _10(fn, pfx##23, sfx),   \
-       _10(fn, pfx##24, sfx), _10(fn, pfx##25, sfx),   \
-       _1(fn, pfx##260, sfx), _1(fn, pfx##261, sfx),   \
-       _1(fn, pfx##262, sfx), _1(fn, pfx##263, sfx),   \
-       _1(fn, pfx##264, sfx)
-
-#define _PORT(pfx, sfx) pfx##_##sfx
-#define PORT_265(str) _265(_PORT, PORT, str)
+#define CPU_ALL_PORT(fn, pfx, sfx)                             \
+       PORT_10(fn, pfx, sfx), PORT_90(fn, pfx, sfx),           \
+       PORT_10(fn, pfx##10, sfx),                              \
+       PORT_1(fn, pfx##110, sfx), PORT_1(fn, pfx##111, sfx),   \
+       PORT_1(fn, pfx##112, sfx), PORT_1(fn, pfx##113, sfx),   \
+       PORT_1(fn, pfx##114, sfx), PORT_1(fn, pfx##115, sfx),   \
+       PORT_1(fn, pfx##116, sfx), PORT_1(fn, pfx##117, sfx),   \
+       PORT_1(fn, pfx##118, sfx),                              \
+       PORT_1(fn, pfx##128, sfx), PORT_1(fn, pfx##129, sfx),   \
+       PORT_10(fn, pfx##13, sfx), PORT_10(fn, pfx##14, sfx),   \
+       PORT_10(fn, pfx##15, sfx),                              \
+       PORT_1(fn, pfx##160, sfx), PORT_1(fn, pfx##161, sfx),   \
+       PORT_1(fn, pfx##162, sfx), PORT_1(fn, pfx##163, sfx),   \
+       PORT_1(fn, pfx##164, sfx),                              \
+       PORT_1(fn, pfx##192, sfx), PORT_1(fn, pfx##193, sfx),   \
+       PORT_1(fn, pfx##194, sfx), PORT_1(fn, pfx##195, sfx),   \
+       PORT_1(fn, pfx##196, sfx), PORT_1(fn, pfx##197, sfx),   \
+       PORT_1(fn, pfx##198, sfx), PORT_1(fn, pfx##199, sfx),   \
+       PORT_10(fn, pfx##20, sfx), PORT_10(fn, pfx##21, sfx),   \
+       PORT_10(fn, pfx##22, sfx), PORT_10(fn, pfx##23, sfx),   \
+       PORT_10(fn, pfx##24, sfx), PORT_10(fn, pfx##25, sfx),   \
+       PORT_1(fn, pfx##260, sfx), PORT_1(fn, pfx##261, sfx),   \
+       PORT_1(fn, pfx##262, sfx), PORT_1(fn, pfx##263, sfx),   \
+       PORT_1(fn, pfx##264, sfx)
 
 enum {
        PINMUX_RESERVED = 0,
 
        PINMUX_DATA_BEGIN,
-       PORT_265(DATA), /* PORT0_DATA -> PORT264_DATA */
+       PORT_ALL(DATA), /* PORT0_DATA -> PORT264_DATA */
        PINMUX_DATA_END,
 
        PINMUX_INPUT_BEGIN,
-       PORT_265(IN), /* PORT0_IN -> PORT264_IN */
+       PORT_ALL(IN), /* PORT0_IN -> PORT264_IN */
        PINMUX_INPUT_END,
 
        PINMUX_INPUT_PULLUP_BEGIN,
-       PORT_265(IN_PU), /* PORT0_IN_PU -> PORT264_IN_PU */
+       PORT_ALL(IN_PU), /* PORT0_IN_PU -> PORT264_IN_PU */
        PINMUX_INPUT_PULLUP_END,
 
        PINMUX_INPUT_PULLDOWN_BEGIN,
-       PORT_265(IN_PD), /* PORT0_IN_PD -> PORT264_IN_PD */
+       PORT_ALL(IN_PD), /* PORT0_IN_PD -> PORT264_IN_PD */
        PINMUX_INPUT_PULLDOWN_END,
 
        PINMUX_OUTPUT_BEGIN,
-       PORT_265(OUT), /* PORT0_OUT -> PORT264_OUT */
+       PORT_ALL(OUT), /* PORT0_OUT -> PORT264_OUT */
        PINMUX_OUTPUT_END,
 
        PINMUX_FUNCTION_BEGIN,
-       PORT_265(FN_IN), /* PORT0_FN_IN -> PORT264_FN_IN */
-       PORT_265(FN_OUT), /* PORT0_FN_OUT -> PORT264_FN_OUT */
-       PORT_265(FN0), /* PORT0_FN0 -> PORT264_FN0 */
-       PORT_265(FN1), /* PORT0_FN1 -> PORT264_FN1 */
-       PORT_265(FN2), /* PORT0_FN2 -> PORT264_FN2 */
-       PORT_265(FN3), /* PORT0_FN3 -> PORT264_FN3 */
-       PORT_265(FN4), /* PORT0_FN4 -> PORT264_FN4 */
-       PORT_265(FN5), /* PORT0_FN5 -> PORT264_FN5 */
-       PORT_265(FN6), /* PORT0_FN6 -> PORT264_FN6 */
-       PORT_265(FN7), /* PORT0_FN7 -> PORT264_FN7 */
+       PORT_ALL(FN_IN), /* PORT0_FN_IN -> PORT264_FN_IN */
+       PORT_ALL(FN_OUT), /* PORT0_FN_OUT -> PORT264_FN_OUT */
+       PORT_ALL(FN0), /* PORT0_FN0 -> PORT264_FN0 */
+       PORT_ALL(FN1), /* PORT0_FN1 -> PORT264_FN1 */
+       PORT_ALL(FN2), /* PORT0_FN2 -> PORT264_FN2 */
+       PORT_ALL(FN3), /* PORT0_FN3 -> PORT264_FN3 */
+       PORT_ALL(FN4), /* PORT0_FN4 -> PORT264_FN4 */
+       PORT_ALL(FN5), /* PORT0_FN5 -> PORT264_FN5 */
+       PORT_ALL(FN6), /* PORT0_FN6 -> PORT264_FN6 */
+       PORT_ALL(FN7), /* PORT0_FN7 -> PORT264_FN7 */
 
        MSELBCR_MSEL17_1, MSELBCR_MSEL17_0,
        MSELBCR_MSEL16_1, MSELBCR_MSEL16_0,
@@ -360,45 +341,6 @@ enum {
        PINMUX_MARK_END,
 };
 
-#define PORT_DATA_I(nr)        \
-       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0, PORT##nr##_IN)
-
-#define PORT_DATA_I_PD(nr)     \
-       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0,    \
-                               PORT##nr##_IN, PORT##nr##_IN_PD)
-
-#define PORT_DATA_I_PU(nr)     \
-       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0,    \
-                               PORT##nr##_IN, PORT##nr##_IN_PU)
-
-#define PORT_DATA_I_PU_PD(nr)  \
-       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0,    \
-                               PORT##nr##_IN, PORT##nr##_IN_PD,        \
-                               PORT##nr##_IN_PU)
-
-#define PORT_DATA_O(nr)        \
-       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0,    \
-                               PORT##nr##_OUT)
-
-#define PORT_DATA_IO(nr)       \
-       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0,    \
-                               PORT##nr##_OUT, PORT##nr##_IN)
-
-#define PORT_DATA_IO_PD(nr)    \
-       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0,    \
-                               PORT##nr##_OUT, PORT##nr##_IN,          \
-                               PORT##nr##_IN_PD)
-
-#define PORT_DATA_IO_PU(nr)    \
-       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0,    \
-                               PORT##nr##_OUT, PORT##nr##_IN,          \
-                               PORT##nr##_IN_PU)
-
-#define PORT_DATA_IO_PU_PD(nr) \
-       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0,    \
-                               PORT##nr##_OUT, PORT##nr##_IN,          \
-                               PORT##nr##_IN_PD, PORT##nr##_IN_PU)
-
 static pinmux_enum_t pinmux_data[] = {
        /* specify valid pin states for each pin in GPIO mode */
        /* 55-1 (GPIO) */
@@ -1078,13 +1020,9 @@ static pinmux_enum_t pinmux_data[] = {
        PINMUX_DATA(RESETOUTS_MARK, PORT264_FN1),
 };
 
-#define _GPIO_PORT(pfx, sfx) PINMUX_GPIO(GPIO_PORT##pfx, PORT##pfx##_DATA)
-#define GPIO_PORT_265() _265(_GPIO_PORT, , unused)
-#define GPIO_FN(str) PINMUX_GPIO(GPIO_FN_##str, str##_MARK)
-
 static struct pinmux_gpio pinmux_gpios[] = {
        /* 55-1 -> 55-5 (GPIO) */
-       GPIO_PORT_265(),
+       GPIO_PORT_ALL(),
 
        /* Special Pull-up / Pull-down Functions */
        GPIO_FN(PORT66_KEYIN0_PU), GPIO_FN(PORT67_KEYIN1_PU),
@@ -1362,23 +1300,6 @@ static struct pinmux_gpio pinmux_gpios[] = {
        GPIO_FN(RESETOUTS),
 };
 
-/* helper for top 4 bits in PORTnCR */
-#define PCRH(in, in_pd, in_pu, out)    \
-       0, (out), (in), 0,      \
-               0, 0, 0, 0,     \
-               0, 0, (in_pd), 0,       \
-               0, 0, (in_pu), 0
-
-#define PORTCR(nr, reg)        \
-       { PINMUX_CFG_REG("PORT" nr "CR", reg, 8, 4) {   \
-                       PCRH(PORT##nr##_IN, PORT##nr##_IN_PD,   \
-                                PORT##nr##_IN_PU, PORT##nr##_OUT),     \
-                               PORT##nr##_FN0, PORT##nr##_FN1, \
-                               PORT##nr##_FN2, PORT##nr##_FN3, \
-                               PORT##nr##_FN4, PORT##nr##_FN5, \
-                               PORT##nr##_FN6, PORT##nr##_FN7 }        \
-       }
-
 static struct pinmux_cfg_reg pinmux_config_regs[] = {
        PORTCR(0, 0xe6050000), /* PORT0CR */
        PORTCR(1, 0xe6050001), /* PORT1CR */
index 5abe02f..e05634c 100644 (file)
 #include <mach/sh73a0.h>
 #include <mach/irqs.h>
 
-#define _1(fn, pfx, sfx) fn(pfx, sfx)
-
-#define _10(fn, pfx, sfx)                              \
-       _1(fn, pfx##0, sfx), _1(fn, pfx##1, sfx),       \
-       _1(fn, pfx##2, sfx), _1(fn, pfx##3, sfx),       \
-       _1(fn, pfx##4, sfx), _1(fn, pfx##5, sfx),       \
-       _1(fn, pfx##6, sfx), _1(fn, pfx##7, sfx),       \
-       _1(fn, pfx##8, sfx), _1(fn, pfx##9, sfx)
-
-#define _310(fn, pfx, sfx)                             \
-       _10(fn, pfx,    sfx), _10(fn, pfx##1, sfx),     \
-       _10(fn, pfx##2, sfx), _10(fn, pfx##3, sfx),     \
-       _10(fn, pfx##4, sfx), _10(fn, pfx##5, sfx),     \
-       _10(fn, pfx##6, sfx), _10(fn, pfx##7, sfx),     \
-       _10(fn, pfx##8, sfx), _10(fn, pfx##9, sfx),     \
-       _10(fn, pfx##10, sfx),                          \
-       _1(fn, pfx##110, sfx), _1(fn, pfx##111, sfx),   \
-       _1(fn, pfx##112, sfx), _1(fn, pfx##113, sfx),   \
-       _1(fn, pfx##114, sfx), _1(fn, pfx##115, sfx),   \
-       _1(fn, pfx##116, sfx), _1(fn, pfx##117, sfx),   \
-       _1(fn, pfx##118, sfx),                          \
-       _1(fn, pfx##128, sfx), _1(fn, pfx##129, sfx),   \
-       _10(fn, pfx##13, sfx), _10(fn, pfx##14, sfx),   \
-       _10(fn, pfx##15, sfx),                          \
-       _1(fn, pfx##160, sfx), _1(fn, pfx##161, sfx),   \
-       _1(fn, pfx##162, sfx), _1(fn, pfx##163, sfx),   \
-       _1(fn, pfx##164, sfx),                          \
-       _1(fn, pfx##192, sfx), _1(fn, pfx##193, sfx),   \
-       _1(fn, pfx##194, sfx), _1(fn, pfx##195, sfx),   \
-       _1(fn, pfx##196, sfx), _1(fn, pfx##197, sfx),   \
-       _1(fn, pfx##198, sfx), _1(fn, pfx##199, sfx),   \
-       _10(fn, pfx##20, sfx), _10(fn, pfx##21, sfx),   \
-       _10(fn, pfx##22, sfx), _10(fn, pfx##23, sfx),   \
-       _10(fn, pfx##24, sfx), _10(fn, pfx##25, sfx),   \
-       _10(fn, pfx##26, sfx), _10(fn, pfx##27, sfx),   \
-       _1(fn, pfx##280, sfx), _1(fn, pfx##281, sfx),   \
-       _1(fn, pfx##282, sfx),                          \
-       _1(fn, pfx##288, sfx), _1(fn, pfx##289, sfx),   \
-       _10(fn, pfx##29, sfx), _10(fn, pfx##30, sfx)
-
-#define _PORT(pfx, sfx) pfx##_##sfx
-#define PORT_310(str) _310(_PORT, PORT, str)
+#define CPU_ALL_PORT(fn, pfx, sfx)                             \
+       PORT_10(fn, pfx,    sfx), PORT_10(fn, pfx##1, sfx),     \
+       PORT_10(fn, pfx##2, sfx), PORT_10(fn, pfx##3, sfx),     \
+       PORT_10(fn, pfx##4, sfx), PORT_10(fn, pfx##5, sfx),     \
+       PORT_10(fn, pfx##6, sfx), PORT_10(fn, pfx##7, sfx),     \
+       PORT_10(fn, pfx##8, sfx), PORT_10(fn, pfx##9, sfx),     \
+       PORT_10(fn, pfx##10, sfx),                              \
+       PORT_1(fn, pfx##110, sfx), PORT_1(fn, pfx##111, sfx),   \
+       PORT_1(fn, pfx##112, sfx), PORT_1(fn, pfx##113, sfx),   \
+       PORT_1(fn, pfx##114, sfx), PORT_1(fn, pfx##115, sfx),   \
+       PORT_1(fn, pfx##116, sfx), PORT_1(fn, pfx##117, sfx),   \
+       PORT_1(fn, pfx##118, sfx),                              \
+       PORT_1(fn, pfx##128, sfx), PORT_1(fn, pfx##129, sfx),   \
+       PORT_10(fn, pfx##13, sfx), PORT_10(fn, pfx##14, sfx),   \
+       PORT_10(fn, pfx##15, sfx),                              \
+       PORT_1(fn, pfx##160, sfx), PORT_1(fn, pfx##161, sfx),   \
+       PORT_1(fn, pfx##162, sfx), PORT_1(fn, pfx##163, sfx),   \
+       PORT_1(fn, pfx##164, sfx),                              \
+       PORT_1(fn, pfx##192, sfx), PORT_1(fn, pfx##193, sfx),   \
+       PORT_1(fn, pfx##194, sfx), PORT_1(fn, pfx##195, sfx),   \
+       PORT_1(fn, pfx##196, sfx), PORT_1(fn, pfx##197, sfx),   \
+       PORT_1(fn, pfx##198, sfx), PORT_1(fn, pfx##199, sfx),   \
+       PORT_10(fn, pfx##20, sfx), PORT_10(fn, pfx##21, sfx),   \
+       PORT_10(fn, pfx##22, sfx), PORT_10(fn, pfx##23, sfx),   \
+       PORT_10(fn, pfx##24, sfx), PORT_10(fn, pfx##25, sfx),   \
+       PORT_10(fn, pfx##26, sfx), PORT_10(fn, pfx##27, sfx),   \
+       PORT_1(fn, pfx##280, sfx), PORT_1(fn, pfx##281, sfx),   \
+       PORT_1(fn, pfx##282, sfx),                              \
+       PORT_1(fn, pfx##288, sfx), PORT_1(fn, pfx##289, sfx),   \
+       PORT_10(fn, pfx##29, sfx), PORT_10(fn, pfx##30, sfx)
 
 enum {
        PINMUX_RESERVED = 0,
 
        PINMUX_DATA_BEGIN,
-       PORT_310(DATA),                 /* PORT0_DATA -> PORT309_DATA */
+       PORT_ALL(DATA),                 /* PORT0_DATA -> PORT309_DATA */
        PINMUX_DATA_END,
 
        PINMUX_INPUT_BEGIN,
-       PORT_310(IN),                   /* PORT0_IN -> PORT309_IN */
+       PORT_ALL(IN),                   /* PORT0_IN -> PORT309_IN */
        PINMUX_INPUT_END,
 
        PINMUX_INPUT_PULLUP_BEGIN,
-       PORT_310(IN_PU),                /* PORT0_IN_PU -> PORT309_IN_PU */
+       PORT_ALL(IN_PU),                /* PORT0_IN_PU -> PORT309_IN_PU */
        PINMUX_INPUT_PULLUP_END,
 
        PINMUX_INPUT_PULLDOWN_BEGIN,
-       PORT_310(IN_PD),                /* PORT0_IN_PD -> PORT309_IN_PD */
+       PORT_ALL(IN_PD),                /* PORT0_IN_PD -> PORT309_IN_PD */
        PINMUX_INPUT_PULLDOWN_END,
 
        PINMUX_OUTPUT_BEGIN,
-       PORT_310(OUT),                  /* PORT0_OUT -> PORT309_OUT */
+       PORT_ALL(OUT),                  /* PORT0_OUT -> PORT309_OUT */
        PINMUX_OUTPUT_END,
 
        PINMUX_FUNCTION_BEGIN,
-       PORT_310(FN_IN),                /* PORT0_FN_IN -> PORT309_FN_IN */
-       PORT_310(FN_OUT),               /* PORT0_FN_OUT -> PORT309_FN_OUT */
-       PORT_310(FN0),                  /* PORT0_FN0 -> PORT309_FN0 */
-       PORT_310(FN1),                  /* PORT0_FN1 -> PORT309_FN1 */
-       PORT_310(FN2),                  /* PORT0_FN2 -> PORT309_FN2 */
-       PORT_310(FN3),                  /* PORT0_FN3 -> PORT309_FN3 */
-       PORT_310(FN4),                  /* PORT0_FN4 -> PORT309_FN4 */
-       PORT_310(FN5),                  /* PORT0_FN5 -> PORT309_FN5 */
-       PORT_310(FN6),                  /* PORT0_FN6 -> PORT309_FN6 */
-       PORT_310(FN7),                  /* PORT0_FN7 -> PORT309_FN7 */
+       PORT_ALL(FN_IN),                /* PORT0_FN_IN -> PORT309_FN_IN */
+       PORT_ALL(FN_OUT),               /* PORT0_FN_OUT -> PORT309_FN_OUT */
+       PORT_ALL(FN0),                  /* PORT0_FN0 -> PORT309_FN0 */
+       PORT_ALL(FN1),                  /* PORT0_FN1 -> PORT309_FN1 */
+       PORT_ALL(FN2),                  /* PORT0_FN2 -> PORT309_FN2 */
+       PORT_ALL(FN3),                  /* PORT0_FN3 -> PORT309_FN3 */
+       PORT_ALL(FN4),                  /* PORT0_FN4 -> PORT309_FN4 */
+       PORT_ALL(FN5),                  /* PORT0_FN5 -> PORT309_FN5 */
+       PORT_ALL(FN6),                  /* PORT0_FN6 -> PORT309_FN6 */
+       PORT_ALL(FN7),                  /* PORT0_FN7 -> PORT309_FN7 */
 
        MSEL2CR_MSEL19_0, MSEL2CR_MSEL19_1,
        MSEL2CR_MSEL18_0, MSEL2CR_MSEL18_1,
@@ -508,6 +496,14 @@ enum {
        SDHICMD2_PU_MARK,
        MMCCMD0_PU_MARK,
        MMCCMD1_PU_MARK,
+       MMCD0_0_PU_MARK,
+       MMCD0_1_PU_MARK,
+       MMCD0_2_PU_MARK,
+       MMCD0_3_PU_MARK,
+       MMCD0_4_PU_MARK,
+       MMCD0_5_PU_MARK,
+       MMCD0_6_PU_MARK,
+       MMCD0_7_PU_MARK,
        FSIBISLD_PU_MARK,
        FSIACK_PU_MARK,
        FSIAILR_PU_MARK,
@@ -517,45 +513,6 @@ enum {
        PINMUX_MARK_END,
 };
 
-#define PORT_DATA_I(nr)        \
-       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0, PORT##nr##_IN)
-
-#define PORT_DATA_I_PD(nr)     \
-       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0,    \
-                               PORT##nr##_IN, PORT##nr##_IN_PD)
-
-#define PORT_DATA_I_PU(nr)     \
-       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0,    \
-                               PORT##nr##_IN, PORT##nr##_IN_PU)
-
-#define PORT_DATA_I_PU_PD(nr)  \
-       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0,    \
-                               PORT##nr##_IN, PORT##nr##_IN_PD,        \
-                               PORT##nr##_IN_PU)
-
-#define PORT_DATA_O(nr)        \
-       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0,    \
-                               PORT##nr##_OUT)
-
-#define PORT_DATA_IO(nr)       \
-       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0,    \
-                               PORT##nr##_OUT, PORT##nr##_IN)
-
-#define PORT_DATA_IO_PD(nr)    \
-       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0,    \
-                               PORT##nr##_OUT, PORT##nr##_IN,          \
-                               PORT##nr##_IN_PD)
-
-#define PORT_DATA_IO_PU(nr)    \
-       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0,    \
-                               PORT##nr##_OUT, PORT##nr##_IN,          \
-                               PORT##nr##_IN_PU)
-
-#define PORT_DATA_IO_PU_PD(nr) \
-       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0,    \
-                               PORT##nr##_OUT, PORT##nr##_IN,          \
-                               PORT##nr##_IN_PD, PORT##nr##_IN_PU)
-
 static pinmux_enum_t pinmux_data[] = {
        /* specify valid pin states for each pin in GPIO mode */
 
@@ -1561,6 +1518,24 @@ static pinmux_enum_t pinmux_data[] = {
                MSEL4CR_MSEL15_0),
        PINMUX_DATA(MMCCMD1_PU_MARK, PORT297_FN2, PORT297_IN_PU,
                MSEL4CR_MSEL15_1),
+
+       PINMUX_DATA(MMCD0_0_PU_MARK,
+                   PORT271_FN1, PORT271_IN_PU, MSEL4CR_MSEL15_0),
+       PINMUX_DATA(MMCD0_1_PU_MARK,
+                   PORT272_FN1, PORT272_IN_PU, MSEL4CR_MSEL15_0),
+       PINMUX_DATA(MMCD0_2_PU_MARK,
+                   PORT273_FN1, PORT273_IN_PU, MSEL4CR_MSEL15_0),
+       PINMUX_DATA(MMCD0_3_PU_MARK,
+                   PORT274_FN1, PORT274_IN_PU, MSEL4CR_MSEL15_0),
+       PINMUX_DATA(MMCD0_4_PU_MARK,
+                   PORT275_FN1, PORT275_IN_PU, MSEL4CR_MSEL15_0),
+       PINMUX_DATA(MMCD0_5_PU_MARK,
+                   PORT276_FN1, PORT276_IN_PU, MSEL4CR_MSEL15_0),
+       PINMUX_DATA(MMCD0_6_PU_MARK,
+                   PORT277_FN1, PORT277_IN_PU, MSEL4CR_MSEL15_0),
+       PINMUX_DATA(MMCD0_7_PU_MARK,
+                   PORT278_FN1, PORT278_IN_PU, MSEL4CR_MSEL15_0),
+
        PINMUX_DATA(FSIBISLD_PU_MARK, PORT39_FN1, PORT39_IN_PU),
        PINMUX_DATA(FSIACK_PU_MARK, PORT49_FN1, PORT49_IN_PU),
        PINMUX_DATA(FSIAILR_PU_MARK, PORT50_FN5, PORT50_IN_PU),
@@ -1568,12 +1543,8 @@ static pinmux_enum_t pinmux_data[] = {
        PINMUX_DATA(FSIAISLD_PU_MARK, PORT55_FN1, PORT55_IN_PU),
 };
 
-#define _GPIO_PORT(pfx, sfx) PINMUX_GPIO(GPIO_PORT##pfx, PORT##pfx##_DATA)
-#define GPIO_PORT_310() _310(_GPIO_PORT, , unused)
-#define GPIO_FN(str) PINMUX_GPIO(GPIO_FN_##str, str##_MARK)
-
 static struct pinmux_gpio pinmux_gpios[] = {
-       GPIO_PORT_310(),
+       GPIO_PORT_ALL(),
 
        /* Table 25-1 (Functions 0-7) */
        GPIO_FN(VBUS_0),
@@ -2236,24 +2207,20 @@ static struct pinmux_gpio pinmux_gpios[] = {
        GPIO_FN(SDHICMD2_PU),
        GPIO_FN(MMCCMD0_PU),
        GPIO_FN(MMCCMD1_PU),
+       GPIO_FN(MMCD0_0_PU),
+       GPIO_FN(MMCD0_1_PU),
+       GPIO_FN(MMCD0_2_PU),
+       GPIO_FN(MMCD0_3_PU),
+       GPIO_FN(MMCD0_4_PU),
+       GPIO_FN(MMCD0_5_PU),
+       GPIO_FN(MMCD0_6_PU),
+       GPIO_FN(MMCD0_7_PU),
        GPIO_FN(FSIACK_PU),
        GPIO_FN(FSIAILR_PU),
        GPIO_FN(FSIAIBT_PU),
        GPIO_FN(FSIAISLD_PU),
 };
 
-#define PORTCR(nr, reg)        \
-       { PINMUX_CFG_REG("PORT" nr "CR", reg, 8, 4) { \
-               0, \
-               /*0001*/ PORT##nr##_OUT , \
-               /*0010*/ PORT##nr##_IN , 0, 0, 0, 0, 0, 0, 0, \
-               /*1010*/ PORT##nr##_IN_PD, 0, 0, 0, \
-               /*1110*/ PORT##nr##_IN_PU, 0, \
-               PORT##nr##_FN0, PORT##nr##_FN1, PORT##nr##_FN2, \
-               PORT##nr##_FN3, PORT##nr##_FN4, PORT##nr##_FN5, \
-               PORT##nr##_FN6, PORT##nr##_FN7, 0, 0, 0, 0, 0, 0, 0, 0 } \
-       }
-
 static struct pinmux_cfg_reg pinmux_config_regs[] = {
        PORTCR(0, 0xe6050000), /* PORT0CR */
        PORTCR(1, 0xe6050001), /* PORT1CR */
index 7961273..34bbcbf 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/delay.h>
 #include <linux/irq.h>
 #include <linux/bitrev.h>
+#include <linux/console.h>
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/tlbflush.h>
@@ -106,9 +107,8 @@ static int pd_power_down(struct generic_pm_domain *genpd)
        return 0;
 }
 
-static int pd_power_up(struct generic_pm_domain *genpd)
+static int __pd_power_up(struct sh7372_pm_domain *sh7372_pd, bool do_resume)
 {
-       struct sh7372_pm_domain *sh7372_pd = to_sh7372_pd(genpd);
        unsigned int mask = 1 << sh7372_pd->bit_shift;
        unsigned int retry_count;
        int ret = 0;
@@ -123,13 +123,13 @@ static int pd_power_up(struct generic_pm_domain *genpd)
 
        for (retry_count = 2 * PSTR_RETRIES; retry_count; retry_count--) {
                if (!(__raw_readl(SWUCR) & mask))
-                       goto out;
+                       break;
                if (retry_count > PSTR_RETRIES)
                        udelay(PSTR_DELAY_US);
                else
                        cpu_relax();
        }
-       if (__raw_readl(SWUCR) & mask)
+       if (!retry_count)
                ret = -EIO;
 
        if (!sh7372_pd->no_debug)
@@ -137,12 +137,17 @@ static int pd_power_up(struct generic_pm_domain *genpd)
                         mask, __raw_readl(PSTR));
 
  out:
-       if (ret == 0 && sh7372_pd->resume)
+       if (ret == 0 && sh7372_pd->resume && do_resume)
                sh7372_pd->resume();
 
        return ret;
 }
 
+static int pd_power_up(struct generic_pm_domain *genpd)
+{
+        return __pd_power_up(to_sh7372_pd(genpd), true);
+}
+
 static void sh7372_a4r_suspend(void)
 {
        sh7372_intcs_suspend();
@@ -174,7 +179,7 @@ void sh7372_init_pm_domain(struct sh7372_pm_domain *sh7372_pd)
        genpd->active_wakeup = pd_active_wakeup;
        genpd->power_off = pd_power_down;
        genpd->power_on = pd_power_up;
-       genpd->power_on(&sh7372_pd->genpd);
+       __pd_power_up(sh7372_pd, false);
 }
 
 void sh7372_add_device_to_domain(struct sh7372_pm_domain *sh7372_pd,
@@ -227,11 +232,23 @@ struct sh7372_pm_domain sh7372_a3sp = {
        .no_debug = true,
 };
 
+static void sh7372_a3sp_init(void)
+{
+       /* serial consoles make use of SCIF hardware located in A3SP,
+        * keep such power domain on if "no_console_suspend" is set.
+        */
+       sh7372_a3sp.stay_on = !console_suspend_enabled;
+}
+
 struct sh7372_pm_domain sh7372_a3sg = {
        .bit_shift = 13,
 };
 
-#endif /* CONFIG_PM */
+#else /* !CONFIG_PM */
+
+static inline void sh7372_a3sp_init(void) {}
+
+#endif /* !CONFIG_PM */
 
 #if defined(CONFIG_SUSPEND) || defined(CONFIG_CPU_IDLE)
 static int sh7372_do_idle_core_standby(unsigned long unused)
@@ -402,22 +419,18 @@ static void sh7372_setup_a3sm(unsigned long msk, unsigned long msk2)
 
 #ifdef CONFIG_CPU_IDLE
 
-static void sh7372_cpuidle_setup(struct cpuidle_device *dev)
+static void sh7372_cpuidle_setup(struct cpuidle_driver *drv)
 {
-       struct cpuidle_state *state;
-       int i = dev->state_count;
+       struct cpuidle_state *state = &drv->states[drv->state_count];
 
-       state = &dev->states[i];
        snprintf(state->name, CPUIDLE_NAME_LEN, "C2");
        strncpy(state->desc, "Core Standby Mode", CPUIDLE_DESC_LEN);
        state->exit_latency = 10;
        state->target_residency = 20 + 10;
-       state->power_usage = 1; /* perhaps not */
-       state->flags = 0;
-       state->flags |= CPUIDLE_FLAG_TIME_VALID;
-       shmobile_cpuidle_modes[i] = sh7372_enter_core_standby;
+       state->flags = CPUIDLE_FLAG_TIME_VALID;
+       shmobile_cpuidle_modes[drv->state_count] = sh7372_enter_core_standby;
 
-       dev->state_count = i + 1;
+       drv->state_count++;
 }
 
 static void sh7372_cpuidle_init(void)
@@ -469,6 +482,8 @@ void __init sh7372_pm_init(void)
        /* do not convert A3SM, A3SP, A3SG, A4R power down into A4S */
        __raw_writel(0, PDNSEL);
 
+       sh7372_a3sp_init();
+
        sh7372_suspend_init();
        sh7372_cpuidle_init();
 }
index d368f8d..74743ad 100644 (file)
@@ -101,6 +101,13 @@ static void __init tegra_dt_init(void)
 
        tegra_clk_init_from_table(tegra_dt_clk_init_table);
 
+       /*
+        * Finished with the static registrations now; fill in the missing
+        * devices
+        */
+       of_platform_populate(NULL, tegra_dt_match_table,
+                               tegra20_auxdata_lookup, NULL);
+
        for (i = 0; i < ARRAY_SIZE(pinmux_configs); i++) {
                if (of_machine_is_compatible(pinmux_configs[i].machine)) {
                        pinmux_configs[i].init();
@@ -110,12 +117,6 @@ static void __init tegra_dt_init(void)
 
        WARN(i == ARRAY_SIZE(pinmux_configs),
                "Unknown platform! Pinmuxing not initialized\n");
-
-       /*
-        * Finished with the static registrations now; fill in the missing
-        * devices
-        */
-       of_platform_populate(NULL, tegra_dt_match_table, tegra20_auxdata_lookup, NULL);
 }
 
 static const char * tegra_dt_board_compat[] = {
index e99b456..7a4a26d 100644 (file)
@@ -16,6 +16,8 @@
 
 #include <linux/kernel.h>
 #include <linux/gpio.h>
+#include <linux/of.h>
+
 #include <mach/pinmux.h>
 
 #include "gpio-names.h"
@@ -161,7 +163,9 @@ static struct tegra_gpio_table gpio_table[] = {
 
 void harmony_pinmux_init(void)
 {
-       platform_add_devices(pinmux_devices, ARRAY_SIZE(pinmux_devices));
+       if (!of_machine_is_compatible("nvidia,tegra20"))
+               platform_add_devices(pinmux_devices,
+                                       ARRAY_SIZE(pinmux_devices));
 
        tegra_pinmux_config_table(harmony_pinmux, ARRAY_SIZE(harmony_pinmux));
 
index fb20894..be30e21 100644 (file)
@@ -16,6 +16,8 @@
 
 #include <linux/kernel.h>
 #include <linux/gpio.h>
+#include <linux/of.h>
+
 #include <mach/pinmux.h>
 
 #include "gpio-names.h"
@@ -158,7 +160,9 @@ static struct tegra_gpio_table gpio_table[] = {
 
 void paz00_pinmux_init(void)
 {
-       platform_add_devices(pinmux_devices, ARRAY_SIZE(pinmux_devices));
+       if (!of_machine_is_compatible("nvidia,tegra20"))
+               platform_add_devices(pinmux_devices,
+                                       ARRAY_SIZE(pinmux_devices));
 
        tegra_pinmux_config_table(paz00_pinmux, ARRAY_SIZE(paz00_pinmux));
 
index fbce31d..b1c2972 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/gpio.h>
+#include <linux/of.h>
 
 #include <mach/pinmux.h>
 #include <mach/pinmux-t2.h>
@@ -191,6 +192,7 @@ static struct tegra_gpio_table common_gpio_table[] = {
        { .gpio = TEGRA_GPIO_SD2_POWER,         .enable = true },
        { .gpio = TEGRA_GPIO_LIDSWITCH,         .enable = true },
        { .gpio = TEGRA_GPIO_POWERKEY,          .enable = true },
+       { .gpio = TEGRA_GPIO_HP_DET,            .enable = true },
        { .gpio = TEGRA_GPIO_ISL29018_IRQ,      .enable = true },
        { .gpio = TEGRA_GPIO_CDC_IRQ,           .enable = true },
        { .gpio = TEGRA_GPIO_USB1,              .enable = true },
@@ -218,7 +220,9 @@ static void __init update_pinmux(struct tegra_pingroup_config *newtbl, int size)
 
 void __init seaboard_common_pinmux_init(void)
 {
-       platform_add_devices(pinmux_devices, ARRAY_SIZE(pinmux_devices));
+       if (!of_machine_is_compatible("nvidia,tegra20"))
+               platform_add_devices(pinmux_devices,
+                                       ARRAY_SIZE(pinmux_devices));
 
        tegra_pinmux_config_table(seaboard_pinmux, ARRAY_SIZE(seaboard_pinmux));
 
index 4969dd2..7ab719d 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/gpio.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/of.h>
 
 #include <mach/pinmux.h>
 
@@ -157,7 +158,9 @@ static struct tegra_gpio_table gpio_table[] = {
 
 void __init trimslice_pinmux_init(void)
 {
-       platform_add_devices(pinmux_devices, ARRAY_SIZE(pinmux_devices));
+       if (!of_machine_is_compatible("nvidia,tegra20"))
+               platform_add_devices(pinmux_devices,
+                                       ARRAY_SIZE(pinmux_devices));
        tegra_pinmux_config_table(trimslice_pinmux, ARRAY_SIZE(trimslice_pinmux));
        tegra_gpio_config(gpio_table, ARRAY_SIZE(gpio_table));
 }
index 7a1fa6a..5b0c38a 100644 (file)
@@ -422,7 +422,7 @@ struct platform_device nuc900_device_kpi = {
 
 /* LCD controller*/
 
-static struct nuc900fb_display __initdata nuc900_lcd_info[] = {
+static struct nuc900fb_display nuc900_lcd_info[] = {
        /* Giantplus Technology GPM1040A0 320x240 Color TFT LCD */
        [0] = {
                .type           = LCM_DCCS_VA_SRC_RGB565,
@@ -445,7 +445,7 @@ static struct nuc900fb_display __initdata nuc900_lcd_info[] = {
        },
 };
 
-static struct nuc900fb_mach_info nuc900_fb_info __initdata = {
+static struct nuc900fb_mach_info nuc900_fb_info = {
 #if defined(CONFIG_GPM1040A0_320X240)
        .displays               = &nuc900_lcd_info[0],
 #else
index 94c0e71..23ef1f5 100644 (file)
@@ -19,6 +19,7 @@
 extern void mfp_set_groupf(struct device *dev);
 extern void mfp_set_groupc(struct device *dev);
 extern void mfp_set_groupi(struct device *dev);
-extern void mfp_set_groupg(struct device *dev);
+extern void mfp_set_groupg(struct device *dev, const char *subname);
+extern void mfp_set_groupd(struct device *dev, const char *subname);
 
 #endif /* __ASM_ARCH_MFP_H */
index bd94819..2c4e0c1 100644 (file)
@@ -14,7 +14,7 @@
 #ifndef __ASM_ARCH_SPI_H
 #define __ASM_ARCH_SPI_H
 
-extern void mfp_set_groupg(struct device *dev);
+extern void mfp_set_groupg(struct device *dev, const char *subname);
 
 struct nuc900_spi_info {
        unsigned int num_cs;
index fb7fb62..9dd7461 100644 (file)
 #define REG_MFSEL      (W90X900_VA_GCR + 0xC)
 
 #define GPSELF         (0x01 << 1)
-
 #define GPSELC         (0x03 << 2)
-#define ENKPI          (0x02 << 2)
-#define ENNAND         (0x01 << 2)
+#define GPSELD         (0x0f << 4)
 
 #define GPSELEI0       (0x01 << 26)
 #define GPSELEI1       (0x01 << 27)
 #define GPIOG0TO1      (0x03 << 14)
 #define GPIOG2TO3      (0x03 << 16)
 #define GPIOG22TO23    (0x03 << 22)
+#define GPIOG18TO20    (0x07 << 18)
 
 #define ENSPI          (0x0a << 14)
 #define ENI2C0         (0x01 << 14)
 #define ENI2C1         (0x01 << 16)
 #define ENAC97         (0x02 << 22)
+#define ENSD1          (0x02 << 18)
+#define ENSD0          (0x0a << 4)
+#define ENKPI          (0x02 << 2)
+#define ENNAND         (0x01 << 2)
 
 static DEFINE_MUTEX(mfp_mutex);
 
@@ -127,16 +130,19 @@ void mfp_set_groupi(struct device *dev)
 }
 EXPORT_SYMBOL(mfp_set_groupi);
 
-void mfp_set_groupg(struct device *dev)
+void mfp_set_groupg(struct device *dev, const char *subname)
 {
        unsigned long mfpen;
        const char *dev_id;
 
-       BUG_ON(!dev);
+       BUG_ON((!dev) && (!subname));
 
        mutex_lock(&mfp_mutex);
 
-       dev_id = dev_name(dev);
+       if (subname != NULL)
+               dev_id = subname;
+       else
+               dev_id = dev_name(dev);
 
        mfpen = __raw_readl(REG_MFSEL);
 
@@ -152,6 +158,9 @@ void mfp_set_groupg(struct device *dev)
        } else if (strcmp(dev_id, "nuc900-audio") == 0) {
                mfpen &= ~(GPIOG22TO23);
                mfpen |= ENAC97;/*enable AC97*/
+       } else if (strcmp(dev_id, "nuc900-mmc-port1") == 0) {
+               mfpen &= ~(GPIOG18TO20);
+               mfpen |= (ENSD1 | 0x01);/*enable sd1*/
        } else {
                mfpen &= ~(GPIOG0TO1 | GPIOG2TO3);/*GPIOG[3:0]*/
        }
@@ -162,3 +171,30 @@ void mfp_set_groupg(struct device *dev)
 }
 EXPORT_SYMBOL(mfp_set_groupg);
 
+void mfp_set_groupd(struct device *dev, const char *subname)
+{
+       unsigned long mfpen;
+       const char *dev_id;
+
+       BUG_ON((!dev) && (!subname));
+
+       mutex_lock(&mfp_mutex);
+
+       if (subname != NULL)
+               dev_id = subname;
+       else
+               dev_id = dev_name(dev);
+
+       mfpen = __raw_readl(REG_MFSEL);
+
+       if (strcmp(dev_id, "nuc900-mmc-port0") == 0) {
+               mfpen &= ~GPSELD;/*enable sd0*/
+               mfpen |= ENSD0;
+       } else
+               mfpen &= (~GPSELD);
+
+       __raw_writel(mfpen, REG_MFSEL);
+
+       mutex_unlock(&mfp_mutex);
+}
+EXPORT_SYMBOL(mfp_set_groupd);
index a08a951..b3a1f2b 100644 (file)
@@ -10,7 +10,7 @@ choice
 
 config ARCH_IMX_V4_V5
        bool "i.MX1, i.MX21, i.MX25, i.MX27"
-       select AUTO_ZRELADDR
+       select AUTO_ZRELADDR if !ZBOOT_ROM
        select ARM_PATCH_PHYS_VIRT
        help
          This enables support for systems based on the Freescale i.MX ARMv4
@@ -26,7 +26,7 @@ config ARCH_IMX_V6_V7
 
 config ARCH_MX5
        bool "i.MX50, i.MX51, i.MX53"
-       select AUTO_ZRELADDR
+       select AUTO_ZRELADDR if !ZBOOT_ROM
        select ARM_PATCH_PHYS_VIRT
        help
          This enables support for machines using Freescale's i.MX50 and i.MX53
index 8875fb4..55f1569 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/io.h>
 #include <mach/common.h>
 #include <asm/mach/irq.h>
+#include <asm/exception.h>
 #include <mach/hardware.h>
 
 #include "irq-common.h"
index b3b8eed..12f8f81 100644 (file)
@@ -28,21 +28,14 @@ asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
                if (irqnr == 1023)
                        break;
 
-               if (irqnr > 29 && irqnr < 1021)
+               if (irqnr > 15 && irqnr < 1021)
                        handle_IRQ(irqnr, regs);
 #ifdef CONFIG_SMP
-               else if (irqnr < 16) {
+               else {
                        writel_relaxed(irqstat, gic_cpu_base_addr +
                                                GIC_CPU_EOI);
                        handle_IPI(irqnr, regs);
                }
 #endif
-#ifdef CONFIG_LOCAL_TIMERS
-               else if (irqnr == 29) {
-                       writel_relaxed(irqstat, gic_cpu_base_addr +
-                                               GIC_CPU_EOI);
-                       handle_local_timer(regs);
-               }
-#endif
        } while (1);
 }
index 9fe0dfc..ca5cf26 100644 (file)
@@ -25,6 +25,3 @@
 
        .macro test_for_ipi, irqnr, irqstat, base, tmp
        .endm
-
-       .macro test_for_ltirq, irqnr, irqstat, base, tmp
-       .endm
index e993a18..a3c164c 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/io.h>
 
 #include <asm/mach/irq.h>
+#include <asm/exception.h>
 
 #include <mach/hardware.h>
 #include <mach/common.h>
index c8d1fae..247b88c 100644 (file)
@@ -62,4 +62,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #endif /* __ASM_AVR32_SOCKET_H */
index 7fd0ec7..ecacdf3 100644 (file)
@@ -32,6 +32,8 @@ struct work_struct;
 struct bfin_serial_port {
        struct uart_port port;
        unsigned int old_status;
+       int tx_irq;
+       int rx_irq;
        int status_irq;
 #ifndef BFIN_UART_BF54X_STYLE
        unsigned int lsr;
index 1082e49..d1c0c0c 100644 (file)
@@ -373,8 +373,13 @@ static struct resource bfin_uart0_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART0_TX,
+               .end = IRQ_UART0_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART0_RX,
-               .end = IRQ_UART0_RX+1,
+               .end = IRQ_UART0_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
@@ -416,8 +421,13 @@ static struct resource bfin_uart1_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART1_TX,
+               .end = IRQ_UART1_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART1_RX,
-               .end = IRQ_UART1_RX+1,
+               .end = IRQ_UART1_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
index 55c1279..5470bf8 100644 (file)
@@ -309,8 +309,13 @@ static struct resource bfin_uart0_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART0_TX,
+               .end = IRQ_UART0_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART0_RX,
-               .end = IRQ_UART0_RX+1,
+               .end = IRQ_UART0_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
@@ -352,8 +357,13 @@ static struct resource bfin_uart1_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART1_TX,
+               .end = IRQ_UART1_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART1_RX,
-               .end = IRQ_UART1_RX+1,
+               .end = IRQ_UART1_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
index 8d65d47..5bc6938 100644 (file)
@@ -381,8 +381,13 @@ static struct resource bfin_uart0_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART0_TX,
+               .end = IRQ_UART0_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART0_RX,
-               .end = IRQ_UART0_RX+1,
+               .end = IRQ_UART0_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
@@ -424,8 +429,13 @@ static struct resource bfin_uart1_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART1_TX,
+               .end = IRQ_UART1_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART1_RX,
-               .end = IRQ_UART1_RX+1,
+               .end = IRQ_UART1_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
index 6410fc1..cd28969 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #include <linux/device.h>
+#include <linux/export.h>
 #include <linux/platform_device.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
@@ -539,8 +540,13 @@ static struct resource bfin_uart0_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART0_TX,
+               .end = IRQ_UART0_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART0_RX,
-               .end = IRQ_UART0_RX+1,
+               .end = IRQ_UART0_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
@@ -582,8 +588,13 @@ static struct resource bfin_uart1_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART1_TX,
+               .end = IRQ_UART1_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART1_RX,
-               .end = IRQ_UART1_RX+1,
+               .end = IRQ_UART1_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
@@ -801,7 +812,6 @@ static struct platform_device bfin_sport1_uart_device = {
 #if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
 #include <linux/input.h>
 #include <linux/gpio_keys.h>
-#include <linux/export.h>
 
 static struct gpio_keys_button bfin_gpio_keys_table[] = {
        {BTN_0, GPIO_PF14, 1, "gpio-keys: BTN0"},
index 64f7278..9f792ea 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 #include <linux/device.h>
+#include <linux/export.h>
 #include <linux/platform_device.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
@@ -417,8 +418,13 @@ static struct resource bfin_uart0_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART0_TX,
+               .end = IRQ_UART0_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART0_RX,
-               .end = IRQ_UART0_RX+1,
+               .end = IRQ_UART0_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
@@ -460,8 +466,13 @@ static struct resource bfin_uart1_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART1_TX,
+               .end = IRQ_UART1_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART1_RX,
-               .end = IRQ_UART1_RX+1,
+               .end = IRQ_UART1_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
@@ -674,7 +685,6 @@ static struct platform_device bfin_sport1_uart_device = {
 #if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
 #include <linux/input.h>
 #include <linux/gpio_keys.h>
-#include <linux/export.h>
 
 static struct gpio_keys_button bfin_gpio_keys_table[] = {
        {BTN_0, GPIO_PG0, 1, "gpio-keys: BTN0"},
index e4c6a12..3ecafff 100644 (file)
@@ -711,8 +711,13 @@ static struct resource bfin_uart0_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART0_TX,
+               .end = IRQ_UART0_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART0_RX,
-               .end = IRQ_UART0_RX+1,
+               .end = IRQ_UART0_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
@@ -754,8 +759,13 @@ static struct resource bfin_uart1_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART1_TX,
+               .end = IRQ_UART1_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART1_RX,
-               .end = IRQ_UART1_RX+1,
+               .end = IRQ_UART1_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
index 76dbc03..3a92c43 100644 (file)
@@ -496,8 +496,13 @@ static struct resource bfin_uart0_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART0_TX,
+               .end = IRQ_UART0_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART0_RX,
-               .end = IRQ_UART0_RX+1,
+               .end = IRQ_UART0_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
@@ -540,8 +545,13 @@ static struct resource bfin_uart1_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART1_TX,
+               .end = IRQ_UART1_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART1_RX,
-               .end = IRQ_UART1_RX+1,
+               .end = IRQ_UART1_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
index 5da5787..47cadd3 100644 (file)
@@ -238,8 +238,13 @@ static struct resource bfin_uart0_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART0_TX,
+               .end = IRQ_UART0_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART0_RX,
-               .end = IRQ_UART0_RX + 1,
+               .end = IRQ_UART0_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
index b0ec825..18817d5 100644 (file)
@@ -193,8 +193,13 @@ static struct resource bfin_uart0_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART0_TX,
+               .end = IRQ_UART0_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART0_RX,
-               .end = IRQ_UART0_RX + 1,
+               .end = IRQ_UART0_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
index 14f54a3..2c8f30e 100644 (file)
@@ -221,8 +221,13 @@ static struct resource bfin_uart0_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART0_TX,
+               .end = IRQ_UART0_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART0_RX,
-               .end = IRQ_UART0_RX + 1,
+               .end = IRQ_UART0_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
index ecd2801..144556e 100644 (file)
@@ -292,8 +292,13 @@ static struct resource bfin_uart0_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART0_TX,
+               .end = IRQ_UART0_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART0_RX,
-               .end = IRQ_UART0_RX + 1,
+               .end = IRQ_UART0_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
index fbee77f..b597d4e 100644 (file)
@@ -151,8 +151,13 @@ static struct resource bfin_uart0_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART0_TX,
+               .end = IRQ_UART0_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART0_RX,
-               .end = IRQ_UART0_RX + 1,
+               .end = IRQ_UART0_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
index 964a8e5..2afd02e 100644 (file)
@@ -298,8 +298,13 @@ static struct resource bfin_uart0_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART0_TX,
+               .end = IRQ_UART0_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART0_RX,
-               .end = IRQ_UART0_RX + 1,
+               .end = IRQ_UART0_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
index 1471c51..604a430 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #include <linux/device.h>
+#include <linux/export.h>
 #include <linux/etherdevice.h>
 #include <linux/platform_device.h>
 #include <linux/mtd/mtd.h>
@@ -305,8 +306,13 @@ static struct resource bfin_uart0_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART0_TX,
+               .end = IRQ_UART0_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART0_RX,
-               .end = IRQ_UART0_RX+1,
+               .end = IRQ_UART0_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
@@ -366,8 +372,13 @@ static struct resource bfin_uart1_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART1_TX,
+               .end = IRQ_UART1_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART1_RX,
-               .end = IRQ_UART1_RX+1,
+               .end = IRQ_UART1_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
@@ -569,7 +580,6 @@ static struct platform_device bfin_sport1_uart_device = {
 
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
 #include <linux/bfin_mac.h>
-#include <linux/export.h>
 static const unsigned short bfin_mac_peripherals[] = P_MII0;
 
 static struct bfin_phydev_platform_data bfin_phydev_data[] = {
index 47cf37d..d916b46 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/device.h>
 #include <linux/etherdevice.h>
+#include <linux/export.h>
 #include <linux/platform_device.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
@@ -306,8 +307,13 @@ static struct resource bfin_uart0_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART0_TX,
+               .end = IRQ_UART0_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART0_RX,
-               .end = IRQ_UART0_RX+1,
+               .end = IRQ_UART0_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
@@ -349,8 +355,13 @@ static struct resource bfin_uart1_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART1_TX,
+               .end = IRQ_UART1_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART1_RX,
-               .end = IRQ_UART1_RX+1,
+               .end = IRQ_UART1_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
@@ -534,7 +545,6 @@ static struct platform_device bfin_sport1_uart_device = {
 
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
 #include <linux/bfin_mac.h>
-#include <linux/export.h>
 static const unsigned short bfin_mac_peripherals[] = P_MII0;
 
 static struct bfin_phydev_platform_data bfin_phydev_data[] = {
index 33e69e4..5f30722 100644 (file)
@@ -12,6 +12,7 @@
  */
 
 #include <linux/device.h>
+#include <linux/export.h>
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
@@ -49,7 +50,6 @@ static struct platform_device rtc_device = {
 
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
 #include <linux/bfin_mac.h>
-#include <linux/export.h>
 static const unsigned short bfin_mac_peripherals[] = P_RMII0;
 
 static struct bfin_phydev_platform_data bfin_phydev_data[] = {
@@ -237,8 +237,13 @@ static struct resource bfin_uart0_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART0_TX,
+               .end = IRQ_UART0_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART0_RX,
-               .end = IRQ_UART0_RX+1,
+               .end = IRQ_UART0_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
@@ -281,8 +286,13 @@ static struct resource bfin_uart1_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART1_TX,
+               .end   = IRQ_UART1_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART1_RX,
-               .end   = IRQ_UART1_RX+1,
+               .end   = IRQ_UART1_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
index c62f9dc..3901dd0 100644 (file)
@@ -240,8 +240,13 @@ static struct resource bfin_uart0_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART0_TX,
+               .end = IRQ_UART0_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART0_RX,
-               .end = IRQ_UART0_RX+1,
+               .end = IRQ_UART0_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
@@ -283,8 +288,13 @@ static struct resource bfin_uart1_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART1_TX,
+               .end = IRQ_UART1_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART1_RX,
-               .end = IRQ_UART1_RX+1,
+               .end = IRQ_UART1_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
index 3099e91..aebd31c 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <linux/device.h>
 #include <linux/etherdevice.h>
+#include <linux/export.h>
 #include <linux/platform_device.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
@@ -309,8 +310,13 @@ static struct resource bfin_uart0_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART0_TX,
+               .end = IRQ_UART0_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART0_RX,
-               .end = IRQ_UART0_RX+1,
+               .end = IRQ_UART0_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
@@ -352,8 +358,13 @@ static struct resource bfin_uart1_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART1_TX,
+               .end = IRQ_UART1_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART1_RX,
-               .end = IRQ_UART1_RX+1,
+               .end = IRQ_UART1_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
index 27f955d..7fbb0bb 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 #include <linux/device.h>
+#include <linux/export.h>
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
@@ -1566,8 +1567,13 @@ static struct resource bfin_uart0_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART0_TX,
+               .end = IRQ_UART0_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART0_RX,
-               .end = IRQ_UART0_RX+1,
+               .end = IRQ_UART0_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
@@ -1621,8 +1627,13 @@ static struct resource bfin_uart1_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART1_TX,
+               .end = IRQ_UART1_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART1_RX,
-               .end = IRQ_UART1_RX+1,
+               .end = IRQ_UART1_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
@@ -1992,7 +2003,6 @@ static struct adp8870_backlight_platform_data adp8870_pdata = {
 
 #if defined(CONFIG_BACKLIGHT_ADP8860) || defined(CONFIG_BACKLIGHT_ADP8860_MODULE)
 #include <linux/i2c/adp8860.h>
-#include <linux/export.h>
 static struct led_info adp8860_leds[] = {
        {
                .name = "adp8860-led7",
index 8418030..6917ce2 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/device.h>
 #include <linux/etherdevice.h>
+#include <linux/export.h>
 #include <linux/platform_device.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
@@ -306,8 +307,13 @@ static struct resource bfin_uart0_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART0_TX,
+               .end = IRQ_UART0_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART0_RX,
-               .end = IRQ_UART0_RX+1,
+               .end = IRQ_UART0_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
@@ -349,8 +355,13 @@ static struct resource bfin_uart1_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART1_TX,
+               .end = IRQ_UART1_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART1_RX,
-               .end = IRQ_UART1_RX+1,
+               .end = IRQ_UART1_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
@@ -536,7 +547,6 @@ static struct platform_device bfin_sport1_uart_device = {
 
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
 #include <linux/bfin_mac.h>
-#include <linux/export.h>
 static const unsigned short bfin_mac_peripherals[] = P_MII0;
 
 static struct bfin_phydev_platform_data bfin_phydev_data[] = {
index 629f3c3..8356eb5 100644 (file)
@@ -49,8 +49,13 @@ static struct resource bfin_uart0_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART0_TX,
+               .end = IRQ_UART0_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART0_RX,
-               .end = IRQ_UART0_RX+1,
+               .end = IRQ_UART0_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
@@ -104,8 +109,13 @@ static struct resource bfin_uart1_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART1_TX,
+               .end = IRQ_UART1_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART1_RX,
-               .end = IRQ_UART1_RX+1,
+               .end = IRQ_UART1_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
@@ -147,8 +157,13 @@ static struct resource bfin_uart2_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART2_TX,
+               .end = IRQ_UART2_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART2_RX,
-               .end = IRQ_UART2_RX+1,
+               .end = IRQ_UART2_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
index 212b9e0..0350eac 100644 (file)
@@ -135,8 +135,13 @@ static struct resource bfin_uart0_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART0_TX,
+               .end = IRQ_UART0_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART0_RX,
-               .end = IRQ_UART0_RX+1,
+               .end = IRQ_UART0_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
@@ -178,8 +183,13 @@ static struct resource bfin_uart1_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART1_TX,
+               .end = IRQ_UART1_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART1_RX,
-               .end = IRQ_UART1_RX+1,
+               .end = IRQ_UART1_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
@@ -237,8 +247,13 @@ static struct resource bfin_uart2_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART2_TX,
+               .end = IRQ_UART2_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART2_RX,
-               .end = IRQ_UART2_RX+1,
+               .end = IRQ_UART2_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
@@ -280,8 +295,13 @@ static struct resource bfin_uart3_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART3_TX,
+               .end = IRQ_UART3_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART3_RX,
-               .end = IRQ_UART3_RX+1,
+               .end = IRQ_UART3_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
index cd9cbb6..bb868ac 100644 (file)
@@ -241,8 +241,13 @@ static struct resource bfin_uart0_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART0_TX,
+               .end = IRQ_UART0_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART0_RX,
-               .end = IRQ_UART0_RX+1,
+               .end = IRQ_UART0_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
@@ -284,8 +289,13 @@ static struct resource bfin_uart1_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART1_TX,
+               .end = IRQ_UART1_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART1_RX,
-               .end = IRQ_UART1_RX+1,
+               .end = IRQ_UART1_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
@@ -343,8 +353,13 @@ static struct resource bfin_uart2_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART2_TX,
+               .end = IRQ_UART2_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART2_RX,
-               .end = IRQ_UART2_RX+1,
+               .end = IRQ_UART2_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
@@ -386,8 +401,13 @@ static struct resource bfin_uart3_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART3_TX,
+               .end = IRQ_UART3_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART3_RX,
-               .end = IRQ_UART3_RX+1,
+               .end = IRQ_UART3_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
index 972e134..b1b7339 100644 (file)
@@ -203,8 +203,13 @@ static struct resource bfin_uart0_resources[] = {
         .flags = IORESOURCE_MEM,
         },
        {
+        .start = IRQ_UART_TX,
+        .end = IRQ_UART_TX,
+        .flags = IORESOURCE_IRQ,
+        },
+       {
         .start = IRQ_UART_RX,
-        .end = IRQ_UART_RX + 1,
+        .end = IRQ_UART_RX,
         .flags = IORESOURCE_IRQ,
         },
        {
index c1b72f2..c017cf0 100644 (file)
@@ -277,8 +277,13 @@ static struct resource bfin_uart0_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART_TX,
+               .end = IRQ_UART_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART_RX,
-               .end = IRQ_UART_RX+1,
+               .end = IRQ_UART_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
index 9490dc8..27f22ed 100644 (file)
@@ -172,8 +172,13 @@ static struct resource bfin_uart0_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART_TX,
+               .end = IRQ_UART_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART_RX,
-               .end = IRQ_UART_RX+1,
+               .end = IRQ_UART_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
index bb056e6..1a57bc9 100644 (file)
@@ -51,8 +51,13 @@ static struct resource bfin_uart0_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        {
+               .start = IRQ_UART_TX,
+               .end = IRQ_UART_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
                .start = IRQ_UART_RX,
-               .end = IRQ_UART_RX+1,
+               .end = IRQ_UART_RX,
                .flags = IORESOURCE_IRQ,
        },
        {
index 32d9086..5f2cdb3 100644 (file)
@@ -3,7 +3,7 @@ if ETRAX_ARCH_V10
 config ETRAX_ETHERNET
        bool "Ethernet support"
        depends on ETRAX_ARCH_V10
-       select NET_ETHERNET
+       select ETHERNET
        select NET_CORE
        select MII
        help
index e47e9c3..de43aad 100644 (file)
@@ -3,7 +3,7 @@ if ETRAX_ARCH_V32
 config ETRAX_ETHERNET
        bool "Ethernet support"
        depends on ETRAX_ARCH_V32
-       select NET_ETHERNET
+       select ETHERNET
        select NET_CORE
        select MII
        help
index 1a4a619..e269264 100644 (file)
@@ -64,6 +64,9 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #endif /* _ASM_SOCKET_H */
 
 
index a6b2688..ce80fda 100644 (file)
@@ -62,5 +62,8 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #endif /* _ASM_SOCKET_H */
 
index 04c0f45..cf1daab 100644 (file)
@@ -62,4 +62,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #endif /* _ASM_SOCKET_H */
index 51427ea..4b03664 100644 (file)
@@ -71,4 +71,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #endif /* _ASM_IA64_SOCKET_H */
index 469787c..e8b8c5b 100644 (file)
@@ -62,4 +62,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #endif /* _ASM_M32R_SOCKET_H */
index 6c28582..361d540 100644 (file)
@@ -4,8 +4,8 @@ config M68K
        select HAVE_IDE
        select HAVE_AOUT if MMU
        select GENERIC_ATOMIC64 if MMU
-       select HAVE_GENERIC_HARDIRQS if !MMU
-       select GENERIC_IRQ_SHOW if !MMU
+       select HAVE_GENERIC_HARDIRQS
+       select GENERIC_IRQ_SHOW
        select ARCH_HAVE_NMI_SAFE_CMPXCHG if RMW_INSNS
 
 config RWSEM_GENERIC_SPINLOCK
index 8294f0c..3adb499 100644 (file)
@@ -2,6 +2,15 @@ if MMU
 
 comment "Bus Support"
 
+config DIO
+       bool "DIO bus support"
+       depends on HP300
+       default y
+       help
+         Say Y here to enable support for the "DIO" expansion bus used in
+         HP300 machines. If you are using such a system you almost certainly
+         want this.
+
 config NUBUS
        bool
        depends on MAC
index d214034..6033f5d 100644 (file)
@@ -24,6 +24,37 @@ config PROC_HARDWARE
          including the model, CPU, MMU, clock speed, BogoMIPS rating,
          and memory size.
 
+config NATFEAT
+       bool "ARAnyM emulator support"
+       depends on ATARI
+       help
+         This option enables support for ARAnyM native features, such as
+         access to a disk image as /dev/hda.
+
+config NFBLOCK
+       tristate "NatFeat block device support"
+       depends on BLOCK && NATFEAT
+       help
+         Say Y to include support for the ARAnyM NatFeat block device
+         which allows direct access to the hard drives without using
+         the hardware emulation.
+
+config NFCON
+       tristate "NatFeat console driver"
+       depends on NATFEAT
+       help
+         Say Y to include support for the ARAnyM NatFeat console driver
+         which allows the console output to be redirected to the stderr
+         output of ARAnyM.
+
+config NFETH
+       tristate "NatFeat Ethernet support"
+       depends on ETHERNET && NATFEAT
+       help
+         Say Y to include support for the ARAnyM NatFeat network device
+         which will emulate a regular ethernet device while presenting an
+         ethertap device to the host system.
+
 endmenu
 
 menu "Character devices"
index c5b5212..47b5f90 100644 (file)
@@ -1,43 +1,15 @@
 /*
- * linux/arch/m68k/amiga/amiints.c -- Amiga Linux interrupt handling code
+ * Amiga Linux interrupt handling code
  *
  * 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.
- *
- * 11/07/96: rewritten interrupt handling, irq lists are exists now only for
- *           this sources where it makes sense (VERTB/PORTS/EXTER) and you must
- *           be careful that dev_id for this sources is unique since this the
- *           only possibility to distinguish between different handlers for
- *           free_irq. irq lists also have different irq flags:
- *           - IRQ_FLG_FAST: handler is inserted at top of list (after other
- *                           fast handlers)
- *           - IRQ_FLG_SLOW: handler is inserted at bottom of list and before
- *                           they're executed irq level is set to the previous
- *                           one, but handlers don't need to be reentrant, if
- *                           reentrance occurred, slow handlers will be just
- *                           called again.
- *           The whole interrupt handling for CIAs is moved to cia.c
- *           /Roman Zippel
- *
- * 07/08/99: rewamp of the interrupt handling - we now have two types of
- *           interrupts, normal and fast handlers, fast handlers being
- *           marked with IRQF_DISABLED and runs with all other interrupts
- *           disabled. Normal interrupts disable their own source but
- *           run with all other interrupt sources enabled.
- *           PORTS and EXTER interrupts are always shared even if the
- *           drivers do not explicitly mark this when calling
- *           request_irq which they really should do.
- *           This is similar to the way interrupts are handled on all
- *           other architectures and makes a ton of sense besides
- *           having the advantage of making it easier to share
- *           drivers.
- *           /Jes
  */
 
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/errno.h>
+#include <linux/irq.h>
 
 #include <asm/irq.h>
 #include <asm/traps.h>
 #include <asm/amigaints.h>
 #include <asm/amipcmcia.h>
 
-static void amiga_enable_irq(unsigned int irq);
-static void amiga_disable_irq(unsigned int irq);
-static irqreturn_t ami_int1(int irq, void *dev_id);
-static irqreturn_t ami_int3(int irq, void *dev_id);
-static irqreturn_t ami_int4(int irq, void *dev_id);
-static irqreturn_t ami_int5(int irq, void *dev_id);
-
-static struct irq_controller amiga_irq_controller = {
-       .name           = "amiga",
-       .lock           = __SPIN_LOCK_UNLOCKED(amiga_irq_controller.lock),
-       .enable         = amiga_enable_irq,
-       .disable        = amiga_disable_irq,
-};
-
-/*
- * void amiga_init_IRQ(void)
- *
- * Parameters: None
- *
- * Returns:    Nothing
- *
- * This function should be called during kernel startup to initialize
- * the amiga IRQ handling routines.
- */
-
-void __init amiga_init_IRQ(void)
-{
-       if (request_irq(IRQ_AUTO_1, ami_int1, 0, "int1", NULL))
-               pr_err("Couldn't register int%d\n", 1);
-       if (request_irq(IRQ_AUTO_3, ami_int3, 0, "int3", NULL))
-               pr_err("Couldn't register int%d\n", 3);
-       if (request_irq(IRQ_AUTO_4, ami_int4, 0, "int4", NULL))
-               pr_err("Couldn't register int%d\n", 4);
-       if (request_irq(IRQ_AUTO_5, ami_int5, 0, "int5", NULL))
-               pr_err("Couldn't register int%d\n", 5);
-
-       m68k_setup_irq_controller(&amiga_irq_controller, IRQ_USER, AMI_STD_IRQS);
-
-       /* turn off PCMCIA interrupts */
-       if (AMIGAHW_PRESENT(PCMCIA))
-               gayle.inten = GAYLE_IRQ_IDE;
-
-       /* turn off all interrupts and enable the master interrupt bit */
-       amiga_custom.intena = 0x7fff;
-       amiga_custom.intreq = 0x7fff;
-       amiga_custom.intena = IF_SETCLR | IF_INTEN;
-
-       cia_init_IRQ(&ciaa_base);
-       cia_init_IRQ(&ciab_base);
-}
 
 /*
  * Enable/disable a particular machine specific interrupt source.
@@ -103,112 +25,150 @@ void __init amiga_init_IRQ(void)
  * internal data, that may not be changed by the interrupt at the same time.
  */
 
-static void amiga_enable_irq(unsigned int irq)
+static void amiga_irq_enable(struct irq_data *data)
 {
-       amiga_custom.intena = IF_SETCLR | (1 << (irq - IRQ_USER));
+       amiga_custom.intena = IF_SETCLR | (1 << (data->irq - IRQ_USER));
 }
 
-static void amiga_disable_irq(unsigned int irq)
+static void amiga_irq_disable(struct irq_data *data)
 {
-       amiga_custom.intena = 1 << (irq - IRQ_USER);
+       amiga_custom.intena = 1 << (data->irq - IRQ_USER);
 }
 
+static struct irq_chip amiga_irq_chip = {
+       .name           = "amiga",
+       .irq_enable     = amiga_irq_enable,
+       .irq_disable    = amiga_irq_disable,
+};
+
+
 /*
  * The builtin Amiga hardware interrupt handlers.
  */
 
-static irqreturn_t ami_int1(int irq, void *dev_id)
+static void ami_int1(unsigned int irq, struct irq_desc *desc)
 {
        unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
 
        /* if serial transmit buffer empty, interrupt */
        if (ints & IF_TBE) {
                amiga_custom.intreq = IF_TBE;
-               m68k_handle_int(IRQ_AMIGA_TBE);
+               generic_handle_irq(IRQ_AMIGA_TBE);
        }
 
        /* if floppy disk transfer complete, interrupt */
        if (ints & IF_DSKBLK) {
                amiga_custom.intreq = IF_DSKBLK;
-               m68k_handle_int(IRQ_AMIGA_DSKBLK);
+               generic_handle_irq(IRQ_AMIGA_DSKBLK);
        }
 
        /* if software interrupt set, interrupt */
        if (ints & IF_SOFT) {
                amiga_custom.intreq = IF_SOFT;
-               m68k_handle_int(IRQ_AMIGA_SOFT);
+               generic_handle_irq(IRQ_AMIGA_SOFT);
        }
-       return IRQ_HANDLED;
 }
 
-static irqreturn_t ami_int3(int irq, void *dev_id)
+static void ami_int3(unsigned int irq, struct irq_desc *desc)
 {
        unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
 
        /* if a blitter interrupt */
        if (ints & IF_BLIT) {
                amiga_custom.intreq = IF_BLIT;
-               m68k_handle_int(IRQ_AMIGA_BLIT);
+               generic_handle_irq(IRQ_AMIGA_BLIT);
        }
 
        /* if a copper interrupt */
        if (ints & IF_COPER) {
                amiga_custom.intreq = IF_COPER;
-               m68k_handle_int(IRQ_AMIGA_COPPER);
+               generic_handle_irq(IRQ_AMIGA_COPPER);
        }
 
        /* if a vertical blank interrupt */
        if (ints & IF_VERTB) {
                amiga_custom.intreq = IF_VERTB;
-               m68k_handle_int(IRQ_AMIGA_VERTB);
+               generic_handle_irq(IRQ_AMIGA_VERTB);
        }
-       return IRQ_HANDLED;
 }
 
-static irqreturn_t ami_int4(int irq, void *dev_id)
+static void ami_int4(unsigned int irq, struct irq_desc *desc)
 {
        unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
 
        /* if audio 0 interrupt */
        if (ints & IF_AUD0) {
                amiga_custom.intreq = IF_AUD0;
-               m68k_handle_int(IRQ_AMIGA_AUD0);
+               generic_handle_irq(IRQ_AMIGA_AUD0);
        }
 
        /* if audio 1 interrupt */
        if (ints & IF_AUD1) {
                amiga_custom.intreq = IF_AUD1;
-               m68k_handle_int(IRQ_AMIGA_AUD1);
+               generic_handle_irq(IRQ_AMIGA_AUD1);
        }
 
        /* if audio 2 interrupt */
        if (ints & IF_AUD2) {
                amiga_custom.intreq = IF_AUD2;
-               m68k_handle_int(IRQ_AMIGA_AUD2);
+               generic_handle_irq(IRQ_AMIGA_AUD2);
        }
 
        /* if audio 3 interrupt */
        if (ints & IF_AUD3) {
                amiga_custom.intreq = IF_AUD3;
-               m68k_handle_int(IRQ_AMIGA_AUD3);
+               generic_handle_irq(IRQ_AMIGA_AUD3);
        }
-       return IRQ_HANDLED;
 }
 
-static irqreturn_t ami_int5(int irq, void *dev_id)
+static void ami_int5(unsigned int irq, struct irq_desc *desc)
 {
        unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
 
        /* if serial receive buffer full interrupt */
        if (ints & IF_RBF) {
                /* acknowledge of IF_RBF must be done by the serial interrupt */
-               m68k_handle_int(IRQ_AMIGA_RBF);
+               generic_handle_irq(IRQ_AMIGA_RBF);
        }
 
        /* if a disk sync interrupt */
        if (ints & IF_DSKSYN) {
                amiga_custom.intreq = IF_DSKSYN;
-               m68k_handle_int(IRQ_AMIGA_DSKSYN);
+               generic_handle_irq(IRQ_AMIGA_DSKSYN);
        }
-       return IRQ_HANDLED;
+}
+
+
+/*
+ * void amiga_init_IRQ(void)
+ *
+ * Parameters: None
+ *
+ * Returns:    Nothing
+ *
+ * This function should be called during kernel startup to initialize
+ * the amiga IRQ handling routines.
+ */
+
+void __init amiga_init_IRQ(void)
+{
+       m68k_setup_irq_controller(&amiga_irq_chip, handle_simple_irq, IRQ_USER,
+                                 AMI_STD_IRQS);
+
+       irq_set_chained_handler(IRQ_AUTO_1, ami_int1);
+       irq_set_chained_handler(IRQ_AUTO_3, ami_int3);
+       irq_set_chained_handler(IRQ_AUTO_4, ami_int4);
+       irq_set_chained_handler(IRQ_AUTO_5, ami_int5);
+
+       /* turn off PCMCIA interrupts */
+       if (AMIGAHW_PRESENT(PCMCIA))
+               gayle.inten = GAYLE_IRQ_IDE;
+
+       /* turn off all interrupts and enable the master interrupt bit */
+       amiga_custom.intena = 0x7fff;
+       amiga_custom.intreq = 0x7fff;
+       amiga_custom.intena = IF_SETCLR | IF_INTEN;
+
+       cia_init_IRQ(&ciaa_base);
+       cia_init_IRQ(&ciab_base);
 }
index ecd0f7c..18c0e29 100644 (file)
@@ -93,13 +93,14 @@ static irqreturn_t cia_handler(int irq, void *dev_id)
        amiga_custom.intreq = base->int_mask;
        for (; ints; mach_irq++, ints >>= 1) {
                if (ints & 1)
-                       m68k_handle_int(mach_irq);
+                       generic_handle_irq(mach_irq);
        }
        return IRQ_HANDLED;
 }
 
-static void cia_enable_irq(unsigned int irq)
+static void cia_irq_enable(struct irq_data *data)
 {
+       unsigned int irq = data->irq;
        unsigned char mask;
 
        if (irq >= IRQ_AMIGA_CIAB) {
@@ -113,19 +114,20 @@ static void cia_enable_irq(unsigned int irq)
        }
 }
 
-static void cia_disable_irq(unsigned int irq)
+static void cia_irq_disable(struct irq_data *data)
 {
+       unsigned int irq = data->irq;
+
        if (irq >= IRQ_AMIGA_CIAB)
                cia_able_irq(&ciab_base, 1 << (irq - IRQ_AMIGA_CIAB));
        else
                cia_able_irq(&ciaa_base, 1 << (irq - IRQ_AMIGA_CIAA));
 }
 
-static struct irq_controller cia_irq_controller = {
+static struct irq_chip cia_irq_chip = {
        .name           = "cia",
-       .lock           = __SPIN_LOCK_UNLOCKED(cia_irq_controller.lock),
-       .enable         = cia_enable_irq,
-       .disable        = cia_disable_irq,
+       .irq_enable     = cia_irq_enable,
+       .irq_disable    = cia_irq_disable,
 };
 
 /*
@@ -134,9 +136,9 @@ static struct irq_controller cia_irq_controller = {
  * into this chain.
  */
 
-static void auto_enable_irq(unsigned int irq)
+static void auto_irq_enable(struct irq_data *data)
 {
-       switch (irq) {
+       switch (data->irq) {
        case IRQ_AUTO_2:
                amiga_custom.intena = IF_SETCLR | IF_PORTS;
                break;
@@ -146,9 +148,9 @@ static void auto_enable_irq(unsigned int irq)
        }
 }
 
-static void auto_disable_irq(unsigned int irq)
+static void auto_irq_disable(struct irq_data *data)
 {
-       switch (irq) {
+       switch (data->irq) {
        case IRQ_AUTO_2:
                amiga_custom.intena = IF_PORTS;
                break;
@@ -158,24 +160,25 @@ static void auto_disable_irq(unsigned int irq)
        }
 }
 
-static struct irq_controller auto_irq_controller = {
+static struct irq_chip auto_irq_chip = {
        .name           = "auto",
-       .lock           = __SPIN_LOCK_UNLOCKED(auto_irq_controller.lock),
-       .enable         = auto_enable_irq,
-       .disable        = auto_disable_irq,
+       .irq_enable     = auto_irq_enable,
+       .irq_disable    = auto_irq_disable,
 };
 
 void __init cia_init_IRQ(struct ciabase *base)
 {
-       m68k_setup_irq_controller(&cia_irq_controller, base->cia_irq, CIA_IRQS);
+       m68k_setup_irq_controller(&cia_irq_chip, handle_simple_irq,
+                                 base->cia_irq, CIA_IRQS);
 
        /* clear any pending interrupt and turn off all interrupts */
        cia_set_irq(base, CIA_ICR_ALL);
        cia_able_irq(base, CIA_ICR_ALL);
 
        /* override auto int and install CIA handler */
-       m68k_setup_irq_controller(&auto_irq_controller, base->handler_irq, 1);
-       m68k_irq_startup(base->handler_irq);
+       m68k_setup_irq_controller(&auto_irq_chip, handle_simple_irq,
+                                 base->handler_irq, 1);
+       m68k_irq_startup_irq(base->handler_irq);
        if (request_irq(base->handler_irq, cia_handler, IRQF_SHARED,
                        base->name, base))
                pr_err("Couldn't register %s interrupt\n", base->name);
index 5d47f3a..17be1e7 100644 (file)
@@ -1,19 +1,13 @@
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 
-#include <asm/irq.h>
 #include <asm/traps.h>
 #include <asm/apollohw.h>
 
-void dn_process_int(unsigned int irq, struct pt_regs *fp)
+unsigned int apollo_irq_startup(struct irq_data *data)
 {
-       __m68k_handle_int(irq, fp);
+       unsigned int irq = data->irq;
 
-       *(volatile unsigned char *)(pica)=0x20;
-       *(volatile unsigned char *)(picb)=0x20;
-}
-
-int apollo_irq_startup(unsigned int irq)
-{
        if (irq < 8)
                *(volatile unsigned char *)(pica+1) &= ~(1 << irq);
        else
@@ -21,24 +15,33 @@ int apollo_irq_startup(unsigned int irq)
        return 0;
 }
 
-void apollo_irq_shutdown(unsigned int irq)
+void apollo_irq_shutdown(struct irq_data *data)
 {
+       unsigned int irq = data->irq;
+
        if (irq < 8)
                *(volatile unsigned char *)(pica+1) |= (1 << irq);
        else
                *(volatile unsigned char *)(picb+1) |= (1 << (irq - 8));
 }
 
-static struct irq_controller apollo_irq_controller = {
+void apollo_irq_eoi(struct irq_data *data)
+{
+       *(volatile unsigned char *)(pica) = 0x20;
+       *(volatile unsigned char *)(picb) = 0x20;
+}
+
+static struct irq_chip apollo_irq_chip = {
        .name           = "apollo",
-       .lock           = __SPIN_LOCK_UNLOCKED(apollo_irq_controller.lock),
-       .startup        = apollo_irq_startup,
-       .shutdown       = apollo_irq_shutdown,
+       .irq_startup    = apollo_irq_startup,
+       .irq_shutdown   = apollo_irq_shutdown,
+       .irq_eoi        = apollo_irq_eoi,
 };
 
 
 void __init dn_init_IRQ(void)
 {
-       m68k_setup_user_interrupt(VEC_USER + 96, 16, dn_process_int);
-       m68k_setup_irq_controller(&apollo_irq_controller, IRQ_APOLLO, 16);
+       m68k_setup_user_interrupt(VEC_USER + 96, 16);
+       m68k_setup_irq_controller(&apollo_irq_chip, handle_fasteoi_irq,
+                                 IRQ_APOLLO, 16);
 }
index 26a804e..6d196da 100644 (file)
  * <asm/atariints.h>): Autovector interrupts are 1..7, then follow ST-MFP,
  * TT-MFP, SCC, and finally VME interrupts. Vector numbers for the latter can
  * be allocated by atari_register_vme_int().
- *
- * Each interrupt can be of three types:
- *
- *  - SLOW: The handler runs with all interrupts enabled, except the one it
- *    was called by (to avoid reentering). This should be the usual method.
- *    But it is currently possible only for MFP ints, since only the MFP
- *    offers an easy way to mask interrupts.
- *
- *  - FAST: The handler runs with all interrupts disabled. This should be used
- *    only for really fast handlers, that just do actions immediately
- *    necessary, and let the rest do a bottom half or task queue.
- *
- *  - PRIORITIZED: The handler can be interrupted by higher-level ints
- *    (greater IPL, no MFP priorities!). This is the method of choice for ints
- *    which should be slow, but are not from a MFP.
- *
- * The feature of more than one handler for one int source is still there, but
- * only applicable if all handers are of the same type. To not slow down
- * processing of ints with only one handler by the chaining feature, the list
- * calling function atari_call_irq_list() is only plugged in at the time the
- * second handler is registered.
- *
- * Implementation notes: For fast-as-possible int handling, there are separate
- * entry points for each type (slow/fast/prio). The assembler handler calls
- * the irq directly in the usual case, no C wrapper is involved. In case of
- * multiple handlers, atari_call_irq_list() is registered as handler and calls
- * in turn the real irq's. To ease access from assembler level to the irq
- * function pointer and accompanying data, these two are stored in a separate
- * array, irq_handler[]. The rest of data (type, name) are put into a second
- * array, irq_param, that is accessed from C only. For each slow interrupt (32
- * in all) there are separate handler functions, which makes it possible to
- * hard-code the MFP register address and value, are necessary to mask the
- * int. If there'd be only one generic function, lots of calculations would be
- * needed to determine MFP register and int mask from the vector number :-(
- *
- * Furthermore, slow ints may not lower the IPL below its previous value
- * (before the int happened). This is needed so that an int of class PRIO, on
- * that this int may be stacked, cannot be reentered. This feature is
- * implemented as follows: If the stack frame format is 1 (throwaway), the int
- * is not stacked, and the IPL is anded with 0xfbff, resulting in a new level
- * 2, which still blocks the HSYNC, but no interrupts of interest. If the
- * frame format is 0, the int is nested, and the old IPL value can be found in
- * the sr copy in the frame.
- */
-
-#if 0
-
-#define        NUM_INT_SOURCES (8 + NUM_ATARI_SOURCES)
-
-typedef void (*asm_irq_handler)(void);
-
-struct irqhandler {
-       irqreturn_t (*handler)(int, void *, struct pt_regs *);
-       void    *dev_id;
-};
-
-struct irqparam {
-       unsigned long   flags;
-       const char      *devname;
-};
-
-/*
- * Array with irq's and their parameter data. This array is accessed from low
- * level assembler code, so an element size of 8 allows usage of index scaling
- * addressing mode.
  */
-static struct irqhandler irq_handler[NUM_INT_SOURCES];
-
-/*
- * This array hold the rest of parameters of int handlers: type
- * (slow,fast,prio) and the name of the handler. These values are only
- * accessed from C
- */
-static struct irqparam irq_param[NUM_INT_SOURCES];
-
-/* check for valid int number (complex, sigh...) */
-#define        IS_VALID_INTNO(n)                                                                                       \
-       ((n) > 0 &&                                                                                                             \
-        /* autovec and ST-MFP ok anyway */                                                             \
-        (((n) < TTMFP_SOURCE_BASE) ||                                                                  \
-         /* TT-MFP ok if present */                                                                    \
-         ((n) >= TTMFP_SOURCE_BASE && (n) < SCC_SOURCE_BASE &&                 \
-          ATARIHW_PRESENT(TT_MFP)) ||                                                                  \
-         /* SCC ok if present and number even */                                               \
-         ((n) >= SCC_SOURCE_BASE && (n) < VME_SOURCE_BASE &&                   \
-          !((n) & 1) && ATARIHW_PRESENT(SCC)) ||                                               \
-         /* greater numbers ok if they are registered VME vectors */           \
-         ((n) >= VME_SOURCE_BASE && (n) < VME_SOURCE_BASE + VME_MAX_SOURCES && \
-                 free_vme_vec_bitmap & (1 << ((n) - VME_SOURCE_BASE)))))
-
-
-/*
- * Here start the assembler entry points for interrupts
- */
-
-#define IRQ_NAME(nr) atari_slow_irq_##nr##_handler(void)
-
-#define        BUILD_SLOW_IRQ(n)                                                  \
-asmlinkage void IRQ_NAME(n);                                              \
-/* Dummy function to allow asm with operands.  */                         \
-void atari_slow_irq_##n##_dummy (void) {                                  \
-__asm__ (__ALIGN_STR "\n"                                                 \
-"atari_slow_irq_" #n "_handler:\t"                                        \
-"      addl    %6,%5\n"        /* preempt_count() += HARDIRQ_OFFSET */    \
-       SAVE_ALL_INT "\n"                                                  \
-       GET_CURRENT(%%d0) "\n"                                             \
-"      andb    #~(1<<(%c3&7)),%a4:w\n" /* mask this interrupt */          \
-       /* get old IPL from stack frame */                                 \
-"      bfextu  %%sp@(%c2){#5,#3},%%d0\n"                                  \
-"      movew   %%sr,%%d1\n"                                               \
-"      bfins   %%d0,%%d1{#21,#3}\n"                                       \
-"      movew   %%d1,%%sr\n"            /* set IPL = previous value */     \
-"      addql   #1,%a0\n"                                                  \
-"      lea     %a1,%%a0\n"                                                \
-"      pea     %%sp@\n"                /* push addr of frame */           \
-"      movel   %%a0@(4),%%sp@-\n"      /* push handler data */            \
-"      pea     (%c3+8)\n"              /* push int number */              \
-"      movel   %%a0@,%%a0\n"                                              \
-"      jbsr    %%a0@\n"                /* call the handler */             \
-"      addql   #8,%%sp\n"                                                 \
-"      addql   #4,%%sp\n"                                                 \
-"      orw     #0x0600,%%sr\n"                                            \
-"      andw    #0xfeff,%%sr\n"         /* set IPL = 6 again */            \
-"      orb     #(1<<(%c3&7)),%a4:w\n"  /* now unmask the int again */     \
-"      jbra    ret_from_interrupt\n"                                      \
-        : : "i" (&kstat_cpu(0).irqs[n+8]), "i" (&irq_handler[n+8]),       \
-            "n" (PT_OFF_SR), "n" (n),                                     \
-            "i" (n & 8 ? (n & 16 ? &tt_mfp.int_mk_a : &st_mfp.int_mk_a)   \
-                       : (n & 16 ? &tt_mfp.int_mk_b : &st_mfp.int_mk_b)), \
-            "m" (preempt_count()), "di" (HARDIRQ_OFFSET)                  \
-);                                                                        \
-       for (;;);                       /* fake noreturn */                \
-}
-
-BUILD_SLOW_IRQ(0);
-BUILD_SLOW_IRQ(1);
-BUILD_SLOW_IRQ(2);
-BUILD_SLOW_IRQ(3);
-BUILD_SLOW_IRQ(4);
-BUILD_SLOW_IRQ(5);
-BUILD_SLOW_IRQ(6);
-BUILD_SLOW_IRQ(7);
-BUILD_SLOW_IRQ(8);
-BUILD_SLOW_IRQ(9);
-BUILD_SLOW_IRQ(10);
-BUILD_SLOW_IRQ(11);
-BUILD_SLOW_IRQ(12);
-BUILD_SLOW_IRQ(13);
-BUILD_SLOW_IRQ(14);
-BUILD_SLOW_IRQ(15);
-BUILD_SLOW_IRQ(16);
-BUILD_SLOW_IRQ(17);
-BUILD_SLOW_IRQ(18);
-BUILD_SLOW_IRQ(19);
-BUILD_SLOW_IRQ(20);
-BUILD_SLOW_IRQ(21);
-BUILD_SLOW_IRQ(22);
-BUILD_SLOW_IRQ(23);
-BUILD_SLOW_IRQ(24);
-BUILD_SLOW_IRQ(25);
-BUILD_SLOW_IRQ(26);
-BUILD_SLOW_IRQ(27);
-BUILD_SLOW_IRQ(28);
-BUILD_SLOW_IRQ(29);
-BUILD_SLOW_IRQ(30);
-BUILD_SLOW_IRQ(31);
-
-asm_irq_handler slow_handlers[32] = {
-       [0]     = atari_slow_irq_0_handler,
-       [1]     = atari_slow_irq_1_handler,
-       [2]     = atari_slow_irq_2_handler,
-       [3]     = atari_slow_irq_3_handler,
-       [4]     = atari_slow_irq_4_handler,
-       [5]     = atari_slow_irq_5_handler,
-       [6]     = atari_slow_irq_6_handler,
-       [7]     = atari_slow_irq_7_handler,
-       [8]     = atari_slow_irq_8_handler,
-       [9]     = atari_slow_irq_9_handler,
-       [10]    = atari_slow_irq_10_handler,
-       [11]    = atari_slow_irq_11_handler,
-       [12]    = atari_slow_irq_12_handler,
-       [13]    = atari_slow_irq_13_handler,
-       [14]    = atari_slow_irq_14_handler,
-       [15]    = atari_slow_irq_15_handler,
-       [16]    = atari_slow_irq_16_handler,
-       [17]    = atari_slow_irq_17_handler,
-       [18]    = atari_slow_irq_18_handler,
-       [19]    = atari_slow_irq_19_handler,
-       [20]    = atari_slow_irq_20_handler,
-       [21]    = atari_slow_irq_21_handler,
-       [22]    = atari_slow_irq_22_handler,
-       [23]    = atari_slow_irq_23_handler,
-       [24]    = atari_slow_irq_24_handler,
-       [25]    = atari_slow_irq_25_handler,
-       [26]    = atari_slow_irq_26_handler,
-       [27]    = atari_slow_irq_27_handler,
-       [28]    = atari_slow_irq_28_handler,
-       [29]    = atari_slow_irq_29_handler,
-       [30]    = atari_slow_irq_30_handler,
-       [31]    = atari_slow_irq_31_handler
-};
-
-asmlinkage void atari_fast_irq_handler( void );
-asmlinkage void atari_prio_irq_handler( void );
-
-/* Dummy function to allow asm with operands.  */
-void atari_fast_prio_irq_dummy (void) {
-__asm__ (__ALIGN_STR "\n"
-"atari_fast_irq_handler:\n\t"
-       "orw    #0x700,%%sr\n"          /* disable all interrupts */
-"atari_prio_irq_handler:\n\t"
-       "addl   %3,%2\n\t"              /* preempt_count() += HARDIRQ_OFFSET */
-       SAVE_ALL_INT "\n\t"
-       GET_CURRENT(%%d0) "\n\t"
-       /* get vector number from stack frame and convert to source */
-       "bfextu %%sp@(%c1){#4,#10},%%d0\n\t"
-       "subw   #(0x40-8),%%d0\n\t"
-       "jpl    1f\n\t"
-       "addw   #(0x40-8-0x18),%%d0\n"
-    "1:\tlea   %a0,%%a0\n\t"
-       "addql  #1,%%a0@(%%d0:l:4)\n\t"
-       "lea    irq_handler,%%a0\n\t"
-       "lea    %%a0@(%%d0:l:8),%%a0\n\t"
-       "pea    %%sp@\n\t"              /* push frame address */
-       "movel  %%a0@(4),%%sp@-\n\t"    /* push handler data */
-       "movel  %%d0,%%sp@-\n\t"        /* push int number */
-       "movel  %%a0@,%%a0\n\t"
-       "jsr    %%a0@\n\t"              /* and call the handler */
-       "addql  #8,%%sp\n\t"
-       "addql  #4,%%sp\n\t"
-       "jbra   ret_from_interrupt"
-        : : "i" (&kstat_cpu(0).irqs), "n" (PT_OFF_FORMATVEC),
-            "m" (preempt_count()), "di" (HARDIRQ_OFFSET)
-);
-       for (;;);
-}
-#endif
 
 /*
  * Bitmap for free interrupt vector numbers
@@ -320,31 +84,44 @@ extern void atari_microwire_cmd(int cmd);
 
 extern int atari_SCC_reset_done;
 
-static int atari_startup_irq(unsigned int irq)
+static unsigned int atari_irq_startup(struct irq_data *data)
 {
-       m68k_irq_startup(irq);
+       unsigned int irq = data->irq;
+
+       m68k_irq_startup(data);
        atari_turnon_irq(irq);
        atari_enable_irq(irq);
        return 0;
 }
 
-static void atari_shutdown_irq(unsigned int irq)
+static void atari_irq_shutdown(struct irq_data *data)
 {
+       unsigned int irq = data->irq;
+
        atari_disable_irq(irq);
        atari_turnoff_irq(irq);
-       m68k_irq_shutdown(irq);
+       m68k_irq_shutdown(data);
 
        if (irq == IRQ_AUTO_4)
            vectors[VEC_INT4] = falcon_hblhandler;
 }
 
-static struct irq_controller atari_irq_controller = {
+static void atari_irq_enable(struct irq_data *data)
+{
+       atari_enable_irq(data->irq);
+}
+
+static void atari_irq_disable(struct irq_data *data)
+{
+       atari_disable_irq(data->irq);
+}
+
+static struct irq_chip atari_irq_chip = {
        .name           = "atari",
-       .lock           = __SPIN_LOCK_UNLOCKED(atari_irq_controller.lock),
-       .startup        = atari_startup_irq,
-       .shutdown       = atari_shutdown_irq,
-       .enable         = atari_enable_irq,
-       .disable        = atari_disable_irq,
+       .irq_startup    = atari_irq_startup,
+       .irq_shutdown   = atari_irq_shutdown,
+       .irq_enable     = atari_irq_enable,
+       .irq_disable    = atari_irq_disable,
 };
 
 /*
@@ -360,8 +137,9 @@ static struct irq_controller atari_irq_controller = {
 
 void __init atari_init_IRQ(void)
 {
-       m68k_setup_user_interrupt(VEC_USER, NUM_ATARI_SOURCES - IRQ_USER, NULL);
-       m68k_setup_irq_controller(&atari_irq_controller, 1, NUM_ATARI_SOURCES - 1);
+       m68k_setup_user_interrupt(VEC_USER, NUM_ATARI_SOURCES - IRQ_USER);
+       m68k_setup_irq_controller(&atari_irq_chip, handle_simple_irq, 1,
+                                 NUM_ATARI_SOURCES - 1);
 
        /* Initialize the MFP(s) */
 
index 1edd950..8128647 100644 (file)
@@ -86,7 +86,7 @@ static void bvme6000_get_model(char *model)
  */
 static void __init bvme6000_init_IRQ(void)
 {
-       m68k_setup_user_interrupt(VEC_USER, 192, NULL);
+       m68k_setup_user_interrupt(VEC_USER, 192);
 }
 
 void __init config_bvme6000(void)
index f6312c7..c87fe69 100644 (file)
@@ -70,7 +70,7 @@ void __init hp300_sched_init(irq_handler_t vector)
 
   asm volatile(" movpw %0,%1@(5)" : : "d" (INTVAL), "a" (CLOCKBASE));
 
-  if (request_irq(IRQ_AUTO_6, hp300_tick, IRQ_FLG_STD, "timer tick", vector))
+  if (request_irq(IRQ_AUTO_6, hp300_tick, 0, "timer tick", vector))
     pr_err("Couldn't register timer interrupt\n");
 
   out_8(CLOCKBASE + CLKCR2, 0x1);              /* select CR1 */
index 870e534..db30ed2 100644 (file)
 
 #ifdef CONFIG_MMU
 
+static inline void ack_bad_irq(unsigned int irq)
+{
+       pr_crit("unexpected IRQ trap at vector %02x\n", irq);
+}
+
 /* entry.S is sensitive to the offsets of these fields */
 typedef struct {
        unsigned int __softirq_pending;
index 69ed0d7..6198df5 100644 (file)
 
 #ifdef CONFIG_MMU
 
-#include <linux/linkage.h>
-#include <linux/hardirq.h>
-#include <linux/irqreturn.h>
-#include <linux/spinlock_types.h>
-
 /*
  * Interrupt source definitions
  * General interrupt sources are the level 1-7.
 
 #define IRQ_USER       8
 
-extern unsigned int irq_canonicalize(unsigned int irq);
-
-struct pt_regs;
-
 /*
  * various flags for request_irq() - the Amiga now uses the standard
  * mechanism like all other architectures - IRQF_DISABLED and
@@ -71,57 +62,27 @@ struct pt_regs;
 #define IRQ_FLG_STD    (0x8000)        /* internally used              */
 #endif
 
-/*
- * This structure is used to chain together the ISRs for a particular
- * interrupt source (if it supports chaining).
- */
-typedef struct irq_node {
-       irqreturn_t     (*handler)(int, void *);
-       void            *dev_id;
-       struct irq_node *next;
-       unsigned long   flags;
-       const char      *devname;
-} irq_node_t;
-
-/*
- * This structure has only 4 elements for speed reasons
- */
-struct irq_handler {
-       int             (*handler)(int, void *);
-       unsigned long   flags;
-       void            *dev_id;
-       const char      *devname;
-};
-
-struct irq_controller {
-       const char *name;
-       spinlock_t lock;
-       int (*startup)(unsigned int irq);
-       void (*shutdown)(unsigned int irq);
-       void (*enable)(unsigned int irq);
-       void (*disable)(unsigned int irq);
-};
-
-extern int m68k_irq_startup(unsigned int);
-extern void m68k_irq_shutdown(unsigned int);
-
-/*
- * This function returns a new irq_node_t
- */
-extern irq_node_t *new_irq_node(void);
+struct irq_data;
+struct irq_chip;
+struct irq_desc;
+extern unsigned int m68k_irq_startup(struct irq_data *data);
+extern unsigned int m68k_irq_startup_irq(unsigned int irq);
+extern void m68k_irq_shutdown(struct irq_data *data);
+extern void m68k_setup_auto_interrupt(void (*handler)(unsigned int,
+                                                     struct pt_regs *));
+extern void m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt);
+extern void m68k_setup_irq_controller(struct irq_chip *,
+                                     void (*handle)(unsigned int irq,
+                                                    struct irq_desc *desc),
+                                     unsigned int irq, unsigned int cnt);
 
-extern void m68k_setup_auto_interrupt(void (*handler)(unsigned int, struct pt_regs *));
-extern void m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt,
-                                     void (*handler)(unsigned int, struct pt_regs *));
-extern void m68k_setup_irq_controller(struct irq_controller *, unsigned int, unsigned int);
-
-asmlinkage void m68k_handle_int(unsigned int);
-asmlinkage void __m68k_handle_int(unsigned int, struct pt_regs *);
+extern unsigned int irq_canonicalize(unsigned int irq);
 
 #else
 #define irq_canonicalize(irq)  (irq)
 #endif /* CONFIG_MMU */
 
 asmlinkage void do_IRQ(int irq, struct pt_regs *regs);
+extern atomic_t irq_err_count;
 
 #endif /* _M68K_IRQ_H_ */
index c2a1c5e..12ebe43 100644 (file)
@@ -12,6 +12,8 @@ extern void mac_reset(void);
 extern void mac_poweroff(void);
 extern void mac_init_IRQ(void);
 extern int mac_irq_pending(unsigned int);
+extern void mac_irq_enable(struct irq_data *data);
+extern void mac_irq_disable(struct irq_data *data);
 
 /*
  *     Floppy driver magic hook - probably shouldn't be here
index 3d970af..22f12c9 100644 (file)
@@ -24,6 +24,3 @@
 #define Q40_IRQ10_MASK       (1<<5)
 #define Q40_IRQ14_MASK       (1<<6)
 #define Q40_IRQ15_MASK       (1<<7)
-
-extern unsigned long q40_probe_irq_on (void);
-extern int q40_probe_irq_off (unsigned long irqs);
index 9bf49c8..d4708ce 100644 (file)
@@ -62,4 +62,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #endif /* _ASM_SOCKET_H */
index e7f0f2e..c569619 100644 (file)
@@ -6,16 +6,15 @@ extra-$(CONFIG_MMU)   := head.o
 extra-$(CONFIG_SUN3)   := sun3-head.o
 extra-y                        += vmlinux.lds
 
-obj-y  := entry.o m68k_ksyms.o module.o process.o ptrace.o setup.o signal.o \
-          sys_m68k.o syscalltable.o time.o traps.o
+obj-y  := entry.o irq.o m68k_ksyms.o module.o process.o ptrace.o setup.o \
+          signal.o sys_m68k.o syscalltable.o time.o traps.o
 
-obj-$(CONFIG_MMU)      += ints.o devres.o vectors.o
-devres-$(CONFIG_MMU)   = ../../../kernel/irq/devres.o
+obj-$(CONFIG_MMU)      += ints.o vectors.o
 
 ifndef CONFIG_MMU_SUN3
 obj-y                  += dma.o
 endif
 ifndef CONFIG_MMU
-obj-y                  += init_task.o irq.o
+obj-y                  += init_task.o
 endif
 
index bd0ec05..c713f51 100644 (file)
@@ -48,7 +48,7 @@
 .globl sys_fork, sys_clone, sys_vfork
 .globl ret_from_interrupt, bad_interrupt
 .globl auto_irqhandler_fixup
-.globl user_irqvec_fixup, user_irqhandler_fixup
+.globl user_irqvec_fixup
 
 .text
 ENTRY(buserr)
@@ -207,7 +207,7 @@ ENTRY(auto_inthandler)
        movel   %sp,%sp@-
        movel   %d0,%sp@-               |  put vector # on stack
 auto_irqhandler_fixup = . + 2
-       jsr     __m68k_handle_int       |  process the IRQ
+       jsr     do_IRQ                  |  process the IRQ
        addql   #8,%sp                  |  pop parameters off stack
 
 ret_from_interrupt:
@@ -240,8 +240,7 @@ user_irqvec_fixup = . + 2
 
        movel   %sp,%sp@-
        movel   %d0,%sp@-               |  put vector # on stack
-user_irqhandler_fixup = . + 2
-       jsr     __m68k_handle_int       |  process the IRQ
+       jsr     do_IRQ                  |  process the IRQ
        addql   #8,%sp                  |  pop parameters off stack
 
        subqb   #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
index 761ee04..74fefac 100644 (file)
@@ -4,25 +4,6 @@
  * 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.
- *
- * 07/03/96: Timer initialization, and thus mach_sched_init(),
- *           removed from request_irq() and moved to init_time().
- *           We should therefore consider renaming our add_isr() and
- *           remove_isr() to request_irq() and free_irq()
- *           respectively, so they are compliant with the other
- *           architectures.                                     /Jes
- * 11/07/96: Changed all add_/remove_isr() to request_/free_irq() calls.
- *           Removed irq list support, if any machine needs an irq server
- *           it must implement this itself (as it's already done), instead
- *           only default handler are used with mach_default_handler.
- *           request_irq got some flags different from other architectures:
- *           - IRQ_FLG_REPLACE : Replace an existing handler (the default one
- *                               can be replaced without this flag)
- *           - IRQ_FLG_LOCK : handler can't be replaced
- *           There are other machine depending flags, see there
- *           If you want to replace a default handler you should know what
- *           you're doing, since it might handle different other irq sources
- *           which must be served                               /Roman Zippel
  */
 
 #include <linux/module.h>
 #endif
 
 extern u32 auto_irqhandler_fixup[];
-extern u32 user_irqhandler_fixup[];
 extern u16 user_irqvec_fixup[];
 
-/* table for system interrupt handlers */
-static struct irq_node *irq_list[NR_IRQS];
-static struct irq_controller *irq_controller[NR_IRQS];
-static int irq_depth[NR_IRQS];
-
 static int m68k_first_user_vec;
 
-static struct irq_controller auto_irq_controller = {
+static struct irq_chip auto_irq_chip = {
        .name           = "auto",
-       .lock           = __SPIN_LOCK_UNLOCKED(auto_irq_controller.lock),
-       .startup        = m68k_irq_startup,
-       .shutdown       = m68k_irq_shutdown,
+       .irq_startup    = m68k_irq_startup,
+       .irq_shutdown   = m68k_irq_shutdown,
 };
 
-static struct irq_controller user_irq_controller = {
+static struct irq_chip user_irq_chip = {
        .name           = "user",
-       .lock           = __SPIN_LOCK_UNLOCKED(user_irq_controller.lock),
-       .startup        = m68k_irq_startup,
-       .shutdown       = m68k_irq_shutdown,
+       .irq_startup    = m68k_irq_startup,
+       .irq_shutdown   = m68k_irq_shutdown,
 };
 
-#define NUM_IRQ_NODES 100
-static irq_node_t nodes[NUM_IRQ_NODES];
-
 /*
  * void init_IRQ(void)
  *
@@ -96,7 +66,7 @@ void __init init_IRQ(void)
        }
 
        for (i = IRQ_AUTO_1; i <= IRQ_AUTO_7; i++)
-               irq_controller[i] = &auto_irq_controller;
+               irq_set_chip_and_handler(i, &auto_irq_chip, handle_simple_irq);
 
        mach_init_IRQ();
 }
@@ -106,7 +76,7 @@ void __init init_IRQ(void)
  * @handler: called from auto vector interrupts
  *
  * setup the handler to be called from auto vector interrupts instead of the
- * standard __m68k_handle_int(), it will be called with irq numbers in the range
+ * standard do_IRQ(), it will be called with irq numbers in the range
  * from IRQ_AUTO_1 - IRQ_AUTO_7.
  */
 void __init m68k_setup_auto_interrupt(void (*handler)(unsigned int, struct pt_regs *))
@@ -120,217 +90,49 @@ void __init m68k_setup_auto_interrupt(void (*handler)(unsigned int, struct pt_re
  * m68k_setup_user_interrupt
  * @vec: first user vector interrupt to handle
  * @cnt: number of active user vector interrupts
- * @handler: called from user vector interrupts
  *
  * setup user vector interrupts, this includes activating the specified range
  * of interrupts, only then these interrupts can be requested (note: this is
- * different from auto vector interrupts). An optional handler can be installed
- * to be called instead of the default __m68k_handle_int(), it will be called
- * with irq numbers starting from IRQ_USER.
+ * different from auto vector interrupts).
  */
-void __init m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt,
-                                     void (*handler)(unsigned int, struct pt_regs *))
+void __init m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt)
 {
        int i;
 
        BUG_ON(IRQ_USER + cnt > NR_IRQS);
        m68k_first_user_vec = vec;
        for (i = 0; i < cnt; i++)
-               irq_controller[IRQ_USER + i] = &user_irq_controller;
+               irq_set_chip(IRQ_USER + i, &user_irq_chip);
        *user_irqvec_fixup = vec - IRQ_USER;
-       if (handler)
-               *user_irqhandler_fixup = (u32)handler;
        flush_icache();
 }
 
 /**
  * m68k_setup_irq_controller
- * @contr: irq controller which controls specified irq
+ * @chip: irq chip which controls specified irq
+ * @handle: flow handler which handles specified irq
  * @irq: first irq to be managed by the controller
+ * @cnt: number of irqs to be managed by the controller
  *
  * Change the controller for the specified range of irq, which will be used to
  * manage these irq. auto/user irq already have a default controller, which can
  * be changed as well, but the controller probably should use m68k_irq_startup/
  * m68k_irq_shutdown.
  */
-void m68k_setup_irq_controller(struct irq_controller *contr, unsigned int irq,
+void m68k_setup_irq_controller(struct irq_chip *chip,
+                              irq_flow_handler_t handle, unsigned int irq,
                               unsigned int cnt)
 {
        int i;
 
-       for (i = 0; i < cnt; i++)
-               irq_controller[irq + i] = contr;
-}
-
-irq_node_t *new_irq_node(void)
-{
-       irq_node_t *node;
-       short i;
-
-       for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--) {
-               if (!node->handler) {
-                       memset(node, 0, sizeof(*node));
-                       return node;
-               }
+       for (i = 0; i < cnt; i++) {
+               irq_set_chip(irq + i, chip);
+               if (handle)
+                       irq_set_handler(irq + i, handle);
        }
-
-       printk ("new_irq_node: out of nodes\n");
-       return NULL;
 }
 
-int setup_irq(unsigned int irq, struct irq_node *node)
-{
-       struct irq_controller *contr;
-       struct irq_node **prev;
-       unsigned long flags;
-
-       if (irq >= NR_IRQS || !(contr = irq_controller[irq])) {
-               printk("%s: Incorrect IRQ %d from %s\n",
-                      __func__, irq, node->devname);
-               return -ENXIO;
-       }
-
-       spin_lock_irqsave(&contr->lock, flags);
-
-       prev = irq_list + irq;
-       if (*prev) {
-               /* Can't share interrupts unless both agree to */
-               if (!((*prev)->flags & node->flags & IRQF_SHARED)) {
-                       spin_unlock_irqrestore(&contr->lock, flags);
-                       return -EBUSY;
-               }
-               while (*prev)
-                       prev = &(*prev)->next;
-       }
-
-       if (!irq_list[irq]) {
-               if (contr->startup)
-                       contr->startup(irq);
-               else
-                       contr->enable(irq);
-       }
-       node->next = NULL;
-       *prev = node;
-
-       spin_unlock_irqrestore(&contr->lock, flags);
-
-       return 0;
-}
-
-int request_irq(unsigned int irq,
-               irq_handler_t handler,
-               unsigned long flags, const char *devname, void *dev_id)
-{
-       struct irq_node *node;
-       int res;
-
-       node = new_irq_node();
-       if (!node)
-               return -ENOMEM;
-
-       node->handler = handler;
-       node->flags   = flags;
-       node->dev_id  = dev_id;
-       node->devname = devname;
-
-       res = setup_irq(irq, node);
-       if (res)
-               node->handler = NULL;
-
-       return res;
-}
-
-EXPORT_SYMBOL(request_irq);
-
-void free_irq(unsigned int irq, void *dev_id)
-{
-       struct irq_controller *contr;
-       struct irq_node **p, *node;
-       unsigned long flags;
-
-       if (irq >= NR_IRQS || !(contr = irq_controller[irq])) {
-               printk("%s: Incorrect IRQ %d\n", __func__, irq);
-               return;
-       }
-
-       spin_lock_irqsave(&contr->lock, flags);
-
-       p = irq_list + irq;
-       while ((node = *p)) {
-               if (node->dev_id == dev_id)
-                       break;
-               p = &node->next;
-       }
-
-       if (node) {
-               *p = node->next;
-               node->handler = NULL;
-       } else
-               printk("%s: Removing probably wrong IRQ %d\n",
-                      __func__, irq);
-
-       if (!irq_list[irq]) {
-               if (contr->shutdown)
-                       contr->shutdown(irq);
-               else
-                       contr->disable(irq);
-       }
-
-       spin_unlock_irqrestore(&contr->lock, flags);
-}
-
-EXPORT_SYMBOL(free_irq);
-
-void enable_irq(unsigned int irq)
-{
-       struct irq_controller *contr;
-       unsigned long flags;
-
-       if (irq >= NR_IRQS || !(contr = irq_controller[irq])) {
-               printk("%s: Incorrect IRQ %d\n",
-                      __func__, irq);
-               return;
-       }
-
-       spin_lock_irqsave(&contr->lock, flags);
-       if (irq_depth[irq]) {
-               if (!--irq_depth[irq]) {
-                       if (contr->enable)
-                               contr->enable(irq);
-               }
-       } else
-               WARN_ON(1);
-       spin_unlock_irqrestore(&contr->lock, flags);
-}
-
-EXPORT_SYMBOL(enable_irq);
-
-void disable_irq(unsigned int irq)
-{
-       struct irq_controller *contr;
-       unsigned long flags;
-
-       if (irq >= NR_IRQS || !(contr = irq_controller[irq])) {
-               printk("%s: Incorrect IRQ %d\n",
-                      __func__, irq);
-               return;
-       }
-
-       spin_lock_irqsave(&contr->lock, flags);
-       if (!irq_depth[irq]++) {
-               if (contr->disable)
-                       contr->disable(irq);
-       }
-       spin_unlock_irqrestore(&contr->lock, flags);
-}
-
-EXPORT_SYMBOL(disable_irq);
-
-void disable_irq_nosync(unsigned int irq) __attribute__((alias("disable_irq")));
-
-EXPORT_SYMBOL(disable_irq_nosync);
-
-int m68k_irq_startup(unsigned int irq)
+unsigned int m68k_irq_startup_irq(unsigned int irq)
 {
        if (irq <= IRQ_AUTO_7)
                vectors[VEC_SPUR + irq] = auto_inthandler;
@@ -339,41 +141,21 @@ int m68k_irq_startup(unsigned int irq)
        return 0;
 }
 
-void m68k_irq_shutdown(unsigned int irq)
+unsigned int m68k_irq_startup(struct irq_data *data)
 {
-       if (irq <= IRQ_AUTO_7)
-               vectors[VEC_SPUR + irq] = bad_inthandler;
-       else
-               vectors[m68k_first_user_vec + irq - IRQ_USER] = bad_inthandler;
+       return m68k_irq_startup_irq(data->irq);
 }
 
-
-/*
- * Do we need these probe functions on the m68k?
- *
- *  ... may be useful with ISA devices
- */
-unsigned long probe_irq_on (void)
+void m68k_irq_shutdown(struct irq_data *data)
 {
-#ifdef CONFIG_Q40
-       if (MACH_IS_Q40)
-               return q40_probe_irq_on();
-#endif
-       return 0;
-}
+       unsigned int irq = data->irq;
 
-EXPORT_SYMBOL(probe_irq_on);
-
-int probe_irq_off (unsigned long irqs)
-{
-#ifdef CONFIG_Q40
-       if (MACH_IS_Q40)
-               return q40_probe_irq_off(irqs);
-#endif
-       return 0;
+       if (irq <= IRQ_AUTO_7)
+               vectors[VEC_SPUR + irq] = bad_inthandler;
+       else
+               vectors[m68k_first_user_vec + irq - IRQ_USER] = bad_inthandler;
 }
 
-EXPORT_SYMBOL(probe_irq_off);
 
 unsigned int irq_canonicalize(unsigned int irq)
 {
@@ -386,52 +168,9 @@ unsigned int irq_canonicalize(unsigned int irq)
 
 EXPORT_SYMBOL(irq_canonicalize);
 
-asmlinkage void m68k_handle_int(unsigned int irq)
-{
-       struct irq_node *node;
-       kstat_cpu(0).irqs[irq]++;
-       node = irq_list[irq];
-       do {
-               node->handler(irq, node->dev_id);
-               node = node->next;
-       } while (node);
-}
-
-asmlinkage void __m68k_handle_int(unsigned int irq, struct pt_regs *regs)
-{
-       struct pt_regs *old_regs;
-       old_regs = set_irq_regs(regs);
-       m68k_handle_int(irq);
-       set_irq_regs(old_regs);
-}
 
 asmlinkage void handle_badint(struct pt_regs *regs)
 {
-       kstat_cpu(0).irqs[0]++;
-       printk("unexpected interrupt from %u\n", regs->vector);
-}
-
-int show_interrupts(struct seq_file *p, void *v)
-{
-       struct irq_controller *contr;
-       struct irq_node *node;
-       int i = *(loff_t *) v;
-
-       /* autovector interrupts */
-       if (irq_list[i]) {
-               contr = irq_controller[i];
-               node = irq_list[i];
-               seq_printf(p, "%-8s %3u: %10u %s", contr->name, i, kstat_cpu(0).irqs[i], node->devname);
-               while ((node = node->next))
-                       seq_printf(p, ", %s", node->devname);
-               seq_puts(p, "\n");
-       }
-       return 0;
-}
-
-#ifdef CONFIG_PROC_FS
-void init_irq_proc(void)
-{
-       /* Insert /proc/irq driver here */
+       atomic_inc(&irq_err_count);
+       pr_warn("unexpected interrupt from %u\n", regs->vector);
 }
-#endif
index 2a96beb..b403924 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/mm.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/irq.h>
 
 #include <asm/traps.h>
 #include <asm/bootinfo.h>
@@ -20,9 +21,6 @@
 
 /* #define DEBUG_IRQS */
 
-extern void mac_enable_irq(unsigned int);
-extern void mac_disable_irq(unsigned int);
-
 int baboon_present;
 static volatile struct baboon *baboon;
 static unsigned char baboon_disabled;
@@ -53,7 +51,7 @@ void __init baboon_init(void)
  * Baboon interrupt handler. This works a lot like a VIA.
  */
 
-static irqreturn_t baboon_irq(int irq, void *dev_id)
+static void baboon_irq(unsigned int irq, struct irq_desc *desc)
 {
        int irq_bit, irq_num;
        unsigned char events;
@@ -64,15 +62,16 @@ static irqreturn_t baboon_irq(int irq, void *dev_id)
                (uint) baboon->mb_status);
 #endif
 
-       if (!(events = baboon->mb_ifr & 0x07))
-               return IRQ_NONE;
+       events = baboon->mb_ifr & 0x07;
+       if (!events)
+               return;
 
        irq_num = IRQ_BABOON_0;
        irq_bit = 1;
        do {
                if (events & irq_bit) {
                        baboon->mb_ifr &= ~irq_bit;
-                       m68k_handle_int(irq_num);
+                       generic_handle_irq(irq_num);
                }
                irq_bit <<= 1;
                irq_num++;
@@ -82,7 +81,6 @@ static irqreturn_t baboon_irq(int irq, void *dev_id)
        /* for now we need to smash all interrupts */
        baboon->mb_ifr &= ~events;
 #endif
-       return IRQ_HANDLED;
 }
 
 /*
@@ -92,8 +90,7 @@ static irqreturn_t baboon_irq(int irq, void *dev_id)
 void __init baboon_register_interrupts(void)
 {
        baboon_disabled = 0;
-       if (request_irq(IRQ_NUBUS_C, baboon_irq, 0, "baboon", (void *)baboon))
-               pr_err("Couldn't register baboon interrupt\n");
+       irq_set_chained_handler(IRQ_NUBUS_C, baboon_irq);
 }
 
 /*
@@ -111,7 +108,7 @@ void baboon_irq_enable(int irq)
 
        baboon_disabled &= ~(1 << irq_idx);
        if (!baboon_disabled)
-               mac_enable_irq(IRQ_NUBUS_C);
+               mac_irq_enable(irq_get_irq_data(IRQ_NUBUS_C));
 }
 
 void baboon_irq_disable(int irq)
@@ -124,7 +121,7 @@ void baboon_irq_disable(int irq)
 
        baboon_disabled |= 1 << irq_idx;
        if (baboon_disabled)
-               mac_disable_irq(IRQ_NUBUS_C);
+               mac_irq_disable(irq_get_irq_data(IRQ_NUBUS_C));
 }
 
 void baboon_irq_clear(int irq)
index 1ad4e9d..a5462cc 100644 (file)
@@ -305,15 +305,13 @@ void __init iop_register_interrupts(void)
 {
        if (iop_ism_present) {
                if (oss_present) {
-                       if (request_irq(OSS_IRQLEV_IOPISM, iop_ism_irq,
-                                       IRQ_FLG_LOCK, "ISM IOP",
-                                       (void *) IOP_NUM_ISM))
+                       if (request_irq(OSS_IRQLEV_IOPISM, iop_ism_irq, 0,
+                                       "ISM IOP", (void *)IOP_NUM_ISM))
                                pr_err("Couldn't register ISM IOP interrupt\n");
                        oss_irq_enable(IRQ_MAC_ADB);
                } else {
-                       if (request_irq(IRQ_VIA2_0, iop_ism_irq,
-                                       IRQ_FLG_LOCK|IRQ_FLG_FAST, "ISM IOP",
-                                       (void *) IOP_NUM_ISM))
+                       if (request_irq(IRQ_VIA2_0, iop_ism_irq, 0, "ISM IOP",
+                                       (void *)IOP_NUM_ISM))
                                pr_err("Couldn't register ISM IOP interrupt\n");
                }
                if (!iop_alive(iop_base[IOP_NUM_ISM])) {
index f92190c..ba220b7 100644 (file)
@@ -190,14 +190,10 @@ irqreturn_t mac_debug_handler(int, void *);
 
 /* #define DEBUG_MACINTS */
 
-void mac_enable_irq(unsigned int irq);
-void mac_disable_irq(unsigned int irq);
-
-static struct irq_controller mac_irq_controller = {
+static struct irq_chip mac_irq_chip = {
        .name           = "mac",
-       .lock           = __SPIN_LOCK_UNLOCKED(mac_irq_controller.lock),
-       .enable         = mac_enable_irq,
-       .disable        = mac_disable_irq,
+       .irq_enable     = mac_irq_enable,
+       .irq_disable    = mac_irq_disable,
 };
 
 void __init mac_init_IRQ(void)
@@ -205,7 +201,7 @@ void __init mac_init_IRQ(void)
 #ifdef DEBUG_MACINTS
        printk("mac_init_IRQ(): Setting things up...\n");
 #endif
-       m68k_setup_irq_controller(&mac_irq_controller, IRQ_USER,
+       m68k_setup_irq_controller(&mac_irq_chip, handle_simple_irq, IRQ_USER,
                                  NUM_MAC_SOURCES - IRQ_USER);
        /* Make sure the SONIC interrupt is cleared or things get ugly */
 #ifdef SHUTUP_SONIC
@@ -241,16 +237,17 @@ void __init mac_init_IRQ(void)
 }
 
 /*
- *  mac_enable_irq - enable an interrupt source
- * mac_disable_irq - disable an interrupt source
+ *  mac_irq_enable - enable an interrupt source
+ * mac_irq_disable - disable an interrupt source
  *   mac_clear_irq - clears a pending interrupt
- * mac_pending_irq - Returns the pending status of an IRQ (nonzero = pending)
+ * mac_irq_pending - returns the pending status of an IRQ (nonzero = pending)
  *
  * These routines are just dispatchers to the VIA/OSS/PSC routines.
  */
 
-void mac_enable_irq(unsigned int irq)
+void mac_irq_enable(struct irq_data *data)
 {
+       int irq = data->irq;
        int irq_src = IRQ_SRC(irq);
 
        switch(irq_src) {
@@ -283,8 +280,9 @@ void mac_enable_irq(unsigned int irq)
        }
 }
 
-void mac_disable_irq(unsigned int irq)
+void mac_irq_disable(struct irq_data *data)
 {
+       int irq = data->irq;
        int irq_src = IRQ_SRC(irq);
 
        switch(irq_src) {
index a9c0f5a..a4c82da 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/mm.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/irq.h>
 
 #include <asm/bootinfo.h>
 #include <asm/macintosh.h>
 int oss_present;
 volatile struct mac_oss *oss;
 
-static irqreturn_t oss_irq(int, void *);
-static irqreturn_t oss_nubus_irq(int, void *);
-
-extern irqreturn_t via1_irq(int, void *);
+extern void via1_irq(unsigned int irq, struct irq_desc *desc);
 
 /*
  * Initialize the OSS
@@ -60,26 +58,6 @@ void __init oss_init(void)
 }
 
 /*
- * Register the OSS and NuBus interrupt dispatchers.
- */
-
-void __init oss_register_interrupts(void)
-{
-       if (request_irq(OSS_IRQLEV_SCSI, oss_irq, IRQ_FLG_LOCK,
-                       "scsi", (void *) oss))
-               pr_err("Couldn't register %s interrupt\n", "scsi");
-       if (request_irq(OSS_IRQLEV_NUBUS, oss_nubus_irq, IRQ_FLG_LOCK,
-                       "nubus", (void *) oss))
-               pr_err("Couldn't register %s interrupt\n", "nubus");
-       if (request_irq(OSS_IRQLEV_SOUND, oss_irq, IRQ_FLG_LOCK,
-                       "sound", (void *) oss))
-               pr_err("Couldn't register %s interrupt\n", "sound");
-       if (request_irq(OSS_IRQLEV_VIA1, via1_irq, IRQ_FLG_LOCK,
-                       "via1", (void *) via1))
-               pr_err("Couldn't register %s interrupt\n", "via1");
-}
-
-/*
  * Initialize OSS for Nubus access
  */
 
@@ -92,17 +70,17 @@ void __init oss_nubus_init(void)
  * and SCSI; everything else is routed to its own autovector IRQ.
  */
 
-static irqreturn_t oss_irq(int irq, void *dev_id)
+static void oss_irq(unsigned int irq, struct irq_desc *desc)
 {
        int events;
 
        events = oss->irq_pending & (OSS_IP_SOUND|OSS_IP_SCSI);
        if (!events)
-               return IRQ_NONE;
+               return;
 
 #ifdef DEBUG_IRQS
        if ((console_loglevel == 10) && !(events & OSS_IP_SCSI)) {
-               printk("oss_irq: irq %d events = 0x%04X\n", irq,
+               printk("oss_irq: irq %u events = 0x%04X\n", irq,
                        (int) oss->irq_pending);
        }
 #endif
@@ -113,11 +91,10 @@ static irqreturn_t oss_irq(int irq, void *dev_id)
                /* FIXME: call sound handler */
        } else if (events & OSS_IP_SCSI) {
                oss->irq_pending &= ~OSS_IP_SCSI;
-               m68k_handle_int(IRQ_MAC_SCSI);
+               generic_handle_irq(IRQ_MAC_SCSI);
        } else {
                /* FIXME: error check here? */
        }
-       return IRQ_HANDLED;
 }
 
 /*
@@ -126,13 +103,13 @@ static irqreturn_t oss_irq(int irq, void *dev_id)
  * Unlike the VIA/RBV this is on its own autovector interrupt level.
  */
 
-static irqreturn_t oss_nubus_irq(int irq, void *dev_id)
+static void oss_nubus_irq(unsigned int irq, struct irq_desc *desc)
 {
        int events, irq_bit, i;
 
        events = oss->irq_pending & OSS_IP_NUBUS;
        if (!events)
-               return IRQ_NONE;
+               return;
 
 #ifdef DEBUG_NUBUS_INT
        if (console_loglevel > 7) {
@@ -148,10 +125,21 @@ static irqreturn_t oss_nubus_irq(int irq, void *dev_id)
                irq_bit >>= 1;
                if (events & irq_bit) {
                        oss->irq_pending &= ~irq_bit;
-                       m68k_handle_int(NUBUS_SOURCE_BASE + i);
+                       generic_handle_irq(NUBUS_SOURCE_BASE + i);
                }
        } while(events & (irq_bit - 1));
-       return IRQ_HANDLED;
+}
+
+/*
+ * Register the OSS and NuBus interrupt dispatchers.
+ */
+
+void __init oss_register_interrupts(void)
+{
+       irq_set_chained_handler(OSS_IRQLEV_SCSI, oss_irq);
+       irq_set_chained_handler(OSS_IRQLEV_NUBUS, oss_nubus_irq);
+       irq_set_chained_handler(OSS_IRQLEV_SOUND, oss_irq);
+       irq_set_chained_handler(OSS_IRQLEV_VIA1, via1_irq);
 }
 
 /*
index a4c3eb6..e6c2d20 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/mm.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/irq.h>
 
 #include <asm/traps.h>
 #include <asm/bootinfo.h>
@@ -30,8 +31,6 @@
 int psc_present;
 volatile __u8 *psc;
 
-irqreturn_t psc_irq(int, void *);
-
 /*
  * Debugging dump, used in various places to see what's going on.
  */
@@ -112,52 +111,52 @@ void __init psc_init(void)
 }
 
 /*
- * Register the PSC interrupt dispatchers for autovector interrupts 3-6.
- */
-
-void __init psc_register_interrupts(void)
-{
-       if (request_irq(IRQ_AUTO_3, psc_irq, 0, "psc3", (void *) 0x30))
-               pr_err("Couldn't register psc%d interrupt\n", 3);
-       if (request_irq(IRQ_AUTO_4, psc_irq, 0, "psc4", (void *) 0x40))
-               pr_err("Couldn't register psc%d interrupt\n", 4);
-       if (request_irq(IRQ_AUTO_5, psc_irq, 0, "psc5", (void *) 0x50))
-               pr_err("Couldn't register psc%d interrupt\n", 5);
-       if (request_irq(IRQ_AUTO_6, psc_irq, 0, "psc6", (void *) 0x60))
-               pr_err("Couldn't register psc%d interrupt\n", 6);
-}
-
-/*
  * PSC interrupt handler. It's a lot like the VIA interrupt handler.
  */
 
-irqreturn_t psc_irq(int irq, void *dev_id)
+static void psc_irq(unsigned int irq, struct irq_desc *desc)
 {
-       int pIFR        = pIFRbase + ((int) dev_id);
-       int pIER        = pIERbase + ((int) dev_id);
+       unsigned int offset = (unsigned int)irq_desc_get_handler_data(desc);
+       int pIFR        = pIFRbase + offset;
+       int pIER        = pIERbase + offset;
        int irq_num;
        unsigned char irq_bit, events;
 
 #ifdef DEBUG_IRQS
-       printk("psc_irq: irq %d pIFR = 0x%02X pIER = 0x%02X\n",
+       printk("psc_irq: irq %u pIFR = 0x%02X pIER = 0x%02X\n",
                irq, (int) psc_read_byte(pIFR), (int) psc_read_byte(pIER));
 #endif
 
        events = psc_read_byte(pIFR) & psc_read_byte(pIER) & 0xF;
        if (!events)
-               return IRQ_NONE;
+               return;
 
        irq_num = irq << 3;
        irq_bit = 1;
        do {
                if (events & irq_bit) {
                        psc_write_byte(pIFR, irq_bit);
-                       m68k_handle_int(irq_num);
+                       generic_handle_irq(irq_num);
                }
                irq_num++;
                irq_bit <<= 1;
        } while (events >= irq_bit);
-       return IRQ_HANDLED;
+}
+
+/*
+ * Register the PSC interrupt dispatchers for autovector interrupts 3-6.
+ */
+
+void __init psc_register_interrupts(void)
+{
+       irq_set_chained_handler(IRQ_AUTO_3, psc_irq);
+       irq_set_handler_data(IRQ_AUTO_3, (void *)0x30);
+       irq_set_chained_handler(IRQ_AUTO_4, psc_irq);
+       irq_set_handler_data(IRQ_AUTO_4, (void *)0x40);
+       irq_set_chained_handler(IRQ_AUTO_5, psc_irq);
+       irq_set_handler_data(IRQ_AUTO_5, (void *)0x50);
+       irq_set_chained_handler(IRQ_AUTO_6, psc_irq);
+       irq_set_handler_data(IRQ_AUTO_6, (void *)0x60);
 }
 
 void psc_irq_enable(int irq) {
index e71166d..f1600ad 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/irq.h>
 
 #include <asm/bootinfo.h>
 #include <asm/macintosh.h>
@@ -77,9 +78,6 @@ static int gIER,gIFR,gBufA,gBufB;
 static u8 nubus_disabled;
 
 void via_debug_dump(void);
-irqreturn_t via1_irq(int, void *);
-irqreturn_t via2_irq(int, void *);
-irqreturn_t via_nubus_irq(int, void *);
 void via_irq_enable(int irq);
 void via_irq_disable(int irq);
 void via_irq_clear(int irq);
@@ -281,40 +279,11 @@ void __init via_init_clock(irq_handler_t func)
        via1[vT1CL] = MAC_CLOCK_LOW;
        via1[vT1CH] = MAC_CLOCK_HIGH;
 
-       if (request_irq(IRQ_MAC_TIMER_1, func, IRQ_FLG_LOCK, "timer", func))
+       if (request_irq(IRQ_MAC_TIMER_1, func, 0, "timer", func))
                pr_err("Couldn't register %s interrupt\n", "timer");
 }
 
 /*
- * Register the interrupt dispatchers for VIA or RBV machines only.
- */
-
-void __init via_register_interrupts(void)
-{
-       if (via_alt_mapping) {
-               if (request_irq(IRQ_AUTO_1, via1_irq,
-                               IRQ_FLG_LOCK|IRQ_FLG_FAST, "software",
-                               (void *) via1))
-                       pr_err("Couldn't register %s interrupt\n", "software");
-               if (request_irq(IRQ_AUTO_6, via1_irq,
-                               IRQ_FLG_LOCK|IRQ_FLG_FAST, "via1",
-                               (void *) via1))
-                       pr_err("Couldn't register %s interrupt\n", "via1");
-       } else {
-               if (request_irq(IRQ_AUTO_1, via1_irq,
-                               IRQ_FLG_LOCK|IRQ_FLG_FAST, "via1",
-                               (void *) via1))
-                       pr_err("Couldn't register %s interrupt\n", "via1");
-       }
-       if (request_irq(IRQ_AUTO_2, via2_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
-                       "via2", (void *) via2))
-               pr_err("Couldn't register %s interrupt\n", "via2");
-       if (request_irq(IRQ_MAC_NUBUS, via_nubus_irq,
-                       IRQ_FLG_LOCK|IRQ_FLG_FAST, "nubus", (void *) via2))
-               pr_err("Couldn't register %s interrupt\n", "nubus");
-}
-
-/*
  * Debugging dump, used in various places to see what's going on.
  */
 
@@ -446,48 +415,46 @@ void __init via_nubus_init(void)
  * via6522.c :-), disable/pending masks added.
  */
 
-irqreturn_t via1_irq(int irq, void *dev_id)
+void via1_irq(unsigned int irq, struct irq_desc *desc)
 {
        int irq_num;
        unsigned char irq_bit, events;
 
        events = via1[vIFR] & via1[vIER] & 0x7F;
        if (!events)
-               return IRQ_NONE;
+               return;
 
        irq_num = VIA1_SOURCE_BASE;
        irq_bit = 1;
        do {
                if (events & irq_bit) {
                        via1[vIFR] = irq_bit;
-                       m68k_handle_int(irq_num);
+                       generic_handle_irq(irq_num);
                }
                ++irq_num;
                irq_bit <<= 1;
        } while (events >= irq_bit);
-       return IRQ_HANDLED;
 }
 
-irqreturn_t via2_irq(int irq, void *dev_id)
+static void via2_irq(unsigned int irq, struct irq_desc *desc)
 {
        int irq_num;
        unsigned char irq_bit, events;
 
        events = via2[gIFR] & via2[gIER] & 0x7F;
        if (!events)
-               return IRQ_NONE;
+               return;
 
        irq_num = VIA2_SOURCE_BASE;
        irq_bit = 1;
        do {
                if (events & irq_bit) {
                        via2[gIFR] = irq_bit | rbv_clear;
-                       m68k_handle_int(irq_num);
+                       generic_handle_irq(irq_num);
                }
                ++irq_num;
                irq_bit <<= 1;
        } while (events >= irq_bit);
-       return IRQ_HANDLED;
 }
 
 /*
@@ -495,7 +462,7 @@ irqreturn_t via2_irq(int irq, void *dev_id)
  * VIA2 dispatcher as a fast interrupt handler.
  */
 
-irqreturn_t via_nubus_irq(int irq, void *dev_id)
+void via_nubus_irq(unsigned int irq, struct irq_desc *desc)
 {
        int slot_irq;
        unsigned char slot_bit, events;
@@ -506,7 +473,7 @@ irqreturn_t via_nubus_irq(int irq, void *dev_id)
        else
                events &= ~via2[vDirA];
        if (!events)
-               return IRQ_NONE;
+               return;
 
        do {
                slot_irq = IRQ_NUBUS_F;
@@ -514,7 +481,7 @@ irqreturn_t via_nubus_irq(int irq, void *dev_id)
                do {
                        if (events & slot_bit) {
                                events &= ~slot_bit;
-                               m68k_handle_int(slot_irq);
+                               generic_handle_irq(slot_irq);
                        }
                        --slot_irq;
                        slot_bit >>= 1;
@@ -528,7 +495,24 @@ irqreturn_t via_nubus_irq(int irq, void *dev_id)
                else
                        events &= ~via2[vDirA];
        } while (events);
-       return IRQ_HANDLED;
+}
+
+/*
+ * Register the interrupt dispatchers for VIA or RBV machines only.
+ */
+
+void __init via_register_interrupts(void)
+{
+       if (via_alt_mapping) {
+               /* software interrupt */
+               irq_set_chained_handler(IRQ_AUTO_1, via1_irq);
+               /* via1 interrupt */
+               irq_set_chained_handler(IRQ_AUTO_6, via1_irq);
+       } else {
+               irq_set_chained_handler(IRQ_AUTO_1, via1_irq);
+       }
+       irq_set_chained_handler(IRQ_AUTO_2, via2_irq);
+       irq_set_chained_handler(IRQ_MAC_NUBUS, via_nubus_irq);
 }
 
 void via_irq_enable(int irq) {
index 6cb9c3a..5de924e 100644 (file)
@@ -81,7 +81,7 @@ static void mvme147_get_model(char *model)
 
 void __init mvme147_init_IRQ(void)
 {
-       m68k_setup_user_interrupt(VEC_USER, 192, NULL);
+       m68k_setup_user_interrupt(VEC_USER, 192);
 }
 
 void __init config_mvme147(void)
@@ -114,8 +114,7 @@ static irqreturn_t mvme147_timer_int (int irq, void *dev_id)
 void mvme147_sched_init (irq_handler_t timer_routine)
 {
        tick_handler = timer_routine;
-       if (request_irq(PCC_IRQ_TIMER1, mvme147_timer_int, IRQ_FLG_REPLACE,
-                       "timer 1", NULL))
+       if (request_irq(PCC_IRQ_TIMER1, mvme147_timer_int, 0, "timer 1", NULL))
                pr_err("Couldn't register timer interrupt\n");
 
        /* Init the clock with a value */
index 0b28e26..31a66d9 100644 (file)
@@ -117,7 +117,7 @@ static void mvme16x_get_hardware_list(struct seq_file *m)
 
 static void __init mvme16x_init_IRQ (void)
 {
-       m68k_setup_user_interrupt(VEC_USER, 192, NULL);
+       m68k_setup_user_interrupt(VEC_USER, 192);
 }
 
 #define pcc2chip       ((volatile u_char *)0xfff42000)
index 9f0e3d5..2b88849 100644 (file)
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 
 #include <asm/ptrace.h>
 #include <asm/system.h>
-#include <asm/irq.h>
 #include <asm/traps.h>
 
 #include <asm/q40_master.h>
 */
 
 static void q40_irq_handler(unsigned int, struct pt_regs *fp);
-static void q40_enable_irq(unsigned int);
-static void q40_disable_irq(unsigned int);
+static void q40_irq_enable(struct irq_data *data);
+static void q40_irq_disable(struct irq_data *data);
 
 unsigned short q40_ablecount[35];
 unsigned short q40_state[35];
 
-static int q40_irq_startup(unsigned int irq)
+static unsigned int q40_irq_startup(struct irq_data *data)
 {
+       unsigned int irq = data->irq;
+
        /* test for ISA ints not implemented by HW */
        switch (irq) {
        case 1: case 2: case 8: case 9:
        case 11: case 12: case 13:
                printk("%s: ISA IRQ %d not implemented by HW\n", __func__, irq);
-               return -ENXIO;
+               /* FIXME return -ENXIO; */
        }
        return 0;
 }
 
-static void q40_irq_shutdown(unsigned int irq)
+static void q40_irq_shutdown(struct irq_data *data)
 {
 }
 
-static struct irq_controller q40_irq_controller = {
+static struct irq_chip q40_irq_chip = {
        .name           = "q40",
-       .lock           = __SPIN_LOCK_UNLOCKED(q40_irq_controller.lock),
-       .startup        = q40_irq_startup,
-       .shutdown       = q40_irq_shutdown,
-       .enable         = q40_enable_irq,
-       .disable        = q40_disable_irq,
+       .irq_startup    = q40_irq_startup,
+       .irq_shutdown   = q40_irq_shutdown,
+       .irq_enable     = q40_irq_enable,
+       .irq_disable    = q40_irq_disable,
 };
 
 /*
@@ -81,13 +82,14 @@ static int disabled;
 
 void __init q40_init_IRQ(void)
 {
-       m68k_setup_irq_controller(&q40_irq_controller, 1, Q40_IRQ_MAX);
+       m68k_setup_irq_controller(&q40_irq_chip, handle_simple_irq, 1,
+                                 Q40_IRQ_MAX);
 
        /* setup handler for ISA ints */
        m68k_setup_auto_interrupt(q40_irq_handler);
 
-       m68k_irq_startup(IRQ_AUTO_2);
-       m68k_irq_startup(IRQ_AUTO_4);
+       m68k_irq_startup_irq(IRQ_AUTO_2);
+       m68k_irq_startup_irq(IRQ_AUTO_4);
 
        /* now enable some ints.. */
        master_outb(1, EXT_ENABLE_REG);  /* ISA IRQ 5-15 */
@@ -218,11 +220,11 @@ static void q40_irq_handler(unsigned int irq, struct pt_regs *fp)
        switch (irq) {
        case 4:
        case 6:
-               __m68k_handle_int(Q40_IRQ_SAMPLE, fp);
+               do_IRQ(Q40_IRQ_SAMPLE, fp);
                return;
        }
        if (mir & Q40_IRQ_FRAME_MASK) {
-               __m68k_handle_int(Q40_IRQ_FRAME, fp);
+               do_IRQ(Q40_IRQ_FRAME, fp);
                master_outb(-1, FRAME_CLEAR_REG);
        }
        if ((mir & Q40_IRQ_SER_MASK) || (mir & Q40_IRQ_EXT_MASK)) {
@@ -257,7 +259,7 @@ static void q40_irq_handler(unsigned int irq, struct pt_regs *fp)
                                        goto iirq;
                                }
                                q40_state[irq] |= IRQ_INPROGRESS;
-                               __m68k_handle_int(irq, fp);
+                               do_IRQ(irq, fp);
                                q40_state[irq] &= ~IRQ_INPROGRESS;
 
                                /* naively enable everything, if that fails than    */
@@ -288,25 +290,29 @@ static void q40_irq_handler(unsigned int irq, struct pt_regs *fp)
        mir = master_inb(IIRQ_REG);
        /* should test whether keyboard irq is really enabled, doing it in defhand */
        if (mir & Q40_IRQ_KEYB_MASK)
-               __m68k_handle_int(Q40_IRQ_KEYBOARD, fp);
+               do_IRQ(Q40_IRQ_KEYBOARD, fp);
 
        return;
 }
 
-void q40_enable_irq(unsigned int irq)
+void q40_irq_enable(struct irq_data *data)
 {
+       unsigned int irq = data->irq;
+
        if (irq >= 5 && irq <= 15) {
                mext_disabled--;
                if (mext_disabled > 0)
-                       printk("q40_enable_irq : nested disable/enable\n");
+                       printk("q40_irq_enable : nested disable/enable\n");
                if (mext_disabled == 0)
                        master_outb(1, EXT_ENABLE_REG);
        }
 }
 
 
-void q40_disable_irq(unsigned int irq)
+void q40_irq_disable(struct irq_data *data)
 {
+       unsigned int irq = data->irq;
+
        /* disable ISA iqs : only do something if the driver has been
         * verified to be Q40 "compatible" - right now IDE, NE2K
         * Any driver should not attempt to sleep across disable_irq !!
@@ -319,13 +325,3 @@ void q40_disable_irq(unsigned int irq)
                        printk("disable_irq nesting count %d\n",mext_disabled);
        }
 }
-
-unsigned long q40_probe_irq_on(void)
-{
-       printk("irq probing not working - reconfigure the driver to avoid this\n");
-       return -1;
-}
-int q40_probe_irq_off(unsigned long irqs)
-{
-       return -1;
-}
index 6464ad3..78b60f5 100644 (file)
@@ -51,25 +51,29 @@ void sun3_disable_irq(unsigned int irq)
 
 static irqreturn_t sun3_int7(int irq, void *dev_id)
 {
-       *sun3_intreg |=  (1 << irq);
-       if (!(kstat_cpu(0).irqs[irq] % 2000))
-               sun3_leds(led_pattern[(kstat_cpu(0).irqs[irq] % 16000) / 2000]);
+       unsigned int cnt;
+
+       cnt = kstat_irqs_cpu(irq, 0);
+       if (!(cnt % 2000))
+               sun3_leds(led_pattern[cnt % 16000 / 2000]);
        return IRQ_HANDLED;
 }
 
 static irqreturn_t sun3_int5(int irq, void *dev_id)
 {
+       unsigned int cnt;
+
 #ifdef CONFIG_SUN3
        intersil_clear();
 #endif
-        *sun3_intreg |=  (1 << irq);
 #ifdef CONFIG_SUN3
        intersil_clear();
 #endif
        xtime_update(1);
        update_process_times(user_mode(get_irq_regs()));
-        if (!(kstat_cpu(0).irqs[irq] % 20))
-                sun3_leds(led_pattern[(kstat_cpu(0).irqs[irq] % 160) / 20]);
+       cnt = kstat_irqs_cpu(irq, 0);
+       if (!(cnt % 20))
+               sun3_leds(led_pattern[cnt % 160 / 20]);
        return IRQ_HANDLED;
 }
 
@@ -79,29 +83,33 @@ static irqreturn_t sun3_vec255(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static void sun3_inthandle(unsigned int irq, struct pt_regs *fp)
+static void sun3_irq_enable(struct irq_data *data)
 {
-        *sun3_intreg &= ~(1 << irq);
+    sun3_enable_irq(data->irq);
+};
 
-       __m68k_handle_int(irq, fp);
-}
+static void sun3_irq_disable(struct irq_data *data)
+{
+    sun3_disable_irq(data->irq);
+};
 
-static struct irq_controller sun3_irq_controller = {
+static struct irq_chip sun3_irq_chip = {
        .name           = "sun3",
-       .lock           = __SPIN_LOCK_UNLOCKED(sun3_irq_controller.lock),
-       .startup        = m68k_irq_startup,
-       .shutdown       = m68k_irq_shutdown,
-       .enable         = sun3_enable_irq,
-       .disable        = sun3_disable_irq,
+       .irq_startup    = m68k_irq_startup,
+       .irq_shutdown   = m68k_irq_shutdown,
+       .irq_enable     = sun3_irq_enable,
+       .irq_disable    = sun3_irq_disable,
+       .irq_mask       = sun3_irq_disable,
+       .irq_unmask     = sun3_irq_enable,
 };
 
 void __init sun3_init_IRQ(void)
 {
        *sun3_intreg = 1;
 
-       m68k_setup_auto_interrupt(sun3_inthandle);
-       m68k_setup_irq_controller(&sun3_irq_controller, IRQ_AUTO_1, 7);
-       m68k_setup_user_interrupt(VEC_USER, 128, NULL);
+       m68k_setup_irq_controller(&sun3_irq_chip, handle_level_irq, IRQ_AUTO_1,
+                                 7);
+       m68k_setup_user_interrupt(VEC_USER, 128);
 
        if (request_irq(IRQ_AUTO_5, sun3_int5, 0, "int5", NULL))
                pr_err("Couldn't register %s interrupt\n", "int5");
index 9b4cb00..0be3186 100644 (file)
@@ -286,11 +286,11 @@ CLEAN_FILES += vmlinux.32 vmlinux.64
 archprepare:
 ifdef CONFIG_MIPS32_N32
        @echo '  Checking missing-syscalls for N32'
-       $(Q)$(MAKE) $(build)=. missing-syscalls ccflags-y="-mabi=n32"
+       $(Q)$(MAKE) $(build)=. missing-syscalls missing_syscalls_flags="-mabi=n32"
 endif
 ifdef CONFIG_MIPS32_O32
        @echo '  Checking missing-syscalls for O32'
-       $(Q)$(MAKE) $(build)=. missing-syscalls ccflags-y="-mabi=32"
+       $(Q)$(MAKE) $(build)=. missing-syscalls missing_syscalls_flags="-mabi=32"
 endif
 
 install:
index 975c203..0a430e0 100644 (file)
@@ -17,8 +17,6 @@
 
 static struct map_info flash_map;
 static struct mtd_info *mymtd;
-static int nr_parts;
-static struct mtd_partition *parts;
 static const char *part_probe_types[] = {
        "cmdlinepart",
 #ifdef CONFIG_MTD_REDBOOT_PARTS
@@ -61,11 +59,8 @@ static int __init flash_init(void)
                mymtd = do_map_probe("cfi_probe", &flash_map);
                if (mymtd) {
                        mymtd->owner = THIS_MODULE;
-
-                       nr_parts = parse_mtd_partitions(mymtd,
-                                                       part_probe_types,
-                                                       &parts, 0);
-                       mtd_device_register(mymtd, parts, nr_parts);
+                       mtd_device_parse_register(mymtd, part_probe_types,
+                                                 0, NULL, 0);
                } else {
                        pr_err("Failed to register MTD device for flash\n");
                }
index 8b60642..efcfff4 100644 (file)
@@ -207,8 +207,9 @@ void octeon_prepare_cpus(unsigned int max_cpus)
         * the other bits alone.
         */
        cvmx_write_csr(CVMX_CIU_MBOX_CLRX(cvmx_get_core_num()), 0xffff);
-       if (request_irq(OCTEON_IRQ_MBOX0, mailbox_interrupt, IRQF_DISABLED,
-                       "SMP-IPI", mailbox_interrupt)) {
+       if (request_irq(OCTEON_IRQ_MBOX0, mailbox_interrupt,
+                       IRQF_PERCPU | IRQF_NO_THREAD, "SMP-IPI",
+                       mailbox_interrupt)) {
                panic("Cannot request_irq(OCTEON_IRQ_MBOX0)\n");
        }
 }
index 708f087..cae4225 100644 (file)
@@ -50,7 +50,7 @@ void __init prom_init(void)
 
        /* arg[0] is "g", the rest is boot parameters */
        for (i = 1; i < argc; i++) {
-               if (strlen(arcs_cmdline) + strlen(arg[i] + 1)
+               if (strlen(arcs_cmdline) + strlen(arg[i]) + 1
                    >= sizeof(arcs_cmdline))
                        break;
                strcat(arcs_cmdline, arg[i]);
index 76961ca..2ef17e8 100644 (file)
@@ -36,6 +36,8 @@ static inline int gpio_get_value(unsigned gpio)
        return -EINVAL;
 }
 
+#define gpio_get_value_cansleep        gpio_get_value
+
 static inline void gpio_set_value(unsigned gpio, int value)
 {
        switch (bcm47xx_bus_type) {
@@ -54,6 +56,19 @@ static inline void gpio_set_value(unsigned gpio, int value)
        }
 }
 
+#define gpio_set_value_cansleep gpio_set_value
+
+static inline int gpio_cansleep(unsigned gpio)
+{
+       return 0;
+}
+
+static inline int gpio_is_valid(unsigned gpio)
+{
+       return gpio < (BCM47XX_EXTIF_GPIO_LINES + BCM47XX_CHIPCO_GPIO_LINES);
+}
+
+
 static inline int gpio_direction_input(unsigned gpio)
 {
        switch (bcm47xx_bus_type) {
@@ -137,7 +152,4 @@ static inline int gpio_polarity(unsigned gpio, int value)
 }
 
 
-/* cansleep wrappers */
-#include <asm-generic/gpio.h>
-
 #endif /* __BCM47XX_GPIO_H */
index 9de5190..ad5c0a7 100644 (file)
@@ -82,6 +82,9 @@ To add: #define SO_REUSEPORT 0x0200   /* Allow local address and port reuse.  */
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #ifdef __KERNEL__
 
 /** sock_type - Socket types
index ecea787..d8dad53 100644 (file)
 #define __NR_syncfs                    (__NR_Linux + 342)
 #define __NR_sendmmsg                  (__NR_Linux + 343)
 #define __NR_setns                     (__NR_Linux + 344)
+#define __NR_process_vm_readv          (__NR_Linux + 345)
+#define __NR_process_vm_writev         (__NR_Linux + 346)
 
 /*
  * Offset of the last Linux o32 flavoured syscall
  */
-#define __NR_Linux_syscalls            344
+#define __NR_Linux_syscalls            346
 
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
 
 #define __NR_O32_Linux                 4000
-#define __NR_O32_Linux_syscalls                344
+#define __NR_O32_Linux_syscalls                346
 
 #if _MIPS_SIM == _MIPS_SIM_ABI64
 
 #define __NR_syncfs                    (__NR_Linux + 301)
 #define __NR_sendmmsg                  (__NR_Linux + 302)
 #define __NR_setns                     (__NR_Linux + 303)
+#define __NR_process_vm_readv          (__NR_Linux + 304)
+#define __NR_process_vm_writev         (__NR_Linux + 305)
 
 /*
  * Offset of the last Linux 64-bit flavoured syscall
  */
-#define __NR_Linux_syscalls            303
+#define __NR_Linux_syscalls            305
 
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */
 
 #define __NR_64_Linux                  5000
-#define __NR_64_Linux_syscalls         303
+#define __NR_64_Linux_syscalls         305
 
 #if _MIPS_SIM == _MIPS_SIM_NABI32
 
 #define __NR_syncfs                    (__NR_Linux + 306)
 #define __NR_sendmmsg                  (__NR_Linux + 307)
 #define __NR_setns                     (__NR_Linux + 308)
+#define __NR_process_vm_readv          (__NR_Linux + 309)
+#define __NR_process_vm_writev         (__NR_Linux + 310)
 
 /*
  * Offset of the last N32 flavoured syscall
  */
-#define __NR_Linux_syscalls            308
+#define __NR_Linux_syscalls            310
 
 #endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */
 
 #define __NR_N32_Linux                 6000
-#define __NR_N32_Linux_syscalls                308
+#define __NR_N32_Linux_syscalls                310
 
 #ifdef __KERNEL__
 
index 98c5a97..e2d8e19 100644 (file)
@@ -103,19 +103,10 @@ static int c0_compare_int_pending(void)
 
 /*
  * Compare interrupt can be routed and latched outside the core,
- * so a single execution hazard barrier may not be enough to give
- * it time to clear as seen in the Cause register.  4 time the
- * pipeline depth seems reasonably conservative, and empirically
- * works better in configurations with high CPU/bus clock ratios.
+ * so wait up to worst case number of cycle counter ticks for timer interrupt
+ * changes to propagate to the cause register.
  */
-
-#define compare_change_hazard() \
-       do { \
-               irq_disable_hazard(); \
-               irq_disable_hazard(); \
-               irq_disable_hazard(); \
-               irq_disable_hazard(); \
-       } while (0)
+#define COMPARE_INT_SEEN_TICKS 50
 
 int c0_compare_int_usable(void)
 {
@@ -126,8 +117,12 @@ int c0_compare_int_usable(void)
         * IP7 already pending?  Try to clear it by acking the timer.
         */
        if (c0_compare_int_pending()) {
-               write_c0_compare(read_c0_count());
-               compare_change_hazard();
+               cnt = read_c0_count();
+               write_c0_compare(cnt);
+               back_to_back_c0_hazard();
+               while (read_c0_count() < (cnt  + COMPARE_INT_SEEN_TICKS))
+                       if (!c0_compare_int_pending())
+                               break;
                if (c0_compare_int_pending())
                        return 0;
        }
@@ -136,7 +131,7 @@ int c0_compare_int_usable(void)
                cnt = read_c0_count();
                cnt += delta;
                write_c0_compare(cnt);
-               compare_change_hazard();
+               back_to_back_c0_hazard();
                if ((int)(read_c0_count() - cnt) < 0)
                    break;
                /* increase delta if the timer was already expired */
@@ -145,12 +140,17 @@ int c0_compare_int_usable(void)
        while ((int)(read_c0_count() - cnt) <= 0)
                ;       /* Wait for expiry  */
 
-       compare_change_hazard();
+       while (read_c0_count() < (cnt + COMPARE_INT_SEEN_TICKS))
+               if (c0_compare_int_pending())
+                       break;
        if (!c0_compare_int_pending())
                return 0;
-
-       write_c0_compare(read_c0_count());
-       compare_change_hazard();
+       cnt = read_c0_count();
+       write_c0_compare(cnt);
+       back_to_back_c0_hazard();
+       while (read_c0_count() < (cnt + COMPARE_INT_SEEN_TICKS))
+               if (!c0_compare_int_pending())
+                       break;
        if (c0_compare_int_pending())
                return 0;
 
index cefc6e2..5426779 100644 (file)
@@ -7,6 +7,7 @@
  * for more details.
  */
 
+#include <linux/module.h>
 #include <linux/cpufreq.h>
 #include <linux/platform_device.h>
 
index 4792065..a632bc1 100644 (file)
@@ -591,6 +591,8 @@ einval:     li      v0, -ENOSYS
        sys     sys_syncfs              1
        sys     sys_sendmmsg            4
        sys     sys_setns               2
+       sys     sys_process_vm_readv    6       /* 4345 */
+       sys     sys_process_vm_writev   6
        .endm
 
        /* We pre-compute the number of _instruction_ bytes needed to
index fb7334b..3b5a5e9 100644 (file)
@@ -430,4 +430,6 @@ sys_call_table:
        PTR     sys_syncfs
        PTR     sys_sendmmsg
        PTR     sys_setns
+       PTR     sys_process_vm_readv
+       PTR     sys_process_vm_writev           /* 5305 */
        .size   sys_call_table,.-sys_call_table
index 6de1f59..6be6f70 100644 (file)
@@ -430,4 +430,6 @@ EXPORT(sysn32_call_table)
        PTR     sys_syncfs
        PTR     compat_sys_sendmmsg
        PTR     sys_setns
+       PTR     compat_sys_process_vm_readv
+       PTR     compat_sys_process_vm_writev    /* 6310 */
        .size   sysn32_call_table,.-sysn32_call_table
index 1d81316..5422855 100644 (file)
@@ -548,4 +548,6 @@ sys_call_table:
        PTR     sys_syncfs
        PTR     compat_sys_sendmmsg
        PTR     sys_setns
+       PTR     compat_sys_process_vm_readv     /* 4345 */
+       PTR     compat_sys_process_vm_writev
        .size   sys_call_table,.-sys_call_table
index 261ccbc..5c8a49d 100644 (file)
@@ -1596,7 +1596,8 @@ void __cpuinit per_cpu_trap_init(void)
        }
 #endif /* CONFIG_MIPS_MT_SMTC */
 
-       cpu_data[cpu].asid_cache = ASID_FIRST_VERSION;
+       if (!cpu_data[cpu].asid_cache)
+               cpu_data[cpu].asid_cache = ASID_FIRST_VERSION;
 
        atomic_inc(&init_mm.mm_count);
        current->active_mm = &init_mm;
index 7e9c0ff..77ed70f 100644 (file)
@@ -7,7 +7,7 @@
  * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
  */
 #include <linux/io.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
index 44a3677..de1cb2b 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #include <linux/init.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
index 56ba007..e34fcfd 100644 (file)
@@ -6,7 +6,7 @@
  * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/clk.h>
 #include <asm/bootinfo.h>
 #include <asm/time.h>
index 9b8af77..1ff6c9d 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/io.h>
 #include <linux/ioport.h>
 #include <asm/bootinfo.h>
index 22d823a..6522583 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #include <linux/io.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/init.h>
 #include <linux/clk.h>
 
index ddd3959..696b1a3 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #include <linux/io.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/init.h>
 #include <linux/clk.h>
 
index d0e32ab..d614aa7 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #include <linux/init.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/mtd/physmap.h>
index 4278a45..cbb6ae5 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/dma-mapping.h>
+#include <linux/export.h>
 
 #include <lantiq_soc.h>
 #include <xway_dma.h>
index a321451..d2fa98f 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #include <linux/slab.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
 #include <linux/ioport.h>
index a479355..b91c7f1 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #include <linux/init.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/types.h>
 #include <linux/platform_device.h>
 #include <linux/mutex.h>
index 67d59d6..ff9991c 100644 (file)
@@ -9,7 +9,7 @@
 
 #include <linux/slab.h>
 #include <linux/init.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/types.h>
 #include <linux/platform_device.h>
 #include <linux/mutex.h>
index abe49f4..ae4959a 100644 (file)
@@ -6,7 +6,7 @@
  *  Copyright (C) 2010 John Crispin <blogic@openwrt.org>
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/clk.h>
 #include <asm/bootinfo.h>
 #include <asm/time.h>
index 1686692..2228133 100644 (file)
@@ -6,7 +6,7 @@
  *  Copyright (C) 2010 John Crispin <blogic@openwrt.org>
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/clk.h>
 #include <asm/bootinfo.h>
 #include <asm/time.h>
index a1be36d..3d41f0b 100644 (file)
@@ -10,7 +10,7 @@
 #include <linux/io.h>
 #include <linux/ioport.h>
 #include <linux/pm.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <asm/reboot.h>
 
 #include <lantiq_soc.h>
diff --git a/arch/mips/nxp/pnx8550/common/pci.c b/arch/mips/nxp/pnx8550/common/pci.c
deleted file mode 100644 (file)
index 98e86dd..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- *
- * BRIEF MODULE DESCRIPTION
- *
- * Author: source@mvista.com
- *
- *  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/types.h>
-#include <linux/pci.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <pci.h>
-#include <glb.h>
-#include <nand.h>
-
-static struct resource pci_io_resource = {
-       .start  = PNX8550_PCIIO + 0x1000,       /* reserve regacy I/O space */
-       .end    = PNX8550_PCIIO + PNX8550_PCIIO_SIZE,
-       .name   = "pci IO space",
-       .flags  = IORESOURCE_IO
-};
-
-static struct resource pci_mem_resource = {
-       .start  = PNX8550_PCIMEM,
-       .end    = PNX8550_PCIMEM + PNX8550_PCIMEM_SIZE - 1,
-       .name   = "pci memory space",
-       .flags  = IORESOURCE_MEM
-};
-
-extern struct pci_ops pnx8550_pci_ops;
-
-static struct pci_controller pnx8550_controller = {
-       .pci_ops        = &pnx8550_pci_ops,
-       .io_map_base    = PNX8550_PORT_BASE,
-       .io_resource    = &pci_io_resource,
-       .mem_resource   = &pci_mem_resource,
-};
-
-/* Return the total size of DRAM-memory, (RANK0 + RANK1) */
-static inline unsigned long get_system_mem_size(void)
-{
-       /* Read IP2031_RANK0_ADDR_LO */
-       unsigned long dram_r0_lo = inl(PCI_BASE | 0x65010);
-       /* Read IP2031_RANK1_ADDR_HI */
-       unsigned long dram_r1_hi = inl(PCI_BASE | 0x65018);
-
-       return dram_r1_hi - dram_r0_lo + 1;
-}
-
-static int __init pnx8550_pci_setup(void)
-{
-       int pci_mem_code;
-       int mem_size = get_system_mem_size() >> 20;
-
-       /* Clear the Global 2 Register, PCI Inta Output Enable Registers
-          Bit 1:Enable DAC Powerdown
-         -> 0:DACs are enabled and are working normally
-            1:DACs are powerdown
-          Bit 0:Enable of PCI inta output
-         -> 0 = Disable PCI inta output
-            1 = Enable PCI inta output
-       */
-       PNX8550_GLB2_ENAB_INTA_O = 0;
-
-       /* Calc the PCI mem size code */
-       if (mem_size >= 128)
-               pci_mem_code = SIZE_128M;
-       else if (mem_size >= 64)
-               pci_mem_code = SIZE_64M;
-       else if (mem_size >= 32)
-               pci_mem_code = SIZE_32M;
-       else
-               pci_mem_code = SIZE_16M;
-
-       /* Set PCI_XIO registers */
-       outl(pci_mem_resource.start, PCI_BASE | PCI_BASE1_LO);
-       outl(pci_mem_resource.end + 1, PCI_BASE | PCI_BASE1_HI);
-       outl(pci_io_resource.start, PCI_BASE | PCI_BASE2_LO);
-       outl(pci_io_resource.end, PCI_BASE | PCI_BASE2_HI);
-
-       /* Send memory transaction via PCI_BASE2 */
-       outl(0x00000001, PCI_BASE | PCI_IO);
-
-       /* Unlock the setup register */
-       outl(0xca, PCI_BASE | PCI_UNLOCKREG);
-
-       /*
-        * BAR0 of PNX8550 (pci base 10) must be zero in order for ide
-        * to work, and in order for bus_to_baddr to work without any
-        * hacks.
-        */
-       outl(0x00000000, PCI_BASE | PCI_BASE10);
-
-       /*
-        *These two bars are set by default or the boot code.
-        * However, it's safer to set them here so we're not boot
-        * code dependent.
-        */
-       outl(0x1be00000, PCI_BASE | PCI_BASE14);  /* PNX MMIO */
-       outl(PNX8550_NAND_BASE_ADDR, PCI_BASE | PCI_BASE18);  /* XIO      */
-
-       outl(PCI_EN_TA |
-            PCI_EN_PCI2MMI |
-            PCI_EN_XIO |
-            PCI_SETUP_BASE18_SIZE(SIZE_32M) |
-            PCI_SETUP_BASE18_EN |
-            PCI_SETUP_BASE14_EN |
-            PCI_SETUP_BASE10_PREF |
-            PCI_SETUP_BASE10_SIZE(pci_mem_code) |
-            PCI_SETUP_CFGMANAGE_EN |
-            PCI_SETUP_PCIARB_EN,
-            PCI_BASE |
-            PCI_SETUP);        /* PCI_SETUP */
-       outl(0x00000000, PCI_BASE | PCI_CTRL);  /* PCI_CONTROL */
-
-       register_pci_controller(&pnx8550_controller);
-
-       return 0;
-}
-
-arch_initcall(pnx8550_pci_setup);
diff --git a/arch/mips/nxp/pnx8550/common/setup.c b/arch/mips/nxp/pnx8550/common/setup.c
deleted file mode 100644 (file)
index 71adac3..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- *
- * 2.6 port, Embedded Alley Solutions, Inc
- *
- *  Based on Per Hallsmark, per.hallsmark@mvista.com
- *
- *  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/init.h>
-#include <linux/sched.h>
-#include <linux/ioport.h>
-#include <linux/irq.h>
-#include <linux/mm.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/serial_pnx8xxx.h>
-#include <linux/pm.h>
-
-#include <asm/cpu.h>
-#include <asm/bootinfo.h>
-#include <asm/irq.h>
-#include <asm/mipsregs.h>
-#include <asm/reboot.h>
-#include <asm/pgtable.h>
-#include <asm/time.h>
-
-#include <glb.h>
-#include <int.h>
-#include <pci.h>
-#include <uart.h>
-#include <nand.h>
-
-extern void __init board_setup(void);
-extern void pnx8550_machine_restart(char *);
-extern void pnx8550_machine_halt(void);
-extern void pnx8550_machine_power_off(void);
-extern struct resource ioport_resource;
-extern struct resource iomem_resource;
-extern char *prom_getcmdline(void);
-
-struct resource standard_io_resources[] = {
-       {
-               .start  = 0x00,
-               .end    = 0x1f,
-               .name   = "dma1",
-               .flags  = IORESOURCE_BUSY
-       }, {
-               .start  = 0x40,
-               .end    = 0x5f,
-               .name   = "timer",
-               .flags  = IORESOURCE_BUSY
-       }, {
-               .start  = 0x80,
-               .end    = 0x8f,
-               .name   = "dma page reg",
-               .flags  = IORESOURCE_BUSY
-       }, {
-               .start  = 0xc0,
-               .end    = 0xdf,
-               .name   = "dma2",
-               .flags  = IORESOURCE_BUSY
-       },
-};
-
-#define STANDARD_IO_RESOURCES ARRAY_SIZE(standard_io_resources)
-
-extern struct resource pci_io_resource;
-extern struct resource pci_mem_resource;
-
-/* Return the total size of DRAM-memory, (RANK0 + RANK1) */
-unsigned long get_system_mem_size(void)
-{
-       /* Read IP2031_RANK0_ADDR_LO */
-       unsigned long dram_r0_lo = inl(PCI_BASE | 0x65010);
-       /* Read IP2031_RANK1_ADDR_HI */
-       unsigned long dram_r1_hi = inl(PCI_BASE | 0x65018);
-
-       return dram_r1_hi - dram_r0_lo + 1;
-}
-
-int pnx8550_console_port = -1;
-
-void __init plat_mem_setup(void)
-{
-       int i;
-       char* argptr;
-
-       board_setup();  /* board specific setup */
-
-        _machine_restart = pnx8550_machine_restart;
-        _machine_halt = pnx8550_machine_halt;
-        pm_power_off = pnx8550_machine_power_off;
-
-       /* Clear the Global 2 Register, PCI Inta Output Enable Registers
-          Bit 1:Enable DAC Powerdown
-         -> 0:DACs are enabled and are working normally
-            1:DACs are powerdown
-          Bit 0:Enable of PCI inta output
-         -> 0 = Disable PCI inta output
-            1 = Enable PCI inta output
-       */
-       PNX8550_GLB2_ENAB_INTA_O = 0;
-
-       /* IO/MEM resources. */
-       set_io_port_base(PNX8550_PORT_BASE);
-       ioport_resource.start = 0;
-       ioport_resource.end = ~0;
-       iomem_resource.start = 0;
-       iomem_resource.end = ~0;
-
-       /* Request I/O space for devices on this board */
-       for (i = 0; i < STANDARD_IO_RESOURCES; i++)
-               request_resource(&ioport_resource, standard_io_resources + i);
-
-       /* Place the Mode Control bit for GPIO pin 16 in primary function */
-       /* Pin 16 is used by UART1, UA1_TX                                */
-       outl((PNX8550_GPIO_MODE_PRIMOP << PNX8550_GPIO_MC_16_BIT) |
-                       (PNX8550_GPIO_MODE_PRIMOP << PNX8550_GPIO_MC_17_BIT),
-                       PNX8550_GPIO_MC1);
-
-       argptr = prom_getcmdline();
-       if ((argptr = strstr(argptr, "console=ttyS")) != NULL) {
-               argptr += strlen("console=ttyS");
-               pnx8550_console_port = *argptr == '0' ? 0 : 1;
-
-               /* We must initialize the UART (console) before early printk */
-               /* Set LCR to 8-bit and BAUD to 38400 (no 5)                */
-               ip3106_lcr(UART_BASE, pnx8550_console_port) =
-                       PNX8XXX_UART_LCR_8BIT;
-               ip3106_baud(UART_BASE, pnx8550_console_port) = 5;
-       }
-}
index 4ee5710..b5ce041 100644 (file)
@@ -7,6 +7,7 @@
  * Support for all devices (greater than 16) added by David Gathright.
  */
 
+#include <linux/export.h>
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/platform_device.h>
index 8656388..be1e1af 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/delay.h>
 #include <linux/mm.h>
 #include <linux/vmalloc.h>
+#include <linux/export.h>
 #include <linux/platform_device.h>
 
 #include <asm/pci.h>
index cf4c868..dcc926e 100644 (file)
@@ -102,7 +102,7 @@ void __init prom_init(void)
 
        /* Get the boot parameters */
        for (i = 1; i < argc; i++) {
-               if (strlen(arcs_cmdline) + strlen(arg[i] + 1) >=
+               if (strlen(arcs_cmdline) + strlen(arg[i]) + 1 >=
                    sizeof(arcs_cmdline))
                        break;
 
index 4e60c42..876356d 100644 (file)
@@ -62,4 +62,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #endif /* _ASM_SOCKET_H */
index 225b7d6..d28c51b 100644 (file)
@@ -61,6 +61,9 @@
 
 #define SO_RXQ_OVFL             0x4021
 
+#define SO_WIFI_STATUS         0x4022
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 /* O_NONBLOCK clashes with the bits used for socket types.  Therefore we
  * have to define SOCK_NONBLOCK to a different value here.
  */
index b177caa..951e18f 100644 (file)
@@ -345,7 +345,7 @@ config ARCH_ENABLE_MEMORY_HOTREMOVE
 
 config KEXEC
        bool "kexec system call (EXPERIMENTAL)"
-       depends on (PPC_BOOK3S || FSL_BOOKE || (44x && !SMP && !47x)) && EXPERIMENTAL
+       depends on (PPC_BOOK3S || FSL_BOOKE || (44x && !SMP && !PPC_47x)) && EXPERIMENTAL
        help
          kexec is a system call that implements the ability to shutdown your
          current kernel, and to start another kernel.  It is like a reboot
index 57af16e..70ba0c0 100644 (file)
@@ -255,12 +255,6 @@ checkbin:
                echo 'disable kernel modules' ; \
                false ; \
        fi
-       @if ! /bin/echo dssall | $(AS) -many -o $(TOUT) >/dev/null 2>&1 ; then \
-               echo -n '*** ${VERSION}.${PATCHLEVEL} kernels no longer build ' ; \
-               echo 'correctly with old versions of binutils.' ; \
-               echo '*** Please upgrade your binutils to 2.12.1 or newer' ; \
-               false ; \
-       fi
 
 CLEAN_FILES += $(TOUT)
 
diff --git a/arch/powerpc/boot/dts/charon.dts b/arch/powerpc/boot/dts/charon.dts
new file mode 100644 (file)
index 0000000..0e00e50
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * charon board Device Tree Source
+ *
+ * Copyright (C) 2007 Semihalf
+ * Marian Balakowicz <m8@semihalf.com>
+ *
+ * Copyright (C) 2010 DENX Software Engineering GmbH
+ * Heiko Schocher <hs@denx.de>
+ *
+ * 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.
+ */
+
+/dts-v1/;
+
+/ {
+       model = "anon,charon";
+       compatible = "anon,charon";
+       #address-cells = <1>;
+       #size-cells = <1>;
+       interrupt-parent = <&mpc5200_pic>;
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               PowerPC,5200@0 {
+                       device_type = "cpu";
+                       reg = <0>;
+                       d-cache-line-size = <32>;
+                       i-cache-line-size = <32>;
+                       d-cache-size = <0x4000>;        // L1, 16K
+                       i-cache-size = <0x4000>;        // L1, 16K
+                       timebase-frequency = <0>;       // from bootloader
+                       bus-frequency = <0>;            // from bootloader
+                       clock-frequency = <0>;          // from bootloader
+               };
+       };
+
+       memory {
+               device_type = "memory";
+               reg = <0x00000000 0x08000000>;  // 128MB
+       };
+
+       soc5200@f0000000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "fsl,mpc5200-immr";
+               ranges = <0 0xf0000000 0x0000c000>;
+               reg = <0xf0000000 0x00000100>;
+               bus-frequency = <0>;            // from bootloader
+               system-frequency = <0>;         // from bootloader
+
+               cdm@200 {
+                       compatible = "fsl,mpc5200-cdm";
+                       reg = <0x200 0x38>;
+               };
+
+               mpc5200_pic: interrupt-controller@500 {
+                       // 5200 interrupts are encoded into two levels;
+                       interrupt-controller;
+                       #interrupt-cells = <3>;
+                       compatible = "fsl,mpc5200-pic";
+                       reg = <0x500 0x80>;
+               };
+
+               timer@600 {     // General Purpose Timer
+                       compatible = "fsl,mpc5200-gpt";
+                       reg = <0x600 0x10>;
+                       interrupts = <1 9 0>;
+                       fsl,has-wdt;
+               };
+
+               can@900 {
+                       compatible = "fsl,mpc5200-mscan";
+                       interrupts = <2 17 0>;
+                       reg = <0x900 0x80>;
+               };
+
+               can@980 {
+                       compatible = "fsl,mpc5200-mscan";
+                       interrupts = <2 18 0>;
+                       reg = <0x980 0x80>;
+               };
+
+               gpio_simple: gpio@b00 {
+                       compatible = "fsl,mpc5200-gpio";
+                       reg = <0xb00 0x40>;
+                       interrupts = <1 7 0>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               usb@1000 {
+                       compatible = "fsl,mpc5200-ohci","ohci-be";
+                       reg = <0x1000 0xff>;
+                       interrupts = <2 6 0>;
+               };
+
+               dma-controller@1200 {
+                       device_type = "dma-controller";
+                       compatible = "fsl,mpc5200-bestcomm";
+                       reg = <0x1200 0x80>;
+                       interrupts = <3 0 0  3 1 0  3 2 0  3 3 0
+                                     3 4 0  3 5 0  3 6 0  3 7 0
+                                     3 8 0  3 9 0  3 10 0  3 11 0
+                                     3 12 0  3 13 0  3 14 0  3 15 0>;
+               };
+
+               xlb@1f00 {
+                       compatible = "fsl,mpc5200-xlb";
+                       reg = <0x1f00 0x100>;
+               };
+
+               serial@2000 {           // PSC1
+                       compatible = "fsl,mpc5200-psc-uart";
+                       reg = <0x2000 0x100>;
+                       interrupts = <2 1 0>;
+               };
+
+               serial@2400 {           // PSC3
+                       compatible = "fsl,mpc5200-psc-uart";
+                       reg = <0x2400 0x100>;
+                       interrupts = <2 3 0>;
+               };
+
+               ethernet@3000 {
+                       compatible = "fsl,mpc5200-fec";
+                       reg = <0x3000 0x400>;
+                       local-mac-address = [ 00 00 00 00 00 00 ];
+                       interrupts = <2 5 0>;
+                       fixed-link = <1 1 100 0 0>;
+               };
+
+               mdio@3000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "fsl,mpc5200-mdio";
+                       reg = <0x3000 0x400>;       // fec range, since we need to setup fec interrupts
+                       interrupts = <2 5 0>;   // these are for "mii command finished", not link changes & co.
+               };
+
+               ata@3a00 {
+                       compatible = "fsl,mpc5200-ata";
+                       reg = <0x3a00 0x100>;
+                       interrupts = <2 7 0>;
+               };
+
+               i2c@3d00 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "fsl,mpc5200-i2c","fsl-i2c";
+                       reg = <0x3d00 0x40>;
+                       interrupts = <2 15 0>;
+               };
+
+
+               i2c@3d40 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "fsl,mpc5200-i2c","fsl-i2c";
+                       reg = <0x3d40 0x40>;
+                       interrupts = <2 16 0>;
+
+                       dtt@28 {
+                               compatible = "national,lm80";
+                               reg = <0x28>;
+                       };
+
+                       rtc@68 {
+                               compatible = "dallas,ds1374";
+                               reg = <0x68>;
+                       };
+               };
+
+               sram@8000 {
+                       compatible = "fsl,mpc5200-sram";
+                       reg = <0x8000 0x4000>;
+               };
+       };
+
+       localbus {
+               compatible = "fsl,mpc5200-lpb","simple-bus";
+               #address-cells = <2>;
+               #size-cells = <1>;
+               ranges = <      0 0 0xfc000000 0x02000000
+                               1 0 0xe0000000 0x04000000 // CS1 range, SM501
+                               3 0 0xe8000000 0x00080000>;
+
+               flash@0,0 {
+                       compatible = "cfi-flash";
+                       reg = <0 0 0x02000000>;
+                       bank-width = <4>;
+                       device-width = <2>;
+                       #size-cells = <1>;
+                       #address-cells = <1>;
+               };
+
+               display@1,0 {
+                       compatible = "smi,sm501";
+                       reg = <1 0x00000000 0x00800000
+                              1 0x03e00000 0x00200000>;
+                       mode = "640x480-32@60";
+                       interrupts = <1 1 3>;
+                       little-endian;
+               };
+
+               mram0@3,0 {
+                       compatible = "mtd-ram";
+                       reg = <3 0x00000 0x80000>;
+                       bank-width = <1>;
+               };
+       };
+
+       pci@f0000d00 {
+               #interrupt-cells = <1>;
+               #size-cells = <2>;
+               #address-cells = <3>;
+               device_type = "pci";
+               compatible = "fsl,mpc5200-pci";
+               reg = <0xf0000d00 0x100>;
+               interrupt-map-mask = <0xf800 0 0 7>;
+               interrupt-map = <0xc000 0 0 1 &mpc5200_pic 0 0 3
+                                0xc000 0 0 2 &mpc5200_pic 0 0 3
+                                0xc000 0 0 3 &mpc5200_pic 0 0 3
+                                0xc000 0 0 4 &mpc5200_pic 0 0 3>;
+               clock-frequency = <0>; // From boot loader
+               interrupts = <2 8 0 2 9 0 2 10 0>;
+               bus-range = <0 0>;
+               ranges = <0x42000000 0 0x80000000 0x80000000 0 0x10000000
+                         0x02000000 0 0x90000000 0x90000000 0 0x10000000
+                         0x01000000 0 0x00000000 0xa0000000 0 0x01000000>;
+       };
+};
index 959cd2c..716a37b 100644 (file)
@@ -1,9 +1,10 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
+CONFIG_SPARSE_IRQ=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EXPERT=y
+CONFIG_EMBEDDED=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_KALLSYMS is not set
 # CONFIG_EPOLL is not set
@@ -17,7 +18,6 @@ CONFIG_PPC_MPC5200_SIMPLE=y
 CONFIG_PPC_MPC5200_BUGFIX=y
 # CONFIG_PPC_PMAC is not set
 CONFIG_PPC_BESTCOMM=y
-CONFIG_SPARSE_IRQ=y
 CONFIG_PM=y
 # CONFIG_PCI is not set
 CONFIG_NET=y
@@ -38,17 +38,18 @@ CONFIG_MTD=y
 CONFIG_MTD_CONCAT=y
 CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_OF_PARTS=y
 CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_ROM=y
 CONFIG_MTD_PHYSMAP_OF=y
+CONFIG_MTD_PLATRAM=y
 CONFIG_PROC_DEVICETREE=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=32768
-# CONFIG_MISC_DEVICES is not set
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_SG=y
 CONFIG_ATA=y
@@ -56,13 +57,11 @@ CONFIG_PATA_MPC52xx=y
 CONFIG_PATA_PLATFORM=y
 CONFIG_NETDEVICES=y
 CONFIG_LXT_PHY=y
+CONFIG_FIXED_PHY=y
 CONFIG_NET_ETHERNET=y
 CONFIG_FEC_MPC52xx=y
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
-# CONFIG_INPUT is not set
-# CONFIG_SERIO is not set
-# CONFIG_VT is not set
 CONFIG_SERIAL_MPC52xx=y
 CONFIG_SERIAL_MPC52xx_CONSOLE=y
 CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD=115200
@@ -70,7 +69,13 @@ CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD=115200
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_MPC=y
+CONFIG_SENSORS_LM80=y
 CONFIG_WATCHDOG=y
+CONFIG_MFD_SM501=y
+CONFIG_FB=y
+CONFIG_FB_FOREIGN_ENDIAN=y
+CONFIG_FB_SM501=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_USB=y
 CONFIG_USB_DEVICEFS=y
 # CONFIG_USB_DEVICE_CLASS is not set
@@ -80,10 +85,10 @@ CONFIG_USB_OHCI_HCD_PPC_OF_BE=y
 CONFIG_USB_STORAGE=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_DS1307=y
+CONFIG_RTC_DRV_DS1374=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT3_FS=y
 # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_INOTIFY=y
 CONFIG_MSDOS_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_PROC_KCORE=y
@@ -102,7 +107,6 @@ CONFIG_DEBUG_KERNEL=y
 CONFIG_DETECT_HUNG_TASK=y
 # CONFIG_DEBUG_BUGVERBOSE is not set
 CONFIG_DEBUG_INFO=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
 CONFIG_CRYPTO_ECB=y
 CONFIG_CRYPTO_PCBC=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
index 84a685a..535711f 100644 (file)
@@ -485,3 +485,7 @@ CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_LZO=m
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 # CONFIG_CRYPTO_HW is not set
+CONFIG_VIRTUALIZATION=y
+CONFIG_KVM_BOOK3S_64=m
+CONFIG_KVM_BOOK3S_64_HV=y
+CONFIG_VHOST_NET=m
index 96a58b7..a72f241 100644 (file)
@@ -362,3 +362,7 @@ CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_LZO=m
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 # CONFIG_CRYPTO_HW is not set
+CONFIG_VIRTUALIZATION=y
+CONFIG_KVM_BOOK3S_64=m
+CONFIG_KVM_BOOK3S_64_HV=y
+CONFIG_VHOST_NET=m
index e2a4c26..02e41b5 100644 (file)
@@ -49,13 +49,13 @@ static __inline__ int atomic_add_return(int a, atomic_t *v)
        int t;
 
        __asm__ __volatile__(
-       PPC_RELEASE_BARRIER
+       PPC_ATOMIC_ENTRY_BARRIER
 "1:    lwarx   %0,0,%2         # atomic_add_return\n\
        add     %0,%1,%0\n"
        PPC405_ERR77(0,%2)
 "      stwcx.  %0,0,%2 \n\
        bne-    1b"
-       PPC_ACQUIRE_BARRIER
+       PPC_ATOMIC_EXIT_BARRIER
        : "=&r" (t)
        : "r" (a), "r" (&v->counter)
        : "cc", "memory");
@@ -85,13 +85,13 @@ static __inline__ int atomic_sub_return(int a, atomic_t *v)
        int t;
 
        __asm__ __volatile__(
-       PPC_RELEASE_BARRIER
+       PPC_ATOMIC_ENTRY_BARRIER
 "1:    lwarx   %0,0,%2         # atomic_sub_return\n\
        subf    %0,%1,%0\n"
        PPC405_ERR77(0,%2)
 "      stwcx.  %0,0,%2 \n\
        bne-    1b"
-       PPC_ACQUIRE_BARRIER
+       PPC_ATOMIC_EXIT_BARRIER
        : "=&r" (t)
        : "r" (a), "r" (&v->counter)
        : "cc", "memory");
@@ -119,13 +119,13 @@ static __inline__ int atomic_inc_return(atomic_t *v)
        int t;
 
        __asm__ __volatile__(
-       PPC_RELEASE_BARRIER
+       PPC_ATOMIC_ENTRY_BARRIER
 "1:    lwarx   %0,0,%1         # atomic_inc_return\n\
        addic   %0,%0,1\n"
        PPC405_ERR77(0,%1)
 "      stwcx.  %0,0,%1 \n\
        bne-    1b"
-       PPC_ACQUIRE_BARRIER
+       PPC_ATOMIC_EXIT_BARRIER
        : "=&r" (t)
        : "r" (&v->counter)
        : "cc", "xer", "memory");
@@ -163,13 +163,13 @@ static __inline__ int atomic_dec_return(atomic_t *v)
        int t;
 
        __asm__ __volatile__(
-       PPC_RELEASE_BARRIER
+       PPC_ATOMIC_ENTRY_BARRIER
 "1:    lwarx   %0,0,%1         # atomic_dec_return\n\
        addic   %0,%0,-1\n"
        PPC405_ERR77(0,%1)
 "      stwcx.  %0,0,%1\n\
        bne-    1b"
-       PPC_ACQUIRE_BARRIER
+       PPC_ATOMIC_EXIT_BARRIER
        : "=&r" (t)
        : "r" (&v->counter)
        : "cc", "xer", "memory");
@@ -194,7 +194,7 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u)
        int t;
 
        __asm__ __volatile__ (
-       PPC_RELEASE_BARRIER
+       PPC_ATOMIC_ENTRY_BARRIER
 "1:    lwarx   %0,0,%1         # __atomic_add_unless\n\
        cmpw    0,%0,%3 \n\
        beq-    2f \n\
@@ -202,7 +202,7 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u)
        PPC405_ERR77(0,%2)
 "      stwcx.  %0,0,%1 \n\
        bne-    1b \n"
-       PPC_ACQUIRE_BARRIER
+       PPC_ATOMIC_EXIT_BARRIER
 "      subf    %0,%2,%0 \n\
 2:"
        : "=&r" (t)
@@ -226,7 +226,7 @@ static __inline__ int atomic_dec_if_positive(atomic_t *v)
        int t;
 
        __asm__ __volatile__(
-       PPC_RELEASE_BARRIER
+       PPC_ATOMIC_ENTRY_BARRIER
 "1:    lwarx   %0,0,%1         # atomic_dec_if_positive\n\
        cmpwi   %0,1\n\
        addi    %0,%0,-1\n\
@@ -234,7 +234,7 @@ static __inline__ int atomic_dec_if_positive(atomic_t *v)
        PPC405_ERR77(0,%1)
 "      stwcx.  %0,0,%1\n\
        bne-    1b"
-       PPC_ACQUIRE_BARRIER
+       PPC_ATOMIC_EXIT_BARRIER
        "\n\
 2:"    : "=&b" (t)
        : "r" (&v->counter)
@@ -285,12 +285,12 @@ static __inline__ long atomic64_add_return(long a, atomic64_t *v)
        long t;
 
        __asm__ __volatile__(
-       PPC_RELEASE_BARRIER
+       PPC_ATOMIC_ENTRY_BARRIER
 "1:    ldarx   %0,0,%2         # atomic64_add_return\n\
        add     %0,%1,%0\n\
        stdcx.  %0,0,%2 \n\
        bne-    1b"
-       PPC_ACQUIRE_BARRIER
+       PPC_ATOMIC_EXIT_BARRIER
        : "=&r" (t)
        : "r" (a), "r" (&v->counter)
        : "cc", "memory");
@@ -319,12 +319,12 @@ static __inline__ long atomic64_sub_return(long a, atomic64_t *v)
        long t;
 
        __asm__ __volatile__(
-       PPC_RELEASE_BARRIER
+       PPC_ATOMIC_ENTRY_BARRIER
 "1:    ldarx   %0,0,%2         # atomic64_sub_return\n\
        subf    %0,%1,%0\n\
        stdcx.  %0,0,%2 \n\
        bne-    1b"
-       PPC_ACQUIRE_BARRIER
+       PPC_ATOMIC_EXIT_BARRIER
        : "=&r" (t)
        : "r" (a), "r" (&v->counter)
        : "cc", "memory");
@@ -351,12 +351,12 @@ static __inline__ long atomic64_inc_return(atomic64_t *v)
        long t;
 
        __asm__ __volatile__(
-       PPC_RELEASE_BARRIER
+       PPC_ATOMIC_ENTRY_BARRIER
 "1:    ldarx   %0,0,%1         # atomic64_inc_return\n\
        addic   %0,%0,1\n\
        stdcx.  %0,0,%1 \n\
        bne-    1b"
-       PPC_ACQUIRE_BARRIER
+       PPC_ATOMIC_EXIT_BARRIER
        : "=&r" (t)
        : "r" (&v->counter)
        : "cc", "xer", "memory");
@@ -393,12 +393,12 @@ static __inline__ long atomic64_dec_return(atomic64_t *v)
        long t;
 
        __asm__ __volatile__(
-       PPC_RELEASE_BARRIER
+       PPC_ATOMIC_ENTRY_BARRIER
 "1:    ldarx   %0,0,%1         # atomic64_dec_return\n\
        addic   %0,%0,-1\n\
        stdcx.  %0,0,%1\n\
        bne-    1b"
-       PPC_ACQUIRE_BARRIER
+       PPC_ATOMIC_EXIT_BARRIER
        : "=&r" (t)
        : "r" (&v->counter)
        : "cc", "xer", "memory");
@@ -418,13 +418,13 @@ static __inline__ long atomic64_dec_if_positive(atomic64_t *v)
        long t;
 
        __asm__ __volatile__(
-       PPC_RELEASE_BARRIER
+       PPC_ATOMIC_ENTRY_BARRIER
 "1:    ldarx   %0,0,%1         # atomic64_dec_if_positive\n\
        addic.  %0,%0,-1\n\
        blt-    2f\n\
        stdcx.  %0,0,%1\n\
        bne-    1b"
-       PPC_ACQUIRE_BARRIER
+       PPC_ATOMIC_EXIT_BARRIER
        "\n\
 2:"    : "=&r" (t)
        : "r" (&v->counter)
@@ -450,14 +450,14 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
        long t;
 
        __asm__ __volatile__ (
-       PPC_RELEASE_BARRIER
+       PPC_ATOMIC_ENTRY_BARRIER
 "1:    ldarx   %0,0,%1         # __atomic_add_unless\n\
        cmpd    0,%0,%3 \n\
        beq-    2f \n\
        add     %0,%2,%0 \n"
 "      stdcx.  %0,0,%1 \n\
        bne-    1b \n"
-       PPC_ACQUIRE_BARRIER
+       PPC_ATOMIC_EXIT_BARRIER
 "      subf    %0,%2,%0 \n\
 2:"
        : "=&r" (t)
index e137afc..efdc926 100644 (file)
@@ -124,14 +124,14 @@ static __inline__ unsigned long fn(                       \
        return (old & mask);                            \
 }
 
-DEFINE_TESTOP(test_and_set_bits, or, PPC_RELEASE_BARRIER,
-             PPC_ACQUIRE_BARRIER, 0)
+DEFINE_TESTOP(test_and_set_bits, or, PPC_ATOMIC_ENTRY_BARRIER,
+             PPC_ATOMIC_EXIT_BARRIER, 0)
 DEFINE_TESTOP(test_and_set_bits_lock, or, "",
              PPC_ACQUIRE_BARRIER, 1)
-DEFINE_TESTOP(test_and_clear_bits, andc, PPC_RELEASE_BARRIER,
-             PPC_ACQUIRE_BARRIER, 0)
-DEFINE_TESTOP(test_and_change_bits, xor, PPC_RELEASE_BARRIER,
-             PPC_ACQUIRE_BARRIER, 0)
+DEFINE_TESTOP(test_and_clear_bits, andc, PPC_ATOMIC_ENTRY_BARRIER,
+             PPC_ATOMIC_EXIT_BARRIER, 0)
+DEFINE_TESTOP(test_and_change_bits, xor, PPC_ATOMIC_ENTRY_BARRIER,
+             PPC_ATOMIC_EXIT_BARRIER, 0)
 
 static __inline__ int test_and_set_bit(unsigned long nr,
                                       volatile unsigned long *addr)
index 24bd34c..936a904 100644 (file)
@@ -108,10 +108,10 @@ static int fd_request_irq(void)
 {
        if (can_use_virtual_dma)
                return request_irq(FLOPPY_IRQ, floppy_hardint,
-                                  IRQF_DISABLED, "floppy", NULL);
+                                  0, "floppy", NULL);
        else
                return request_irq(FLOPPY_IRQ, floppy_interrupt,
-                                  IRQF_DISABLED, "floppy", NULL);
+                                  0, "floppy", NULL);
 }
 
 static int vdma_dma_setup(char *addr, unsigned long size, int mode, int io)
index c94e4a3..2a9cf84 100644 (file)
 
 #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
   __asm__ __volatile ( \
-       PPC_RELEASE_BARRIER \
+       PPC_ATOMIC_ENTRY_BARRIER \
 "1:    lwarx   %0,0,%2\n" \
        insn \
        PPC405_ERR77(0, %2) \
 "2:    stwcx.  %1,0,%2\n" \
        "bne-   1b\n" \
+       PPC_ATOMIC_EXIT_BARRIER \
        "li     %1,0\n" \
 "3:    .section .fixup,\"ax\"\n" \
 "4:    li      %1,%3\n" \
@@ -92,14 +93,14 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
                return -EFAULT;
 
         __asm__ __volatile__ (
-        PPC_RELEASE_BARRIER
+        PPC_ATOMIC_ENTRY_BARRIER
 "1:     lwarx   %1,0,%3         # futex_atomic_cmpxchg_inatomic\n\
         cmpw    0,%1,%4\n\
         bne-    3f\n"
         PPC405_ERR77(0,%3)
 "2:     stwcx.  %5,0,%3\n\
         bne-    1b\n"
-        PPC_ACQUIRE_BARRIER
+        PPC_ATOMIC_EXIT_BARRIER
 "3:    .section .fixup,\"ax\"\n\
 4:     li      %0,%6\n\
        b       3b\n\
index 08fe69e..0ad432b 100644 (file)
@@ -149,12 +149,6 @@ struct kvm_regs {
 #define KVM_SREGS_E_UPDATE_DBSR                (1 << 3)
 
 /*
- * Book3S special bits to indicate contents in the struct by maintaining
- * backwards compatibility with older structs. If adding a new field,
- * please make sure to add a flag for that new field */
-#define KVM_SREGS_S_HIOR               (1 << 0)
-
-/*
  * In KVM_SET_SREGS, reserved/pad fields must be left untouched from a
  * previous KVM_GET_REGS.
  *
@@ -179,8 +173,6 @@ struct kvm_sregs {
                                __u64 ibat[8]; 
                                __u64 dbat[8]; 
                        } ppc32;
-                       __u64 flags; /* KVM_SREGS_S_ */
-                       __u64 hior;
                } s;
                struct {
                        union {
index a384ffd..d4df013 100644 (file)
@@ -90,8 +90,6 @@ struct kvmppc_vcpu_book3s {
 #endif
        int context_id[SID_CONTEXTS];
 
-       bool hior_sregs;                /* HIOR is set by SREGS, not PVR */
-
        struct hlist_head hpte_hash_pte[HPTEG_HASH_NUM_PTE];
        struct hlist_head hpte_hash_pte_long[HPTEG_HASH_NUM_PTE_LONG];
        struct hlist_head hpte_hash_vpte[HPTEG_HASH_NUM_VPTE];
index 9cd5fc8..f77c708 100644 (file)
@@ -316,7 +316,7 @@ LV1_CALL(gpu_context_free,                              1, 0, 218 )
 LV1_CALL(gpu_context_iomap,                             5, 0, 221 )
 LV1_CALL(gpu_context_attribute,                         6, 0, 225 )
 LV1_CALL(gpu_context_intr,                              1, 1, 227 )
-LV1_CALL(gpu_attribute,                                 5, 0, 228 )
+LV1_CALL(gpu_attribute,                                 3, 0, 228 )
 LV1_CALL(get_rtc,                                       0, 2, 232 )
 LV1_CALL(set_ppe_periodic_tracer_frequency,             1, 0, 240 )
 LV1_CALL(start_ppe_periodic_tracer,                     5, 0, 241 )
index 28cdbd9..03c48e8 100644 (file)
@@ -31,7 +31,7 @@
 
 #define MSR_           MSR_ME | MSR_CE
 #define MSR_KERNEL     MSR_ | MSR_64BIT
-#define MSR_USER32     MSR_ | MSR_PR | MSR_EE | MSR_DE
+#define MSR_USER32     MSR_ | MSR_PR | MSR_EE
 #define MSR_USER64     MSR_USER32 | MSR_64BIT
 #elif defined (CONFIG_40x)
 #define MSR_KERNEL     (MSR_ME|MSR_RI|MSR_IR|MSR_DR|MSR_CE)
index 6fbce72..a0f358d 100644 (file)
@@ -8,7 +8,7 @@
 
 #ifdef __powerpc64__
 
-extern char _end[];
+extern char __end_interrupts[];
 
 static inline int in_kernel_text(unsigned long addr)
 {
index 866f760..2fc2af8 100644 (file)
@@ -69,4 +69,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #endif /* _ASM_POWERPC_SOCKET_H */
index d7cab44..e682a71 100644 (file)
@@ -13,6 +13,7 @@
 extern unsigned int __start___lwsync_fixup, __stop___lwsync_fixup;
 extern void do_lwsync_fixups(unsigned long value, void *fixup_start,
                             void *fixup_end);
+extern void do_final_fixups(void);
 
 static inline void eieio(void)
 {
@@ -41,11 +42,15 @@ static inline void isync(void)
        START_LWSYNC_SECTION(97);                       \
        isync;                                          \
        MAKE_LWSYNC_SECTION_ENTRY(97, __lwsync_fixup);
-#define PPC_ACQUIRE_BARRIER    "\n" stringify_in_c(__PPC_ACQUIRE_BARRIER)
-#define PPC_RELEASE_BARRIER    stringify_in_c(LWSYNC) "\n"
+#define PPC_ACQUIRE_BARRIER     "\n" stringify_in_c(__PPC_ACQUIRE_BARRIER)
+#define PPC_RELEASE_BARRIER     stringify_in_c(LWSYNC) "\n"
+#define PPC_ATOMIC_ENTRY_BARRIER "\n" stringify_in_c(LWSYNC) "\n"
+#define PPC_ATOMIC_EXIT_BARRIER         "\n" stringify_in_c(sync) "\n"
 #else
 #define PPC_ACQUIRE_BARRIER
 #define PPC_RELEASE_BARRIER
+#define PPC_ATOMIC_ENTRY_BARRIER
+#define PPC_ATOMIC_EXIT_BARRIER
 #endif
 
 #endif /* __KERNEL__ */
index bd6c401..c48de98 100644 (file)
@@ -15,8 +15,8 @@
 #define        DEFAULT_PRIORITY        5
 
 /*
- * Mark IPIs as higher priority so we can take them inside interrupts that
- * arent marked IRQF_DISABLED
+ * Mark IPIs as higher priority so we can take them inside interrupts
+ * FIXME: still true now?
  */
 #define IPI_PRIORITY           4
 
index 56212bc..4f80cf1 100644 (file)
@@ -215,7 +215,22 @@ reenable_mmu:                              /* re-enable mmu so we can */
        stw     r9,8(r1)
        stw     r11,12(r1)
        stw     r3,ORIG_GPR3(r1)
+       /*
+        * The trace_hardirqs_off will use CALLER_ADDR0 and CALLER_ADDR1.
+        * If from user mode there is only one stack frame on the stack, and
+        * accessing CALLER_ADDR1 will cause oops. So we need create a dummy
+        * stack frame to make trace_hardirqs_off happy.
+        */
+       andi.   r12,r12,MSR_PR
+       beq     11f
+       stwu    r1,-16(r1)
+       bl      trace_hardirqs_off
+       addi    r1,r1,16
+       b       12f
+
+11:
        bl      trace_hardirqs_off
+12:
        lwz     r0,GPR0(r1)
        lwz     r3,ORIG_GPR3(r1)
        lwz     r4,GPR4(r1)
index a54d92f..cf9c69b 100644 (file)
@@ -267,7 +267,7 @@ vsx_unavailable_pSeries_1:
 
 #ifdef CONFIG_CBE_RAS
        STD_EXCEPTION_HV(0x1200, 0x1202, cbe_system_error)
-       KVM_HANDLER_PR_SKIP(PACA_EXGEN, EXC_HV, 0x1202)
+       KVM_HANDLER_SKIP(PACA_EXGEN, EXC_HV, 0x1202)
 #endif /* CONFIG_CBE_RAS */
 
        STD_EXCEPTION_PSERIES(0x1300, 0x1300, instruction_breakpoint)
@@ -275,7 +275,7 @@ vsx_unavailable_pSeries_1:
 
 #ifdef CONFIG_CBE_RAS
        STD_EXCEPTION_HV(0x1600, 0x1602, cbe_maintenance)
-       KVM_HANDLER_PR_SKIP(PACA_EXGEN, EXC_HV, 0x1602)
+       KVM_HANDLER_SKIP(PACA_EXGEN, EXC_HV, 0x1602)
 #endif /* CONFIG_CBE_RAS */
 
        STD_EXCEPTION_PSERIES(0x1700, 0x1700, altivec_assist)
@@ -283,7 +283,7 @@ vsx_unavailable_pSeries_1:
 
 #ifdef CONFIG_CBE_RAS
        STD_EXCEPTION_HV(0x1800, 0x1802, cbe_thermal)
-       KVM_HANDLER_PR_SKIP(PACA_EXGEN, EXC_HV, 0x1802)
+       KVM_HANDLER_SKIP(PACA_EXGEN, EXC_HV, 0x1802)
 #endif /* CONFIG_CBE_RAS */
 
        . = 0x3000
index 368d158..a1ed8a8 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/jump_label.h>
 #include <asm/code-patching.h>
 
+#ifdef HAVE_JUMP_LABEL
 void arch_jump_label_transform(struct jump_entry *entry,
                               enum jump_label_type type)
 {
@@ -21,3 +22,4 @@ void arch_jump_label_transform(struct jump_entry *entry,
        else
                patch_instruction(addr, PPC_INST_NOP);
 }
+#endif
index 35f2764..2985338 100644 (file)
@@ -132,7 +132,6 @@ static void kvm_patch_ins_b(u32 *inst, int addr)
        /* On relocatable kernels interrupts handlers and our code
           can be in different regions, so we don't patch them */
 
-       extern u32 __end_interrupts;
        if ((ulong)inst < (ulong)&__end_interrupts)
                return;
 #endif
index f7d760a..7cd07b4 100644 (file)
@@ -738,7 +738,7 @@ relocate_new_kernel:
        mr      r5, r31
 
        li      r0, 0
-#elif defined(CONFIG_44x)  && !defined(CONFIG_47x)
+#elif defined(CONFIG_44x)  && !defined(CONFIG_PPC_47x)
 
 /*
  * Code for setting up 1:1 mapping for PPC440x for KEXEC
index 9054ca9..6457574 100644 (file)
@@ -486,28 +486,6 @@ struct task_struct *__switch_to(struct task_struct *prev,
        new_thread = &new->thread;
        old_thread = &current->thread;
 
-#if defined(CONFIG_PPC_BOOK3E_64)
-       /* XXX Current Book3E code doesn't deal with kernel side DBCR0,
-        * we always hold the user values, so we set it now.
-        *
-        * However, we ensure the kernel MSR:DE is appropriately cleared too
-        * to avoid spurrious single step exceptions in the kernel.
-        *
-        * This will have to change to merge with the ppc32 code at some point,
-        * but I don't like much what ppc32 is doing today so there's some
-        * thinking needed there
-        */
-       if ((new_thread->dbcr0 | old_thread->dbcr0) & DBCR0_IDM) {
-               u32 dbcr0;
-
-               mtmsr(mfmsr() & ~MSR_DE);
-               isync();
-               dbcr0 = mfspr(SPRN_DBCR0);
-               dbcr0 = (dbcr0 & DBCR0_EDM) | new_thread->dbcr0;
-               mtspr(SPRN_DBCR0, dbcr0);
-       }
-#endif /* CONFIG_PPC64_BOOK3E */
-
 #ifdef CONFIG_PPC64
        /*
         * Collect processor utilization data per process
@@ -657,7 +635,7 @@ void show_regs(struct pt_regs * regs)
        if ((regs->trap != 0xc00) && cpu_has_feature(CPU_FTR_CFAR))
                printk("CFAR: "REG"\n", regs->orig_gpr3);
        if (trap == 0x300 || trap == 0x600)
-#ifdef CONFIG_PPC_ADV_DEBUG_REGS
+#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
                printk("DEAR: "REG", ESR: "REG"\n", regs->dar, regs->dsisr);
 #else
                printk("DAR: "REG", DSISR: %08lx\n", regs->dar, regs->dsisr);
index b4fa661..cc58486 100644 (file)
@@ -1579,10 +1579,8 @@ static void __init prom_instantiate_rtas(void)
                return;
 
        base = alloc_down(size, PAGE_SIZE, 0);
-       if (base == 0) {
-               prom_printf("RTAS allocation failed !\n");
-               return;
-       }
+       if (base == 0)
+               prom_panic("Could not allocate memory for RTAS\n");
 
        rtas_inst = call_prom("open", 1, 1, ADDR("/rtas"));
        if (!IHANDLE_VALID(rtas_inst)) {
index c1ce863..ac76108 100644 (file)
@@ -107,6 +107,8 @@ notrace unsigned long __init early_init(unsigned long dt_ptr)
                         PTRRELOC(&__start___lwsync_fixup),
                         PTRRELOC(&__stop___lwsync_fixup));
 
+       do_final_fixups();
+
        return KERNELBASE + offset;
 }
 
index 1a9dea8..fb9bb46 100644 (file)
@@ -359,6 +359,7 @@ void __init setup_system(void)
                          &__start___fw_ftr_fixup, &__stop___fw_ftr_fixup);
        do_lwsync_fixups(cur_cpu_spec->cpu_features,
                         &__start___lwsync_fixup, &__stop___lwsync_fixup);
+       do_final_fixups();
 
        /*
         * Unflatten the device-tree passed by prom_init or kexec
index 78b76dc..836a5a1 100644 (file)
@@ -97,7 +97,7 @@ static inline int put_sigset_t(compat_sigset_t __user *uset, sigset_t *set)
        compat_sigset_t cset;
 
        switch (_NSIG_WORDS) {
-       case 4: cset.sig[5] = set->sig[3] & 0xffffffffull;
+       case 4: cset.sig[6] = set->sig[3] & 0xffffffffull;
                cset.sig[7] = set->sig[3] >> 32;
        case 3: cset.sig[4] = set->sig[2] & 0xffffffffull;
                cset.sig[5] = set->sig[2] >> 32;
index 25ddbfc..6df7090 100644 (file)
@@ -187,7 +187,7 @@ int smp_request_message_ipi(int virq, int msg)
                return 1;
        }
 #endif
-       err = request_irq(virq, smp_ipi_action[msg], IRQF_DISABLED|IRQF_PERCPU,
+       err = request_irq(virq, smp_ipi_action[msg], IRQF_PERCPU,
                          smp_ipi_name[msg], 0);
        WARN(err < 0, "unable to request_irq %d for %s (rc %d)\n",
                virq, smp_ipi_name[msg], err);
index 4e59082..5459d14 100644 (file)
@@ -1298,14 +1298,12 @@ void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status)
 
                if (user_mode(regs)) {
                        current->thread.dbcr0 &= ~DBCR0_IC;
-#ifdef CONFIG_PPC_ADV_DEBUG_REGS
                        if (DBCR_ACTIVE_EVENTS(current->thread.dbcr0,
                                               current->thread.dbcr1))
                                regs->msr |= MSR_DE;
                        else
                                /* Make sure the IDM bit is off */
                                current->thread.dbcr0 &= ~DBCR0_IDM;
-#endif
                }
 
                _exception(SIGTRAP, regs, TRAP_TRACE, regs->nip);
index 0cdbc07..0cb137a 100644 (file)
@@ -44,6 +44,7 @@
 #include <asm/processor.h>
 #include <asm/cputhreads.h>
 #include <asm/page.h>
+#include <asm/hvcall.h>
 #include <linux/gfp.h>
 #include <linux/sched.h>
 #include <linux/vmalloc.h>
index f422231..44d8829 100644 (file)
@@ -1263,7 +1263,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_206)
        addi    r6,r5,VCORE_NAPPING_THREADS
 31:    lwarx   r4,0,r6
        or      r4,r4,r0
-       popcntw r7,r4
+       PPC_POPCNTW(r7,r4)
        cmpw    r7,r8
        bge     2f
        stwcx.  r4,0,r6
index bc4d50d..3c791e1 100644 (file)
@@ -151,16 +151,14 @@ void kvmppc_set_pvr(struct kvm_vcpu *vcpu, u32 pvr)
 #ifdef CONFIG_PPC_BOOK3S_64
        if ((pvr >= 0x330000) && (pvr < 0x70330000)) {
                kvmppc_mmu_book3s_64_init(vcpu);
-               if (!to_book3s(vcpu)->hior_sregs)
-                       to_book3s(vcpu)->hior = 0xfff00000;
+               to_book3s(vcpu)->hior = 0xfff00000;
                to_book3s(vcpu)->msr_mask = 0xffffffffffffffffULL;
                vcpu->arch.cpu_type = KVM_CPU_3S_64;
        } else
 #endif
        {
                kvmppc_mmu_book3s_32_init(vcpu);
-               if (!to_book3s(vcpu)->hior_sregs)
-                       to_book3s(vcpu)->hior = 0;
+               to_book3s(vcpu)->hior = 0;
                to_book3s(vcpu)->msr_mask = 0xffffffffULL;
                vcpu->arch.cpu_type = KVM_CPU_3S_32;
        }
@@ -797,9 +795,6 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
                }
        }
 
-       if (sregs->u.s.flags & KVM_SREGS_S_HIOR)
-               sregs->u.s.hior = to_book3s(vcpu)->hior;
-
        return 0;
 }
 
@@ -836,11 +831,6 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
        /* Flush the MMU after messing with the segments */
        kvmppc_mmu_pte_flush(vcpu, 0, 0);
 
-       if (sregs->u.s.flags & KVM_SREGS_S_HIOR) {
-               to_book3s(vcpu)->hior_sregs = true;
-               to_book3s(vcpu)->hior = sregs->u.s.hior;
-       }
-
        return 0;
 }
 
index efbf9ad..607fbdf 100644 (file)
@@ -208,7 +208,6 @@ int kvm_dev_ioctl_check_extension(long ext)
        case KVM_CAP_PPC_BOOKE_SREGS:
 #else
        case KVM_CAP_PPC_SEGSTATE:
-       case KVM_CAP_PPC_HIOR:
        case KVM_CAP_PPC_PAPR:
 #endif
        case KVM_CAP_PPC_UNSET_IRQ:
index 0d08d01..7a8a748 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/init.h>
 #include <asm/cputable.h>
 #include <asm/code-patching.h>
+#include <asm/page.h>
+#include <asm/sections.h>
 
 
 struct fixup_entry {
@@ -128,6 +130,27 @@ void do_lwsync_fixups(unsigned long value, void *fixup_start, void *fixup_end)
        }
 }
 
+void do_final_fixups(void)
+{
+#if defined(CONFIG_PPC64) && defined(CONFIG_RELOCATABLE)
+       int *src, *dest;
+       unsigned long length;
+
+       if (PHYSICAL_START == 0)
+               return;
+
+       src = (int *)(KERNELBASE + PHYSICAL_START);
+       dest = (int *)KERNELBASE;
+       length = (__end_interrupts - _stext) / sizeof(int);
+
+       while (length--) {
+               patch_instruction(dest, *src);
+               src++;
+               dest++;
+       }
+#endif
+}
+
 #ifdef CONFIG_FTR_FIXUP_SELFTEST
 
 #define check(x)       \
index 16da595..2dd6bdd 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/suspend.h>
 #include <linux/memblock.h>
 #include <linux/hugetlb.h>
+#include <linux/slab.h>
 
 #include <asm/pgalloc.h>
 #include <asm/prom.h>
@@ -555,3 +556,32 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address,
                book3e_hugetlb_preload(vma->vm_mm, address, *ptep);
 #endif
 }
+
+/*
+ * System memory should not be in /proc/iomem but various tools expect it
+ * (eg kdump).
+ */
+static int add_system_ram_resources(void)
+{
+       struct memblock_region *reg;
+
+       for_each_memblock(memory, reg) {
+               struct resource *res;
+               unsigned long base = reg->base;
+               unsigned long size = reg->size;
+
+               res = kzalloc(sizeof(struct resource), GFP_KERNEL);
+               WARN_ON(!res);
+
+               if (res) {
+                       res->name = "System RAM";
+                       res->start = base;
+                       res->end = base + size - 1;
+                       res->flags = IORESOURCE_MEM;
+                       WARN_ON(request_resource(&iomem_resource, res) < 0);
+               }
+       }
+
+       return 0;
+}
+subsys_initcall(add_system_ram_resources);
index c7dd4de..b22a83a 100644 (file)
@@ -315,7 +315,10 @@ static int __init find_min_common_depth(void)
        struct device_node *root;
        const char *vec5;
 
-       root = of_find_node_by_path("/rtas");
+       if (firmware_has_feature(FW_FEATURE_OPAL))
+               root = of_find_node_by_path("/ibm,opal");
+       else
+               root = of_find_node_by_path("/rtas");
        if (!root)
                root = of_find_node_by_path("/");
 
@@ -344,12 +347,19 @@ static int __init find_min_common_depth(void)
 
 #define VEC5_AFFINITY_BYTE     5
 #define VEC5_AFFINITY          0x80
-       chosen = of_find_node_by_path("/chosen");
-       if (chosen) {
-               vec5 = of_get_property(chosen, "ibm,architecture-vec-5", NULL);
-               if (vec5 && (vec5[VEC5_AFFINITY_BYTE] & VEC5_AFFINITY)) {
-                       dbg("Using form 1 affinity\n");
-                       form1_affinity = 1;
+
+       if (firmware_has_feature(FW_FEATURE_OPAL))
+               form1_affinity = 1;
+       else {
+               chosen = of_find_node_by_path("/chosen");
+               if (chosen) {
+                       vec5 = of_get_property(chosen,
+                                              "ibm,architecture-vec-5", NULL);
+                       if (vec5 && (vec5[VEC5_AFFINITY_BYTE] &
+                                                       VEC5_AFFINITY)) {
+                               dbg("Using form 1 affinity\n");
+                               form1_affinity = 1;
+                       }
                }
        }
 
index e36d6e2..846b789 100644 (file)
@@ -50,6 +50,7 @@ static void __init mpc5200_simple_setup_arch(void)
 
 /* list of the supported boards */
 static const char *board[] __initdata = {
+       "anon,charon",
        "intercontrol,digsy-mtc",
        "manroland,mucmc52",
        "manroland,uc101",
index e458872..3fe6d92 100644 (file)
@@ -347,7 +347,7 @@ config SIMPLE_GPIO
 
 config MCU_MPC8349EMITX
        bool "MPC8349E-mITX MCU driver"
-       depends on I2C && PPC_83xx
+       depends on I2C=y && PPC_83xx
        select GENERIC_GPIO
        select ARCH_REQUIRE_GPIOLIB
        help
index 232fc38..852592b 100644 (file)
@@ -230,7 +230,7 @@ static int __init beat_register_event(void)
                }
                ev->virq = virq;
 
-               rc = request_irq(virq, ev->handler, IRQF_DISABLED,
+               rc = request_irq(virq, ev->handler, 0,
                                      ev->typecode, NULL);
                if (rc != 0) {
                        printk(KERN_ERR "Beat: failed to request virtual IRQ"
index ae790ac..14be2bd 100644 (file)
@@ -514,7 +514,7 @@ static __init int celleb_setup_pciex(struct device_node *node,
        virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
                                     oirq.size);
        if (request_irq(virq, pciex_handle_internal_irq,
-                       IRQF_DISABLED, "pciex", (void *)phb)) {
+                       0, "pciex", (void *)phb)) {
                pr_err("PCIEXC:Failed to request irq\n");
                goto error;
        }
index fc46fca..592c3d5 100644 (file)
@@ -412,8 +412,7 @@ static void cell_iommu_enable_hardware(struct cbe_iommu *iommu)
                        IIC_IRQ_IOEX_ATI | (iommu->nid << IIC_IRQ_NODE_SHIFT));
        BUG_ON(virq == NO_IRQ);
 
-       ret = request_irq(virq, ioc_interrupt, IRQF_DISABLED,
-                       iommu->name, iommu);
+       ret = request_irq(virq, ioc_interrupt, 0, iommu->name, iommu);
        BUG_ON(ret);
 
        /* set the IOC segment table origin register (and turn on the iommu) */
index 1acf360..59c1a16 100644 (file)
@@ -392,7 +392,7 @@ static int __init cbe_init_pm_irq(void)
                }
 
                rc = request_irq(irq, cbe_pm_irq,
-                                IRQF_DISABLED, "cbe-pmu-0", NULL);
+                                0, "cbe-pmu-0", NULL);
                if (rc) {
                        printk("ERROR: Request for irq on node %d failed\n",
                               node);
index 3675da7..e94d3ec 100644 (file)
@@ -442,8 +442,7 @@ static int spu_request_irqs(struct spu *spu)
                snprintf(spu->irq_c0, sizeof (spu->irq_c0), "spe%02d.0",
                         spu->number);
                ret = request_irq(spu->irqs[0], spu_irq_class_0,
-                                 IRQF_DISABLED,
-                                 spu->irq_c0, spu);
+                                 0, spu->irq_c0, spu);
                if (ret)
                        goto bail0;
        }
@@ -451,8 +450,7 @@ static int spu_request_irqs(struct spu *spu)
                snprintf(spu->irq_c1, sizeof (spu->irq_c1), "spe%02d.1",
                         spu->number);
                ret = request_irq(spu->irqs[1], spu_irq_class_1,
-                                 IRQF_DISABLED,
-                                 spu->irq_c1, spu);
+                                 0, spu->irq_c1, spu);
                if (ret)
                        goto bail1;
        }
@@ -460,8 +458,7 @@ static int spu_request_irqs(struct spu *spu)
                snprintf(spu->irq_c2, sizeof (spu->irq_c2), "spe%02d.2",
                         spu->number);
                ret = request_irq(spu->irqs[2], spu_irq_class_2,
-                                 IRQF_DISABLED,
-                                 spu->irq_c2, spu);
+                                 0, spu->irq_c2, spu);
                if (ret)
                        goto bail2;
        }
index cb40e92..901bfbd 100644 (file)
@@ -272,7 +272,6 @@ static struct irqaction xmon_action = {
 
 static struct irqaction gatwick_cascade_action = {
        .handler        = gatwick_action,
-       .flags          = IRQF_DISABLED,
        .name           = "cascade",
 };
 
index 9a521dc..9b6a820 100644 (file)
@@ -200,7 +200,7 @@ static int psurge_secondary_ipi_init(void)
 
        if (psurge_secondary_virq)
                rc = request_irq(psurge_secondary_virq, psurge_ipi_intr,
-                       IRQF_DISABLED|IRQF_PERCPU, "IPI", NULL);
+                       IRQF_PERCPU, "IPI", NULL);
 
        if (rc)
                pr_err("Failed to setup secondary cpu IPI\n");
@@ -408,7 +408,7 @@ static int __init smp_psurge_kick_cpu(int nr)
 
 static struct irqaction psurge_irqaction = {
        .handler = psurge_ipi_intr,
-       .flags = IRQF_DISABLED|IRQF_PERCPU,
+       .flags = IRQF_PERCPU,
        .name = "primary IPI",
 };
 
index 6c4b583..3f175e8 100644 (file)
@@ -825,7 +825,7 @@ static int ps3_probe_thread(void *data)
 
        spin_lock_init(&dev.lock);
 
-       res = request_irq(irq, ps3_notification_interrupt, IRQF_DISABLED,
+       res = request_irq(irq, ps3_notification_interrupt, 0,
                          "ps3_notification", &dev);
        if (res) {
                pr_err("%s:%u: request_irq failed %d\n", __func__, __LINE__,
index 404bc52..1d6f4f4 100644 (file)
@@ -88,6 +88,7 @@ struct ps3_private {
        struct ps3_bmp bmp __attribute__ ((aligned (PS3_BMP_MINALIGN)));
        u64 ppe_id;
        u64 thread_id;
+       unsigned long ipi_mask;
 };
 
 static DEFINE_PER_CPU(struct ps3_private, ps3_private);
@@ -144,7 +145,11 @@ static void ps3_chip_unmask(struct irq_data *d)
 static void ps3_chip_eoi(struct irq_data *d)
 {
        const struct ps3_private *pd = irq_data_get_irq_chip_data(d);
-       lv1_end_of_interrupt_ext(pd->ppe_id, pd->thread_id, d->irq);
+
+       /* non-IPIs are EOIed here. */
+
+       if (!test_bit(63 - d->irq, &pd->ipi_mask))
+               lv1_end_of_interrupt_ext(pd->ppe_id, pd->thread_id, d->irq);
 }
 
 /**
@@ -691,6 +696,16 @@ void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq)
                cpu, virq, pd->bmp.ipi_debug_brk_mask);
 }
 
+void __init ps3_register_ipi_irq(unsigned int cpu, unsigned int virq)
+{
+       struct ps3_private *pd = &per_cpu(ps3_private, cpu);
+
+       set_bit(63 - virq, &pd->ipi_mask);
+
+       DBG("%s:%d: cpu %u, virq %u, ipi_mask %lxh\n", __func__, __LINE__,
+               cpu, virq, pd->ipi_mask);
+}
+
 static unsigned int ps3_get_irq(void)
 {
        struct ps3_private *pd = &__get_cpu_var(ps3_private);
@@ -720,6 +735,12 @@ static unsigned int ps3_get_irq(void)
                BUG();
        }
 #endif
+
+       /* IPIs are EOIed here. */
+
+       if (test_bit(63 - plug, &pd->ipi_mask))
+               lv1_end_of_interrupt_ext(pd->ppe_id, pd->thread_id, plug);
+
        return plug;
 }
 
index 9a196a8..1a633ed 100644 (file)
@@ -43,6 +43,7 @@ void ps3_mm_shutdown(void);
 void ps3_init_IRQ(void);
 void ps3_shutdown_IRQ(int cpu);
 void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq);
+void __init ps3_register_ipi_irq(unsigned int cpu, unsigned int virq);
 
 /* smp */
 
index 5e304c2..ca40f6a 100644 (file)
@@ -184,7 +184,7 @@ int ps3_repository_read_bus_type(unsigned int bus_index,
        enum ps3_bus_type *bus_type)
 {
        int result;
-       u64 v1;
+       u64 v1 = 0;
 
        result = read_node(PS3_LPAR_ID_PME,
                make_first_field("bus", bus_index),
@@ -199,7 +199,7 @@ int ps3_repository_read_bus_num_dev(unsigned int bus_index,
        unsigned int *num_dev)
 {
        int result;
-       u64 v1;
+       u64 v1 = 0;
 
        result = read_node(PS3_LPAR_ID_PME,
                make_first_field("bus", bus_index),
@@ -239,7 +239,7 @@ int ps3_repository_read_dev_type(unsigned int bus_index,
        unsigned int dev_index, enum ps3_dev_type *dev_type)
 {
        int result;
-       u64 v1;
+       u64 v1 = 0;
 
        result = read_node(PS3_LPAR_ID_PME,
                make_first_field("bus", bus_index),
@@ -256,8 +256,8 @@ int ps3_repository_read_dev_intr(unsigned int bus_index,
        enum ps3_interrupt_type *intr_type, unsigned int *interrupt_id)
 {
        int result;
-       u64 v1;
-       u64 v2;
+       u64 v1 = 0;
+       u64 v2 = 0;
 
        result = read_node(PS3_LPAR_ID_PME,
                make_first_field("bus", bus_index),
@@ -275,7 +275,7 @@ int ps3_repository_read_dev_reg_type(unsigned int bus_index,
        enum ps3_reg_type *reg_type)
 {
        int result;
-       u64 v1;
+       u64 v1 = 0;
 
        result = read_node(PS3_LPAR_ID_PME,
                make_first_field("bus", bus_index),
@@ -615,7 +615,7 @@ int ps3_repository_read_stor_dev_num_regions(unsigned int bus_index,
        unsigned int dev_index, unsigned int *num_regions)
 {
        int result;
-       u64 v1;
+       u64 v1 = 0;
 
        result = read_node(PS3_LPAR_ID_PME,
                make_first_field("bus", bus_index),
@@ -631,7 +631,7 @@ int ps3_repository_read_stor_dev_region_id(unsigned int bus_index,
        unsigned int *region_id)
 {
        int result;
-       u64 v1;
+       u64 v1 = 0;
 
        result = read_node(PS3_LPAR_ID_PME,
            make_first_field("bus", bus_index),
@@ -786,7 +786,7 @@ int ps3_repository_read_mm_info(u64 *rm_base, u64 *rm_size, u64 *region_total)
 int ps3_repository_read_num_spu_reserved(unsigned int *num_spu_reserved)
 {
        int result;
-       u64 v1;
+       u64 v1 = 0;
 
        result = read_node(PS3_LPAR_ID_CURRENT,
                make_first_field("bi", 0),
@@ -805,7 +805,7 @@ int ps3_repository_read_num_spu_reserved(unsigned int *num_spu_reserved)
 int ps3_repository_read_num_spu_resource_id(unsigned int *num_resource_id)
 {
        int result;
-       u64 v1;
+       u64 v1 = 0;
 
        result = read_node(PS3_LPAR_ID_CURRENT,
                make_first_field("bi", 0),
@@ -827,8 +827,8 @@ int ps3_repository_read_spu_resource_id(unsigned int res_index,
        enum ps3_spu_resource_type *resource_type, unsigned int *resource_id)
 {
        int result;
-       u64 v1;
-       u64 v2;
+       u64 v1 = 0;
+       u64 v2 = 0;
 
        result = read_node(PS3_LPAR_ID_CURRENT,
                make_first_field("bi", 0),
@@ -854,7 +854,7 @@ static int ps3_repository_read_boot_dat_address(u64 *address)
 int ps3_repository_read_boot_dat_size(unsigned int *size)
 {
        int result;
-       u64 v1;
+       u64 v1 = 0;
 
        result = read_node(PS3_LPAR_ID_CURRENT,
                make_first_field("bi", 0),
@@ -869,7 +869,7 @@ int ps3_repository_read_boot_dat_size(unsigned int *size)
 int ps3_repository_read_vuart_av_port(unsigned int *port)
 {
        int result;
-       u64 v1;
+       u64 v1 = 0;
 
        result = read_node(PS3_LPAR_ID_CURRENT,
                make_first_field("bi", 0),
@@ -884,7 +884,7 @@ int ps3_repository_read_vuart_av_port(unsigned int *port)
 int ps3_repository_read_vuart_sysmgr_port(unsigned int *port)
 {
        int result;
-       u64 v1;
+       u64 v1 = 0;
 
        result = read_node(PS3_LPAR_ID_CURRENT,
                make_first_field("bi", 0),
@@ -919,7 +919,7 @@ int ps3_repository_read_boot_dat_info(u64 *lpar_addr, unsigned int *size)
 int ps3_repository_read_num_be(unsigned int *num_be)
 {
        int result;
-       u64 v1;
+       u64 v1 = 0;
 
        result = read_node(PS3_LPAR_ID_PME,
                make_first_field("ben", 0),
index 4c44794..efc1cd8 100644 (file)
@@ -59,46 +59,49 @@ static void ps3_smp_message_pass(int cpu, int msg)
 
 static int ps3_smp_probe(void)
 {
-       return 2;
-}
+       int cpu;
 
-static void __init ps3_smp_setup_cpu(int cpu)
-{
-       int result;
-       unsigned int *virqs = per_cpu(ps3_ipi_virqs, cpu);
-       int i;
+       for (cpu = 0; cpu < 2; cpu++) {
+               int result;
+               unsigned int *virqs = per_cpu(ps3_ipi_virqs, cpu);
+               int i;
 
-       DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu);
+               DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu);
 
-       /*
-        * Check assumptions on ps3_ipi_virqs[] indexing. If this
-        * check fails, then a different mapping of PPC_MSG_
-        * to index needs to be setup.
-        */
+               /*
+               * Check assumptions on ps3_ipi_virqs[] indexing. If this
+               * check fails, then a different mapping of PPC_MSG_
+               * to index needs to be setup.
+               */
 
-       BUILD_BUG_ON(PPC_MSG_CALL_FUNCTION    != 0);
-       BUILD_BUG_ON(PPC_MSG_RESCHEDULE       != 1);
-       BUILD_BUG_ON(PPC_MSG_CALL_FUNC_SINGLE != 2);
-       BUILD_BUG_ON(PPC_MSG_DEBUGGER_BREAK   != 3);
+               BUILD_BUG_ON(PPC_MSG_CALL_FUNCTION    != 0);
+               BUILD_BUG_ON(PPC_MSG_RESCHEDULE       != 1);
+               BUILD_BUG_ON(PPC_MSG_CALL_FUNC_SINGLE != 2);
+               BUILD_BUG_ON(PPC_MSG_DEBUGGER_BREAK   != 3);
 
-       for (i = 0; i < MSG_COUNT; i++) {
-               result = ps3_event_receive_port_setup(cpu, &virqs[i]);
+               for (i = 0; i < MSG_COUNT; i++) {
+                       result = ps3_event_receive_port_setup(cpu, &virqs[i]);
 
-               if (result)
-                       continue;
+                       if (result)
+                               continue;
 
-               DBG("%s:%d: (%d, %d) => virq %u\n",
-                       __func__, __LINE__, cpu, i, virqs[i]);
+                       DBG("%s:%d: (%d, %d) => virq %u\n",
+                               __func__, __LINE__, cpu, i, virqs[i]);
 
-               result = smp_request_message_ipi(virqs[i], i);
+                       result = smp_request_message_ipi(virqs[i], i);
 
-               if (result)
-                       virqs[i] = NO_IRQ;
-       }
+                       if (result)
+                               virqs[i] = NO_IRQ;
+                       else
+                               ps3_register_ipi_irq(cpu, virqs[i]);
+               }
 
-       ps3_register_ipi_debug_brk(cpu, virqs[PPC_MSG_DEBUGGER_BREAK]);
+               ps3_register_ipi_debug_brk(cpu, virqs[PPC_MSG_DEBUGGER_BREAK]);
 
-       DBG(" <- %s:%d: (%d)\n", __func__, __LINE__, cpu);
+               DBG(" <- %s:%d: (%d)\n", __func__, __LINE__, cpu);
+       }
+
+       return 2;
 }
 
 void ps3_smp_cleanup_cpu(int cpu)
@@ -121,7 +124,6 @@ static struct smp_ops_t ps3_smp_ops = {
        .probe          = ps3_smp_probe,
        .message_pass   = ps3_smp_message_pass,
        .kick_cpu       = smp_generic_kick_cpu,
-       .setup_cpu      = ps3_smp_setup_cpu,
 };
 
 void smp_init_ps3(void)
index de170fd..22ffccd 100644 (file)
@@ -23,7 +23,7 @@
  */
 
 #include <linux/init.h>
-#include <linux/export.h>
+#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/dma-mapping.h>
 #include <linux/interrupt.h>
index 0842c6f..8c7e852 100644 (file)
@@ -800,8 +800,6 @@ static void mpic_end_ipi(struct irq_data *d)
         * IPIs are marked IRQ_PER_CPU. This has the side effect of
         * preventing the IRQ_PENDING/IRQ_INPROGRESS logic from
         * applying to them. We EOI them late to avoid re-entering.
-        * We mark IPI's with IRQF_DISABLED as they must run with
-        * irqs disabled.
         */
        mpic_eoi(mpic);
 }
index d3d6ce3..0debcc3 100644 (file)
@@ -115,7 +115,7 @@ static int __init ppc4xx_l2c_probe(void)
        }
 
        /* Install error handler */
-       if (request_irq(irq, l2c_error_handler, IRQF_DISABLED, "L2C", 0) < 0) {
+       if (request_irq(irq, l2c_error_handler, 0, "L2C", 0) < 0) {
                printk(KERN_ERR "Cannot install L2C error handler"
                       ", cache is not enabled\n");
                of_node_put(np);
index 3d93a8d..63762c6 100644 (file)
@@ -134,11 +134,10 @@ static void xics_request_ipi(void)
        BUG_ON(ipi == NO_IRQ);
 
        /*
-        * IPIs are marked IRQF_DISABLED as they must run with irqs
-        * disabled, and PERCPU.  The handler was set in map.
+        * IPIs are marked IRQF_PERCPU. The handler was set in map.
         */
        BUG_ON(request_irq(ipi, icp_ops->ipi_action,
-                          IRQF_DISABLED|IRQF_PERCPU, "IPI", NULL));
+                          IRQF_PERCPU, "IPI", NULL));
 }
 
 int __init xics_smp_probe(void)
index a9fbd43..373679b 100644 (file)
@@ -572,6 +572,7 @@ config KEXEC
 config CRASH_DUMP
        bool "kernel crash dumps"
        depends on 64BIT
+       select KEXEC
        help
          Generate crash dump after being started by kexec.
          Crash dump kernels are loaded in the main kernel with kexec-tools
index 4967677..ffd1ac2 100644 (file)
@@ -368,9 +368,12 @@ static inline int crypt_s390_func_available(int func,
 
        if (facility_mask & CRYPT_S390_MSA && !test_facility(17))
                return 0;
-       if (facility_mask & CRYPT_S390_MSA3 && !test_facility(76))
+
+       if (facility_mask & CRYPT_S390_MSA3 &&
+           (!test_facility(2) || !test_facility(76)))
                return 0;
-       if (facility_mask & CRYPT_S390_MSA4 && !test_facility(77))
+       if (facility_mask & CRYPT_S390_MSA4 &&
+           (!test_facility(2) || !test_facility(77)))
                return 0;
 
        switch (func & CRYPT_S390_OP_MASK) {
index 24e1847..b0c235c 100644 (file)
@@ -47,7 +47,7 @@ struct sca_block {
 #define KVM_HPAGE_MASK(x)      (~(KVM_HPAGE_SIZE(x) - 1))
 #define KVM_PAGES_PER_HPAGE(x) (KVM_HPAGE_SIZE(x) / PAGE_SIZE)
 
-#define CPUSTAT_HOST       0x80000000
+#define CPUSTAT_STOPPED    0x80000000
 #define CPUSTAT_WAIT       0x10000000
 #define CPUSTAT_ECALL_PEND 0x08000000
 #define CPUSTAT_STOP_INT   0x04000000
@@ -139,6 +139,7 @@ struct kvm_vcpu_stat {
        u32 instruction_stfl;
        u32 instruction_tprot;
        u32 instruction_sigp_sense;
+       u32 instruction_sigp_sense_running;
        u32 instruction_sigp_external_call;
        u32 instruction_sigp_emergency;
        u32 instruction_sigp_stop;
index 34ede0e..524d23b 100644 (file)
@@ -593,6 +593,8 @@ static inline pgste_t pgste_update_all(pte_t *ptep, pgste_t pgste)
        unsigned long address, bits;
        unsigned char skey;
 
+       if (!pte_present(*ptep))
+               return pgste;
        address = pte_val(*ptep) & PAGE_MASK;
        skey = page_get_storage_key(address);
        bits = skey & (_PAGE_CHANGED | _PAGE_REFERENCED);
@@ -625,6 +627,8 @@ static inline pgste_t pgste_update_young(pte_t *ptep, pgste_t pgste)
 #ifdef CONFIG_PGSTE
        int young;
 
+       if (!pte_present(*ptep))
+               return pgste;
        young = page_reset_referenced(pte_val(*ptep) & PAGE_MASK);
        /* Transfer page referenced bit to pte software bit (host view) */
        if (young || (pgste_val(pgste) & RCP_HR_BIT))
@@ -638,13 +642,15 @@ static inline pgste_t pgste_update_young(pte_t *ptep, pgste_t pgste)
 
 }
 
-static inline void pgste_set_pte(pte_t *ptep, pgste_t pgste)
+static inline void pgste_set_pte(pte_t *ptep, pgste_t pgste, pte_t entry)
 {
 #ifdef CONFIG_PGSTE
        unsigned long address;
        unsigned long okey, nkey;
 
-       address = pte_val(*ptep) & PAGE_MASK;
+       if (!pte_present(entry))
+               return;
+       address = pte_val(entry) & PAGE_MASK;
        okey = nkey = page_get_storage_key(address);
        nkey &= ~(_PAGE_ACC_BITS | _PAGE_FP_BIT);
        /* Set page access key and fetch protection bit from pgste */
@@ -712,7 +718,7 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
 
        if (mm_has_pgste(mm)) {
                pgste = pgste_get_lock(ptep);
-               pgste_set_pte(ptep, pgste);
+               pgste_set_pte(ptep, pgste, entry);
                *ptep = entry;
                pgste_set_unlock(ptep, pgste);
        } else
index 5a09971..097183c 100644 (file)
@@ -82,6 +82,7 @@ extern unsigned int user_mode;
 #define MACHINE_FLAG_LPAR      (1UL << 12)
 #define MACHINE_FLAG_SPP       (1UL << 13)
 #define MACHINE_FLAG_TOPOLOGY  (1UL << 14)
+#define MACHINE_FLAG_STCKF     (1UL << 15)
 
 #define MACHINE_IS_VM          (S390_lowcore.machine_flags & MACHINE_FLAG_VM)
 #define MACHINE_IS_KVM         (S390_lowcore.machine_flags & MACHINE_FLAG_KVM)
@@ -100,6 +101,7 @@ extern unsigned int user_mode;
 #define MACHINE_HAS_PFMF       (0)
 #define MACHINE_HAS_SPP                (0)
 #define MACHINE_HAS_TOPOLOGY   (0)
+#define MACHINE_HAS_STCKF      (0)
 #else /* __s390x__ */
 #define MACHINE_HAS_IEEE       (1)
 #define MACHINE_HAS_CSP                (1)
@@ -111,6 +113,7 @@ extern unsigned int user_mode;
 #define MACHINE_HAS_PFMF       (S390_lowcore.machine_flags & MACHINE_FLAG_PFMF)
 #define MACHINE_HAS_SPP                (S390_lowcore.machine_flags & MACHINE_FLAG_SPP)
 #define MACHINE_HAS_TOPOLOGY   (S390_lowcore.machine_flags & MACHINE_FLAG_TOPOLOGY)
+#define MACHINE_HAS_STCKF      (S390_lowcore.machine_flags & MACHINE_FLAG_STCKF)
 #endif /* __s390x__ */
 
 #define ZFCPDUMP_HSA_SIZE      (32UL<<20)
index fdff1e9..67b5c1b 100644 (file)
@@ -70,4 +70,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #endif /* _ASM_SOCKET_H */
index d610bef..c447a27 100644 (file)
@@ -90,7 +90,7 @@ static inline unsigned long long get_clock_fast(void)
 {
        unsigned long long clk;
 
-       if (test_facility(25))
+       if (MACHINE_HAS_STCKF)
                asm volatile(".insn     s,0xb27c0000,%0" : "=Q" (clk) : : "cc");
        else
                clk = get_clock();
index 404bdb9..58de4c9 100644 (file)
 #define __NR_clock_adjtime     337
 #define __NR_syncfs            338
 #define __NR_setns             339
-#define NR_syscalls 340
+#define __NR_process_vm_readv  340
+#define __NR_process_vm_writev 341
+#define NR_syscalls 342
 
 /* 
  * There are some system calls that are not present on 64 bit, some
index 5006a1d..18c51df 100644 (file)
@@ -1627,3 +1627,23 @@ ENTRY(sys_setns_wrapper)
        lgfr    %r2,%r2                 # int
        lgfr    %r3,%r3                 # int
        jg      sys_setns
+
+ENTRY(compat_sys_process_vm_readv_wrapper)
+       lgfr    %r2,%r2                 # compat_pid_t
+       llgtr   %r3,%r3                 # struct compat_iovec __user *
+       llgfr   %r4,%r4                 # unsigned long
+       llgtr   %r5,%r5                 # struct compat_iovec __user *
+       llgfr   %r6,%r6                 # unsigned long
+       llgf    %r0,164(%r15)           # unsigned long
+       stg     %r0,160(%r15)
+       jg      sys_process_vm_readv
+
+ENTRY(compat_sys_process_vm_writev_wrapper)
+       lgfr    %r2,%r2                 # compat_pid_t
+       llgtr   %r3,%r3                 # struct compat_iovec __user *
+       llgfr   %r4,%r4                 # unsigned long
+       llgtr   %r5,%r5                 # struct compat_iovec __user *
+       llgfr   %r6,%r6                 # unsigned long
+       llgf    %r0,164(%r15)           # unsigned long
+       stg     %r0,160(%r15)
+       jg      sys_process_vm_writev
index 37394b3..c9ffe00 100644 (file)
@@ -390,6 +390,8 @@ static __init void detect_machine_facilities(void)
                S390_lowcore.machine_flags |= MACHINE_FLAG_MVCOS;
        if (test_facility(40))
                S390_lowcore.machine_flags |= MACHINE_FLAG_SPP;
+       if (test_facility(25))
+               S390_lowcore.machine_flags |= MACHINE_FLAG_STCKF;
 #endif
 }
 
index 8ac6bfa..e58a462 100644 (file)
@@ -211,6 +211,8 @@ static void __init setup_zfcpdump(unsigned int console_devno)
 
        if (ipl_info.type != IPL_TYPE_FCP_DUMP)
                return;
+       if (OLDMEM_BASE)
+               return;
        if (console_devno != -1)
                sprintf(str, " cio_ignore=all,!0.0.%04x,!0.0.%04x",
                        ipl_info.data.fcp.dev_id.devno, console_devno);
@@ -482,7 +484,7 @@ static void __init setup_memory_end(void)
 
 
 #ifdef CONFIG_ZFCPDUMP
-       if (ipl_info.type == IPL_TYPE_FCP_DUMP) {
+       if (ipl_info.type == IPL_TYPE_FCP_DUMP && !OLDMEM_BASE) {
                memory_end = ZFCPDUMP_HSA_SIZE;
                memory_end_set = 1;
        }
index 73eb08c..bcab2f0 100644 (file)
@@ -348,3 +348,5 @@ SYSCALL(sys_open_by_handle_at,sys_open_by_handle_at,compat_sys_open_by_handle_at
 SYSCALL(sys_clock_adjtime,sys_clock_adjtime,compat_sys_clock_adjtime_wrapper)
 SYSCALL(sys_syncfs,sys_syncfs,sys_syncfs_wrapper)
 SYSCALL(sys_setns,sys_setns,sys_setns_wrapper)
+SYSCALL(sys_process_vm_readv,sys_process_vm_readv,compat_sys_process_vm_readv_wrapper) /* 340 */
+SYSCALL(sys_process_vm_writev,sys_process_vm_writev,compat_sys_process_vm_writev_wrapper)
index 77b8942..fdb5b8c 100644 (file)
@@ -68,8 +68,10 @@ static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu)
        return mask;
 }
 
-static void add_cpus_to_mask(struct topology_cpu *tl_cpu,
-                            struct mask_info *book, struct mask_info *core)
+static struct mask_info *add_cpus_to_mask(struct topology_cpu *tl_cpu,
+                                         struct mask_info *book,
+                                         struct mask_info *core,
+                                         int z10)
 {
        unsigned int cpu;
 
@@ -88,10 +90,16 @@ static void add_cpus_to_mask(struct topology_cpu *tl_cpu,
                        cpu_book_id[lcpu] = book->id;
 #endif
                        cpumask_set_cpu(lcpu, &core->mask);
-                       cpu_core_id[lcpu] = core->id;
+                       if (z10) {
+                               cpu_core_id[lcpu] = rcpu;
+                               core = core->next;
+                       } else {
+                               cpu_core_id[lcpu] = core->id;
+                       }
                        smp_cpu_polarization[lcpu] = tl_cpu->pp;
                }
        }
+       return core;
 }
 
 static void clear_masks(void)
@@ -123,18 +131,41 @@ static void tl_to_cores(struct sysinfo_15_1_x *info)
 {
 #ifdef CONFIG_SCHED_BOOK
        struct mask_info *book = &book_info;
+       struct cpuid cpu_id;
 #else
        struct mask_info *book = NULL;
 #endif
        struct mask_info *core = &core_info;
        union topology_entry *tle, *end;
+       int z10 = 0;
 
-
+#ifdef CONFIG_SCHED_BOOK
+       get_cpu_id(&cpu_id);
+       z10 = cpu_id.machine == 0x2097 || cpu_id.machine == 0x2098;
+#endif
        spin_lock_irq(&topology_lock);
        clear_masks();
        tle = info->tle;
        end = (union topology_entry *)((unsigned long)info + info->length);
        while (tle < end) {
+#ifdef CONFIG_SCHED_BOOK
+               if (z10) {
+                       switch (tle->nl) {
+                       case 1:
+                               book = book->next;
+                               book->id = tle->container.id;
+                               break;
+                       case 0:
+                               core = add_cpus_to_mask(&tle->cpu, book, core, z10);
+                               break;
+                       default:
+                               clear_masks();
+                               goto out;
+                       }
+                       tle = next_tle(tle);
+                       continue;
+               }
+#endif
                switch (tle->nl) {
 #ifdef CONFIG_SCHED_BOOK
                case 2:
@@ -147,7 +178,7 @@ static void tl_to_cores(struct sysinfo_15_1_x *info)
                        core->id = tle->container.id;
                        break;
                case 0:
-                       add_cpus_to_mask(&tle->cpu, book, core);
+                       add_cpus_to_mask(&tle->cpu, book, core, z10);
                        break;
                default:
                        clear_masks();
@@ -328,8 +359,8 @@ void __init s390_init_cpu_topology(void)
        for (i = 0; i < TOPOLOGY_NR_MAG; i++)
                printk(" %d", info->mag[i]);
        printk(" / %d\n", info->mnest);
-       alloc_masks(info, &core_info, 2);
+       alloc_masks(info, &core_info, 1);
 #ifdef CONFIG_SCHED_BOOK
-       alloc_masks(info, &book_info, 3);
+       alloc_masks(info, &book_info, 2);
 #endif
 }
index 56fe6bc..e4c79eb 100644 (file)
@@ -43,6 +43,8 @@ SECTIONS
 
        NOTES :text :note
 
+       .dummy : { *(.dummy) } :data
+
        RODATA
 
 #ifdef CONFIG_SHARED_KERNEL
index 87cedd6..8943e82 100644 (file)
@@ -70,7 +70,7 @@ static int __diag_ipl_functions(struct kvm_vcpu *vcpu)
                return -EOPNOTSUPP;
        }
 
-       atomic_clear_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags);
+       atomic_set_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags);
        vcpu->run->s390_reset_flags |= KVM_S390_RESET_SUBSYSTEM;
        vcpu->run->s390_reset_flags |= KVM_S390_RESET_IPL;
        vcpu->run->s390_reset_flags |= KVM_S390_RESET_CPU_INIT;
index c7c5189..0243454 100644 (file)
@@ -132,7 +132,6 @@ static int handle_stop(struct kvm_vcpu *vcpu)
        int rc = 0;
 
        vcpu->stat.exit_stop_request++;
-       atomic_clear_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags);
        spin_lock_bh(&vcpu->arch.local_int.lock);
        if (vcpu->arch.local_int.action_bits & ACTION_STORE_ON_STOP) {
                vcpu->arch.local_int.action_bits &= ~ACTION_STORE_ON_STOP;
@@ -149,6 +148,8 @@ static int handle_stop(struct kvm_vcpu *vcpu)
        }
 
        if (vcpu->arch.local_int.action_bits & ACTION_STOP_ON_STOP) {
+               atomic_set_mask(CPUSTAT_STOPPED,
+                               &vcpu->arch.sie_block->cpuflags);
                vcpu->arch.local_int.action_bits &= ~ACTION_STOP_ON_STOP;
                VCPU_EVENT(vcpu, 3, "%s", "cpu stopped");
                rc = -EOPNOTSUPP;
index 87c1670..278ee00 100644 (file)
@@ -252,6 +252,7 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
                        offsetof(struct _lowcore, restart_psw), sizeof(psw_t));
                if (rc == -EFAULT)
                        exception = 1;
+               atomic_clear_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags);
                break;
 
        case KVM_S390_PROGRAM_INT:
index 0bd3bea..d1c4457 100644 (file)
@@ -65,6 +65,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
        { "instruction_stfl", VCPU_STAT(instruction_stfl) },
        { "instruction_tprot", VCPU_STAT(instruction_tprot) },
        { "instruction_sigp_sense", VCPU_STAT(instruction_sigp_sense) },
+       { "instruction_sigp_sense_running", VCPU_STAT(instruction_sigp_sense_running) },
        { "instruction_sigp_external_call", VCPU_STAT(instruction_sigp_external_call) },
        { "instruction_sigp_emergency", VCPU_STAT(instruction_sigp_emergency) },
        { "instruction_sigp_stop", VCPU_STAT(instruction_sigp_stop) },
@@ -127,6 +128,7 @@ int kvm_dev_ioctl_check_extension(long ext)
        switch (ext) {
        case KVM_CAP_S390_PSW:
        case KVM_CAP_S390_GMAP:
+       case KVM_CAP_SYNC_MMU:
                r = 1;
                break;
        default:
@@ -270,10 +272,12 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
        restore_fp_regs(&vcpu->arch.guest_fpregs);
        restore_access_regs(vcpu->arch.guest_acrs);
        gmap_enable(vcpu->arch.gmap);
+       atomic_set_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags);
 }
 
 void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
 {
+       atomic_clear_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags);
        gmap_disable(vcpu->arch.gmap);
        save_fp_regs(&vcpu->arch.guest_fpregs);
        save_access_regs(vcpu->arch.guest_acrs);
@@ -301,7 +305,9 @@ static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu)
 
 int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
 {
-       atomic_set(&vcpu->arch.sie_block->cpuflags, CPUSTAT_ZARCH | CPUSTAT_SM);
+       atomic_set(&vcpu->arch.sie_block->cpuflags, CPUSTAT_ZARCH |
+                                                   CPUSTAT_SM |
+                                                   CPUSTAT_STOPPED);
        vcpu->arch.sie_block->ecb   = 6;
        vcpu->arch.sie_block->eca   = 0xC1002001U;
        vcpu->arch.sie_block->fac   = (int) (long) facilities;
@@ -428,7 +434,7 @@ static int kvm_arch_vcpu_ioctl_set_initial_psw(struct kvm_vcpu *vcpu, psw_t psw)
 {
        int rc = 0;
 
-       if (atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_RUNNING)
+       if (!(atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_STOPPED))
                rc = -EBUSY;
        else {
                vcpu->run->psw_mask = psw.mask;
@@ -501,7 +507,7 @@ rerun_vcpu:
        if (vcpu->sigset_active)
                sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);
 
-       atomic_set_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags);
+       atomic_clear_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags);
 
        BUG_ON(vcpu->kvm->arch.float_int.local_int[vcpu->vcpu_id] == NULL);
 
index 3916263..d026389 100644 (file)
@@ -336,6 +336,7 @@ static int handle_tprot(struct kvm_vcpu *vcpu)
        u64 address1 = disp1 + base1 ? vcpu->arch.guest_gprs[base1] : 0;
        u64 address2 = disp2 + base2 ? vcpu->arch.guest_gprs[base2] : 0;
        struct vm_area_struct *vma;
+       unsigned long user_address;
 
        vcpu->stat.instruction_tprot++;
 
@@ -349,9 +350,14 @@ static int handle_tprot(struct kvm_vcpu *vcpu)
                return -EOPNOTSUPP;
 
 
+       /* we must resolve the address without holding the mmap semaphore.
+        * This is ok since the userspace hypervisor is not supposed to change
+        * the mapping while the guest queries the memory. Otherwise the guest
+        * might crash or get wrong info anyway. */
+       user_address = (unsigned long) __guestaddr_to_user(vcpu, address1);
+
        down_read(&current->mm->mmap_sem);
-       vma = find_vma(current->mm,
-                       (unsigned long) __guestaddr_to_user(vcpu, address1));
+       vma = find_vma(current->mm, user_address);
        if (!vma) {
                up_read(&current->mm->mmap_sem);
                return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
index f815118..0a7941d 100644 (file)
 #define SIGP_SET_PREFIX        0x0d
 #define SIGP_STORE_STATUS_ADDR 0x0e
 #define SIGP_SET_ARCH          0x12
+#define SIGP_SENSE_RUNNING     0x15
 
 /* cpu status bits */
 #define SIGP_STAT_EQUIPMENT_CHECK   0x80000000UL
+#define SIGP_STAT_NOT_RUNNING      0x00000400UL
 #define SIGP_STAT_INCORRECT_STATE   0x00000200UL
 #define SIGP_STAT_INVALID_PARAMETER 0x00000100UL
 #define SIGP_STAT_EXT_CALL_PENDING  0x00000080UL
@@ -57,8 +59,8 @@ static int __sigp_sense(struct kvm_vcpu *vcpu, u16 cpu_addr,
        spin_lock(&fi->lock);
        if (fi->local_int[cpu_addr] == NULL)
                rc = 3; /* not operational */
-       else if (atomic_read(fi->local_int[cpu_addr]->cpuflags)
-                & CPUSTAT_RUNNING) {
+       else if (!(atomic_read(fi->local_int[cpu_addr]->cpuflags)
+                 & CPUSTAT_STOPPED)) {
                *reg &= 0xffffffff00000000UL;
                rc = 1; /* status stored */
        } else {
@@ -251,7 +253,7 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address,
 
        spin_lock_bh(&li->lock);
        /* cpu must be in stopped state */
-       if (atomic_read(li->cpuflags) & CPUSTAT_RUNNING) {
+       if (!(atomic_read(li->cpuflags) & CPUSTAT_STOPPED)) {
                rc = 1; /* incorrect state */
                *reg &= SIGP_STAT_INCORRECT_STATE;
                kfree(inti);
@@ -275,6 +277,38 @@ out_fi:
        return rc;
 }
 
+static int __sigp_sense_running(struct kvm_vcpu *vcpu, u16 cpu_addr,
+                               unsigned long *reg)
+{
+       int rc;
+       struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
+
+       if (cpu_addr >= KVM_MAX_VCPUS)
+               return 3; /* not operational */
+
+       spin_lock(&fi->lock);
+       if (fi->local_int[cpu_addr] == NULL)
+               rc = 3; /* not operational */
+       else {
+               if (atomic_read(fi->local_int[cpu_addr]->cpuflags)
+                   & CPUSTAT_RUNNING) {
+                       /* running */
+                       rc = 1;
+               } else {
+                       /* not running */
+                       *reg &= 0xffffffff00000000UL;
+                       *reg |= SIGP_STAT_NOT_RUNNING;
+                       rc = 0;
+               }
+       }
+       spin_unlock(&fi->lock);
+
+       VCPU_EVENT(vcpu, 4, "sensed running status of cpu %x rc %x", cpu_addr,
+                  rc);
+
+       return rc;
+}
+
 int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu)
 {
        int r1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4;
@@ -331,6 +365,11 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu)
                rc = __sigp_set_prefix(vcpu, cpu_addr, parameter,
                                       &vcpu->arch.guest_gprs[r1]);
                break;
+       case SIGP_SENSE_RUNNING:
+               vcpu->stat.instruction_sigp_sense_running++;
+               rc = __sigp_sense_running(vcpu, cpu_addr,
+                                         &vcpu->arch.guest_gprs[r1]);
+               break;
        case SIGP_RESTART:
                vcpu->stat.instruction_sigp_restart++;
                /* user space must know about restart */
index 1766def..a9a3018 100644 (file)
@@ -587,8 +587,13 @@ static void pfault_interrupt(unsigned int ext_int_code,
                } else {
                        /* Completion interrupt was faster than initial
                         * interrupt. Set pfault_wait to -1 so the initial
-                        * interrupt doesn't put the task to sleep. */
-                       tsk->thread.pfault_wait = -1;
+                        * interrupt doesn't put the task to sleep.
+                        * If the task is not running, ignore the completion
+                        * interrupt since it must be a leftover of a PFAULT
+                        * CANCEL operation which didn't remove all pending
+                        * completion interrupts. */
+                       if (tsk->state == TASK_RUNNING)
+                               tsk->thread.pfault_wait = -1;
                }
                put_task_struct(tsk);
        } else {
index 0dca9a5..15d9703 100644 (file)
@@ -151,8 +151,13 @@ typedef struct page *pgtable_t;
 #endif /* !__ASSEMBLY__ */
 
 #ifdef CONFIG_UNCACHED_MAPPING
+#if defined(CONFIG_29BIT)
+#define UNCAC_ADDR(addr)       P2SEGADDR(addr)
+#define CAC_ADDR(addr)         P1SEGADDR(addr)
+#else
 #define UNCAC_ADDR(addr)       ((addr) - PAGE_OFFSET + uncached_start)
 #define CAC_ADDR(addr)         ((addr) - uncached_start + PAGE_OFFSET)
+#endif
 #else
 #define UNCAC_ADDR(addr)       ((addr))
 #define CAC_ADDR(addr)         ((addr))
index 3432008..152b862 100644 (file)
 #define __NR_syncfs            362
 #define __NR_sendmmsg          363
 #define __NR_setns             364
+#define __NR_process_vm_readv  365
+#define __NR_process_vm_writev 366
 
-#define NR_syscalls 365
+#define NR_syscalls 367
 
 #ifdef __KERNEL__
 
index ec98986..c330c23 100644 (file)
 #define __NR_syncfs            373
 #define __NR_sendmmsg          374
 #define __NR_setns             375
+#define __NR_process_vm_readv  376
+#define __NR_process_vm_writev 377
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 376
+#define NR_syscalls 378
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
index a43124e..0bd744f 100644 (file)
@@ -176,10 +176,12 @@ static DECLARE_INTC_DESC(intc_desc, "sh7203", vectors, groups,
 static struct plat_sci_port scif0_platform_data = {
        .mapbase        = 0xfffe8000,
        .flags          = UPF_BOOT_AUTOCONF,
-       .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
+       .scscr          = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+                         SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
        .irqs           =  { 192, 192, 192, 192 },
+       .regtype        = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif0_device = {
@@ -193,10 +195,12 @@ static struct platform_device scif0_device = {
 static struct plat_sci_port scif1_platform_data = {
        .mapbase        = 0xfffe8800,
        .flags          = UPF_BOOT_AUTOCONF,
-       .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
+       .scscr          = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+                         SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
        .irqs           =  { 196, 196, 196, 196 },
+       .regtype        = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif1_device = {
@@ -210,10 +214,12 @@ static struct platform_device scif1_device = {
 static struct plat_sci_port scif2_platform_data = {
        .mapbase        = 0xfffe9000,
        .flags          = UPF_BOOT_AUTOCONF,
-       .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
+       .scscr          = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+                         SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
        .irqs           =  { 200, 200, 200, 200 },
+       .regtype        = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif2_device = {
@@ -227,10 +233,12 @@ static struct platform_device scif2_device = {
 static struct plat_sci_port scif3_platform_data = {
        .mapbase        = 0xfffe9800,
        .flags          = UPF_BOOT_AUTOCONF,
-       .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
+       .scscr          = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+                         SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
        .irqs           =  { 204, 204, 204, 204 },
+       .regtype        = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif3_device = {
index 293e39c..ee56a9b 100644 (file)
@@ -382,3 +382,5 @@ ENTRY(sys_call_table)
        .long sys_syncfs
        .long sys_sendmmsg
        .long sys_setns
+       .long sys_process_vm_readv      /* 365 */
+       .long sys_process_vm_writev
index ceb34b9..9af7de2 100644 (file)
@@ -402,3 +402,5 @@ sys_call_table:
        .long sys_syncfs
        .long sys_sendmmsg
        .long sys_setns                 /* 375 */
+       .long sys_process_vm_readv
+       .long sys_process_vm_writev
index 5b31a8e..a790cc6 100644 (file)
@@ -431,10 +431,6 @@ extern unsigned long *sparc_valid_addr_bitmap;
 #define kern_addr_valid(addr) \
        (test_bit(__pa((unsigned long)(addr))>>20, sparc_valid_addr_bitmap))
 
-extern int io_remap_pfn_range(struct vm_area_struct *vma,
-                             unsigned long from, unsigned long pfn,
-                             unsigned long size, pgprot_t prot);
-
 /*
  * For sparc32&64, the pfn in io_remap_pfn_range() carries <iospace> in
  * its high 4 bits.  These macros/functions put it there or get it from there.
@@ -443,6 +439,22 @@ extern int io_remap_pfn_range(struct vm_area_struct *vma,
 #define GET_IOSPACE(pfn)               (pfn >> (BITS_PER_LONG - 4))
 #define GET_PFN(pfn)                   (pfn & 0x0fffffffUL)
 
+extern int remap_pfn_range(struct vm_area_struct *, unsigned long, unsigned long,
+                          unsigned long, pgprot_t);
+
+static inline int io_remap_pfn_range(struct vm_area_struct *vma,
+                                    unsigned long from, unsigned long pfn,
+                                    unsigned long size, pgprot_t prot)
+{
+       unsigned long long offset, space, phys_base;
+
+       offset = ((unsigned long long) GET_PFN(pfn)) << PAGE_SHIFT;
+       space = GET_IOSPACE(pfn);
+       phys_base = offset | (space << 32ULL);
+
+       return remap_pfn_range(vma, from, phys_base >> PAGE_SHIFT, size, prot);
+}
+
 #define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
 #define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
 ({                                                                       \
index adf8932..38ebb2c 100644 (file)
@@ -757,10 +757,6 @@ static inline bool kern_addr_valid(unsigned long addr)
 
 extern int page_in_phys_avail(unsigned long paddr);
 
-extern int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
-                              unsigned long pfn,
-                              unsigned long size, pgprot_t prot);
-
 /*
  * For sparc32&64, the pfn in io_remap_pfn_range() carries <iospace> in
  * its high 4 bits.  These macros/functions put it there or get it from there.
@@ -769,6 +765,22 @@ extern int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
 #define GET_IOSPACE(pfn)               (pfn >> (BITS_PER_LONG - 4))
 #define GET_PFN(pfn)                   (pfn & 0x0fffffffffffffffUL)
 
+extern int remap_pfn_range(struct vm_area_struct *, unsigned long, unsigned long,
+                          unsigned long, pgprot_t);
+
+static inline int io_remap_pfn_range(struct vm_area_struct *vma,
+                                    unsigned long from, unsigned long pfn,
+                                    unsigned long size, pgprot_t prot)
+{
+       unsigned long offset = GET_PFN(pfn) << PAGE_SHIFT;
+       int space = GET_IOSPACE(pfn);
+       unsigned long phys_base;
+
+       phys_base = offset | (((unsigned long) space) << 32UL);
+
+       return remap_pfn_range(vma, from, phys_base >> PAGE_SHIFT, size, prot);
+}
+
 #include <asm-generic/pgtable.h>
 
 /* We provide our own get_unmapped_area to cope with VA holes and
index 9d3fefc..8af1b64 100644 (file)
@@ -58,6 +58,9 @@
 
 #define SO_RXQ_OVFL             0x0024
 
+#define SO_WIFI_STATUS         0x0025
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 /* Security levels - as per NRL IPv6 - don't actually do anything */
 #define SO_SECURITY_AUTHENTICATION             0x5001
 #define SO_SECURITY_ENCRYPTION_TRANSPORT       0x5002
index 6260d5d..c7cb0af 100644 (file)
 #define __NR_syncfs            335
 #define __NR_sendmmsg          336
 #define __NR_setns             337
+#define __NR_process_vm_readv  338
+#define __NR_process_vm_writev 339
 
-#define NR_syscalls            338
+#define NR_syscalls            340
 
 #ifdef __32bit_syscall_numbers__
 /* Sparc 32-bit only has the "setresuid32", "getresuid32" variants,
index e27f8ea..0c218e4 100644 (file)
@@ -42,6 +42,9 @@ extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
 extern void fpload(unsigned long *fpregs, unsigned long *fsr);
 
 #else /* CONFIG_SPARC32 */
+
+#include <asm/trap_block.h>
+
 struct popc_3insn_patch_entry {
        unsigned int    addr;
        unsigned int    insns[3];
@@ -57,6 +60,10 @@ extern struct popc_6insn_patch_entry __popc_6insn_patch,
        __popc_6insn_patch_end;
 
 extern void __init per_cpu_patch(void);
+extern void sun4v_patch_1insn_range(struct sun4v_1insn_patch_entry *,
+                                   struct sun4v_1insn_patch_entry *);
+extern void sun4v_patch_2insn_range(struct sun4v_2insn_patch_entry *,
+                                   struct sun4v_2insn_patch_entry *);
 extern void __init sun4v_patch(void);
 extern void __init boot_cpu_id_too_large(int cpu);
 extern unsigned int dcache_parity_tl1_occurred;
index da0c6c7..e551987 100644 (file)
@@ -17,6 +17,8 @@
 #include <asm/processor.h>
 #include <asm/spitfire.h>
 
+#include "entry.h"
+
 #ifdef CONFIG_SPARC64
 
 #include <linux/jump_label.h>
@@ -203,6 +205,29 @@ int apply_relocate_add(Elf_Shdr *sechdrs,
 }
 
 #ifdef CONFIG_SPARC64
+static void do_patch_sections(const Elf_Ehdr *hdr,
+                             const Elf_Shdr *sechdrs)
+{
+       const Elf_Shdr *s, *sun4v_1insn = NULL, *sun4v_2insn = NULL;
+       char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+
+       for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
+               if (!strcmp(".sun4v_1insn_patch", secstrings + s->sh_name))
+                       sun4v_1insn = s;
+               if (!strcmp(".sun4v_2insn_patch", secstrings + s->sh_name))
+                       sun4v_2insn = s;
+       }
+
+       if (sun4v_1insn && tlb_type == hypervisor) {
+               void *p = (void *) sun4v_1insn->sh_addr;
+               sun4v_patch_1insn_range(p, p + sun4v_1insn->sh_size);
+       }
+       if (sun4v_2insn && tlb_type == hypervisor) {
+               void *p = (void *) sun4v_2insn->sh_addr;
+               sun4v_patch_2insn_range(p, p + sun4v_2insn->sh_size);
+       }
+}
+
 int module_finalize(const Elf_Ehdr *hdr,
                    const Elf_Shdr *sechdrs,
                    struct module *me)
@@ -210,6 +235,8 @@ int module_finalize(const Elf_Ehdr *hdr,
        /* make jump label nops */
        jump_label_apply_nops(me);
 
+       do_patch_sections(hdr, sechdrs);
+
        /* Cheetah's I-cache is fully coherent.  */
        if (tlb_type == spitfire) {
                unsigned long va;
index c965595..a854a1c 100644 (file)
@@ -234,40 +234,50 @@ void __init per_cpu_patch(void)
        }
 }
 
-void __init sun4v_patch(void)
+void sun4v_patch_1insn_range(struct sun4v_1insn_patch_entry *start,
+                            struct sun4v_1insn_patch_entry *end)
 {
-       extern void sun4v_hvapi_init(void);
-       struct sun4v_1insn_patch_entry *p1;
-       struct sun4v_2insn_patch_entry *p2;
-
-       if (tlb_type != hypervisor)
-               return;
+       while (start < end) {
+               unsigned long addr = start->addr;
 
-       p1 = &__sun4v_1insn_patch;
-       while (p1 < &__sun4v_1insn_patch_end) {
-               unsigned long addr = p1->addr;
-
-               *(unsigned int *) (addr +  0) = p1->insn;
+               *(unsigned int *) (addr +  0) = start->insn;
                wmb();
                __asm__ __volatile__("flush     %0" : : "r" (addr +  0));
 
-               p1++;
+               start++;
        }
+}
 
-       p2 = &__sun4v_2insn_patch;
-       while (p2 < &__sun4v_2insn_patch_end) {
-               unsigned long addr = p2->addr;
+void sun4v_patch_2insn_range(struct sun4v_2insn_patch_entry *start,
+                            struct sun4v_2insn_patch_entry *end)
+{
+       while (start < end) {
+               unsigned long addr = start->addr;
 
-               *(unsigned int *) (addr +  0) = p2->insns[0];
+               *(unsigned int *) (addr +  0) = start->insns[0];
                wmb();
                __asm__ __volatile__("flush     %0" : : "r" (addr +  0));
 
-               *(unsigned int *) (addr +  4) = p2->insns[1];
+               *(unsigned int *) (addr +  4) = start->insns[1];
                wmb();
                __asm__ __volatile__("flush     %0" : : "r" (addr +  4));
 
-               p2++;
+               start++;
        }
+}
+
+void __init sun4v_patch(void)
+{
+       extern void sun4v_hvapi_init(void);
+
+       if (tlb_type != hypervisor)
+               return;
+
+       sun4v_patch_1insn_range(&__sun4v_1insn_patch,
+                               &__sun4v_1insn_patch_end);
+
+       sun4v_patch_2insn_range(&__sun4v_2insn_patch,
+                               &__sun4v_2insn_patch_end);
 
        sun4v_hvapi_init();
 }
index 2caa556..023b886 100644 (file)
@@ -822,21 +822,23 @@ static inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
  * mistake.
  */
-void do_signal32(sigset_t *oldset, struct pt_regs * regs,
-                int restart_syscall, unsigned long orig_i0)
+void do_signal32(sigset_t *oldset, struct pt_regs * regs)
 {
        struct k_sigaction ka;
+       unsigned long orig_i0;
+       int restart_syscall;
        siginfo_t info;
        int signr;
        
        signr = get_signal_to_deliver(&info, &ka, regs, NULL);
 
-       /* If the debugger messes with the program counter, it clears
-        * the "in syscall" bit, directing us to not perform a syscall
-        * restart.
-        */
-       if (restart_syscall && !pt_regs_is_syscall(regs))
-               restart_syscall = 0;
+       restart_syscall = 0;
+       orig_i0 = 0;
+       if (pt_regs_is_syscall(regs) &&
+           (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) {
+               restart_syscall = 1;
+               orig_i0 = regs->u_regs[UREG_G6];
+       }
 
        if (signr > 0) {
                if (restart_syscall)
index 8ce247a..d54c6e5 100644 (file)
@@ -519,10 +519,26 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
        siginfo_t info;
        int signr;
 
+       /* It's a lot of work and synchronization to add a new ptrace
+        * register for GDB to save and restore in order to get
+        * orig_i0 correct for syscall restarts when debugging.
+        *
+        * Although it should be the case that most of the global
+        * registers are volatile across a system call, glibc already
+        * depends upon that fact that we preserve them.  So we can't
+        * just use any global register to save away the orig_i0 value.
+        *
+        * In particular %g2, %g3, %g4, and %g5 are all assumed to be
+        * preserved across a system call trap by various pieces of
+        * code in glibc.
+        *
+        * %g7 is used as the "thread register".   %g6 is not used in
+        * any fixed manner.  %g6 is used as a scratch register and
+        * a compiler temporary, but it's value is never used across
+        * a system call.  Therefore %g6 is usable for orig_i0 storage.
+        */
        if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C))
-               restart_syscall = 1;
-       else
-               restart_syscall = 0;
+               regs->u_regs[UREG_G6] = orig_i0;
 
        if (test_thread_flag(TIF_RESTORE_SIGMASK))
                oldset = &current->saved_sigmask;
@@ -535,8 +551,12 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
         * the software "in syscall" bit, directing us to not perform
         * a syscall restart.
         */
-       if (restart_syscall && !pt_regs_is_syscall(regs))
-               restart_syscall = 0;
+       restart_syscall = 0;
+       if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C)) {
+               restart_syscall = 1;
+               orig_i0 = regs->u_regs[UREG_G6];
+       }
+
 
        if (signr > 0) {
                if (restart_syscall)
index a2b8159..f0836cd 100644 (file)
@@ -529,11 +529,27 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
        siginfo_t info;
        int signr;
        
+       /* It's a lot of work and synchronization to add a new ptrace
+        * register for GDB to save and restore in order to get
+        * orig_i0 correct for syscall restarts when debugging.
+        *
+        * Although it should be the case that most of the global
+        * registers are volatile across a system call, glibc already
+        * depends upon that fact that we preserve them.  So we can't
+        * just use any global register to save away the orig_i0 value.
+        *
+        * In particular %g2, %g3, %g4, and %g5 are all assumed to be
+        * preserved across a system call trap by various pieces of
+        * code in glibc.
+        *
+        * %g7 is used as the "thread register".   %g6 is not used in
+        * any fixed manner.  %g6 is used as a scratch register and
+        * a compiler temporary, but it's value is never used across
+        * a system call.  Therefore %g6 is usable for orig_i0 storage.
+        */
        if (pt_regs_is_syscall(regs) &&
-           (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) {
-               restart_syscall = 1;
-       } else
-               restart_syscall = 0;
+           (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY)))
+               regs->u_regs[UREG_G6] = orig_i0;
 
        if (current_thread_info()->status & TS_RESTORE_SIGMASK)
                oldset = &current->saved_sigmask;
@@ -542,22 +558,20 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
 
 #ifdef CONFIG_COMPAT
        if (test_thread_flag(TIF_32BIT)) {
-               extern void do_signal32(sigset_t *, struct pt_regs *,
-                                       int restart_syscall,
-                                       unsigned long orig_i0);
-               do_signal32(oldset, regs, restart_syscall, orig_i0);
+               extern void do_signal32(sigset_t *, struct pt_regs *);
+               do_signal32(oldset, regs);
                return;
        }
 #endif 
 
        signr = get_signal_to_deliver(&info, &ka, regs, NULL);
 
-       /* If the debugger messes with the program counter, it clears
-        * the software "in syscall" bit, directing us to not perform
-        * a syscall restart.
-        */
-       if (restart_syscall && !pt_regs_is_syscall(regs))
-               restart_syscall = 0;
+       restart_syscall = 0;
+       if (pt_regs_is_syscall(regs) &&
+           (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) {
+               restart_syscall = 1;
+               orig_i0 = regs->u_regs[UREG_G6];
+       }
 
        if (signr > 0) {
                if (restart_syscall)
index e7dc508..b19570d 100644 (file)
@@ -2,6 +2,7 @@
 #include <linux/types.h>
 #include <linux/thread_info.h>
 #include <linux/uaccess.h>
+#include <linux/errno.h>
 
 #include <asm/sigcontext.h>
 #include <asm/fpumacro.h>
index 09d8ec4..63402f9 100644 (file)
@@ -84,4 +84,4 @@ sys_call_table:
 /*320*/        .long sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv
 /*325*/        .long sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg, sys_fanotify_init
 /*330*/        .long sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, sys_open_by_handle_at, sys_clock_adjtime
-/*335*/        .long sys_syncfs, sys_sendmmsg, sys_setns
+/*335*/        .long sys_syncfs, sys_sendmmsg, sys_setns, sys_process_vm_readv, sys_process_vm_writev
index edbec45..db86b1a 100644 (file)
@@ -85,7 +85,7 @@ sys_call_table32:
 /*320*/        .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, compat_sys_preadv
        .word compat_sys_pwritev, compat_sys_rt_tgsigqueueinfo, sys_perf_event_open, compat_sys_recvmmsg, sys_fanotify_init
 /*330*/        .word sys32_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, compat_sys_open_by_handle_at, compat_sys_clock_adjtime
-       .word sys_syncfs, compat_sys_sendmmsg, sys_setns
+       .word sys_syncfs, compat_sys_sendmmsg, sys_setns, compat_sys_process_vm_readv, compat_sys_process_vm_writev
 
 #endif /* CONFIG_COMPAT */
 
@@ -162,4 +162,4 @@ sys_call_table:
 /*320*/        .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv
        .word sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg, sys_fanotify_init
 /*330*/        .word sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, sys_open_by_handle_at, sys_clock_adjtime
-       .word sys_syncfs, sys_sendmmsg, sys_setns
+       .word sys_syncfs, sys_sendmmsg, sys_setns, sys_process_vm_readv, sys_process_vm_writev
index e3cda21..301421c 100644 (file)
@@ -8,7 +8,6 @@ obj-$(CONFIG_SPARC64)   += ultra.o tlb.o tsb.o gup.o
 obj-y                   += fault_$(BITS).o
 obj-y                   += init_$(BITS).o
 obj-$(CONFIG_SPARC32)   += loadmmu.o
-obj-y                   += generic_$(BITS).o
 obj-$(CONFIG_SPARC32)   += extable.o btfixup.o srmmu.o iommu.o io-unit.o
 obj-$(CONFIG_SPARC32)   += hypersparc.o viking.o tsunami.o swift.o
 obj-$(CONFIG_SPARC_LEON)+= leon_mm.o
diff --git a/arch/sparc/mm/generic_32.c b/arch/sparc/mm/generic_32.c
deleted file mode 100644 (file)
index 6ca39a6..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * generic.c: Generic Sparc mm routines that are not dependent upon
- *            MMU type but are Sparc specific.
- *
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/swap.h>
-#include <linux/pagemap.h>
-#include <linux/export.h>
-
-#include <asm/pgalloc.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/cacheflush.h>
-#include <asm/tlbflush.h>
-
-/* Remap IO memory, the same way as remap_pfn_range(), but use
- * the obio memory space.
- *
- * They use a pgprot that sets PAGE_IO and does not check the
- * mem_map table as this is independent of normal memory.
- */
-static inline void io_remap_pte_range(struct mm_struct *mm, pte_t * pte, unsigned long address, unsigned long size,
-       unsigned long offset, pgprot_t prot, int space)
-{
-       unsigned long end;
-
-       address &= ~PMD_MASK;
-       end = address + size;
-       if (end > PMD_SIZE)
-               end = PMD_SIZE;
-       do {
-               set_pte_at(mm, address, pte, mk_pte_io(offset, prot, space));
-               address += PAGE_SIZE;
-               offset += PAGE_SIZE;
-               pte++;
-       } while (address < end);
-}
-
-static inline int io_remap_pmd_range(struct mm_struct *mm, pmd_t * pmd, unsigned long address, unsigned long size,
-       unsigned long offset, pgprot_t prot, int space)
-{
-       unsigned long end;
-
-       address &= ~PGDIR_MASK;
-       end = address + size;
-       if (end > PGDIR_SIZE)
-               end = PGDIR_SIZE;
-       offset -= address;
-       do {
-               pte_t *pte = pte_alloc_map(mm, NULL, pmd, address);
-               if (!pte)
-                       return -ENOMEM;
-               io_remap_pte_range(mm, pte, address, end - address, address + offset, prot, space);
-               address = (address + PMD_SIZE) & PMD_MASK;
-               pmd++;
-       } while (address < end);
-       return 0;
-}
-
-int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
-                      unsigned long pfn, unsigned long size, pgprot_t prot)
-{
-       int error = 0;
-       pgd_t * dir;
-       unsigned long beg = from;
-       unsigned long end = from + size;
-       struct mm_struct *mm = vma->vm_mm;
-       int space = GET_IOSPACE(pfn);
-       unsigned long offset = GET_PFN(pfn) << PAGE_SHIFT;
-
-       /* See comment in mm/memory.c remap_pfn_range */
-       vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP;
-       vma->vm_pgoff = (offset >> PAGE_SHIFT) |
-               ((unsigned long)space << 28UL);
-
-       offset -= from;
-       dir = pgd_offset(mm, from);
-       flush_cache_range(vma, beg, end);
-
-       while (from < end) {
-               pmd_t *pmd = pmd_alloc(mm, dir, from);
-               error = -ENOMEM;
-               if (!pmd)
-                       break;
-               error = io_remap_pmd_range(mm, pmd, from, end - from, offset + from, prot, space);
-               if (error)
-                       break;
-               from = (from + PGDIR_SIZE) & PGDIR_MASK;
-               dir++;
-       }
-
-       flush_tlb_range(vma, beg, end);
-       return error;
-}
-EXPORT_SYMBOL(io_remap_pfn_range);
diff --git a/arch/sparc/mm/generic_64.c b/arch/sparc/mm/generic_64.c
deleted file mode 100644 (file)
index 9b357dd..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * generic.c: Generic Sparc mm routines that are not dependent upon
- *            MMU type but are Sparc specific.
- *
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/swap.h>
-#include <linux/export.h>
-#include <linux/pagemap.h>
-
-#include <asm/pgalloc.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/tlbflush.h>
-
-/* Remap IO memory, the same way as remap_pfn_range(), but use
- * the obio memory space.
- *
- * They use a pgprot that sets PAGE_IO and does not check the
- * mem_map table as this is independent of normal memory.
- */
-static inline void io_remap_pte_range(struct mm_struct *mm, pte_t * pte,
-                                     unsigned long address,
-                                     unsigned long size,
-                                     unsigned long offset, pgprot_t prot,
-                                     int space)
-{
-       unsigned long end;
-
-       /* clear hack bit that was used as a write_combine side-effect flag */
-       offset &= ~0x1UL;
-       address &= ~PMD_MASK;
-       end = address + size;
-       if (end > PMD_SIZE)
-               end = PMD_SIZE;
-       do {
-               pte_t entry;
-               unsigned long curend = address + PAGE_SIZE;
-               
-               entry = mk_pte_io(offset, prot, space, PAGE_SIZE);
-               if (!(address & 0xffff)) {
-                       if (PAGE_SIZE < (4 * 1024 * 1024) &&
-                           !(address & 0x3fffff) &&
-                           !(offset & 0x3ffffe) &&
-                           end >= address + 0x400000) {
-                               entry = mk_pte_io(offset, prot, space,
-                                                 4 * 1024 * 1024);
-                               curend = address + 0x400000;
-                               offset += 0x400000;
-                       } else if (PAGE_SIZE < (512 * 1024) &&
-                                  !(address & 0x7ffff) &&
-                                  !(offset & 0x7fffe) &&
-                                  end >= address + 0x80000) {
-                               entry = mk_pte_io(offset, prot, space,
-                                                 512 * 1024 * 1024);
-                               curend = address + 0x80000;
-                               offset += 0x80000;
-                       } else if (PAGE_SIZE < (64 * 1024) &&
-                                  !(offset & 0xfffe) &&
-                                  end >= address + 0x10000) {
-                               entry = mk_pte_io(offset, prot, space,
-                                                 64 * 1024);
-                               curend = address + 0x10000;
-                               offset += 0x10000;
-                       } else
-                               offset += PAGE_SIZE;
-               } else
-                       offset += PAGE_SIZE;
-
-               if (pte_write(entry))
-                       entry = pte_mkdirty(entry);
-               do {
-                       BUG_ON(!pte_none(*pte));
-                       set_pte_at(mm, address, pte, entry);
-                       address += PAGE_SIZE;
-                       pte_val(entry) += PAGE_SIZE;
-                       pte++;
-               } while (address < curend);
-       } while (address < end);
-}
-
-static inline int io_remap_pmd_range(struct mm_struct *mm, pmd_t * pmd, unsigned long address, unsigned long size,
-       unsigned long offset, pgprot_t prot, int space)
-{
-       unsigned long end;
-
-       address &= ~PGDIR_MASK;
-       end = address + size;
-       if (end > PGDIR_SIZE)
-               end = PGDIR_SIZE;
-       offset -= address;
-       do {
-               pte_t *pte = pte_alloc_map(mm, NULL, pmd, address);
-               if (!pte)
-                       return -ENOMEM;
-               io_remap_pte_range(mm, pte, address, end - address, address + offset, prot, space);
-               pte_unmap(pte);
-               address = (address + PMD_SIZE) & PMD_MASK;
-               pmd++;
-       } while (address < end);
-       return 0;
-}
-
-static inline int io_remap_pud_range(struct mm_struct *mm, pud_t * pud, unsigned long address, unsigned long size,
-       unsigned long offset, pgprot_t prot, int space)
-{
-       unsigned long end;
-
-       address &= ~PUD_MASK;
-       end = address + size;
-       if (end > PUD_SIZE)
-               end = PUD_SIZE;
-       offset -= address;
-       do {
-               pmd_t *pmd = pmd_alloc(mm, pud, address);
-               if (!pud)
-                       return -ENOMEM;
-               io_remap_pmd_range(mm, pmd, address, end - address, address + offset, prot, space);
-               address = (address + PUD_SIZE) & PUD_MASK;
-               pud++;
-       } while (address < end);
-       return 0;
-}
-
-int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
-               unsigned long pfn, unsigned long size, pgprot_t prot)
-{
-       int error = 0;
-       pgd_t * dir;
-       unsigned long beg = from;
-       unsigned long end = from + size;
-       struct mm_struct *mm = vma->vm_mm;
-       int space = GET_IOSPACE(pfn);
-       unsigned long offset = GET_PFN(pfn) << PAGE_SHIFT;
-       unsigned long phys_base;
-
-       phys_base = offset | (((unsigned long) space) << 32UL);
-
-       /* See comment in mm/memory.c remap_pfn_range */
-       vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP;
-       vma->vm_pgoff = phys_base >> PAGE_SHIFT;
-
-       offset -= from;
-       dir = pgd_offset(mm, from);
-       flush_cache_range(vma, beg, end);
-
-       while (from < end) {
-               pud_t *pud = pud_alloc(mm, dir, from);
-               error = -ENOMEM;
-               if (!pud)
-                       break;
-               error = io_remap_pud_range(mm, pud, from, end - from, offset + from, prot, space);
-               if (error)
-                       break;
-               from = (from + PGDIR_SIZE) & PGDIR_MASK;
-               dir++;
-       }
-
-       flush_tlb_range(vma, beg, end);
-       return error;
-}
-EXPORT_SYMBOL(io_remap_pfn_range);
index e57dcce..942ed61 100644 (file)
@@ -237,13 +237,13 @@ menu "PKUnity NetBook-0916 Features"
 
 config I2C_BATTERY_BQ27200
        tristate "I2C Battery BQ27200 Support"
-       select PUV3_I2C
+       select I2C_PUV3
        select POWER_SUPPLY
        select BATTERY_BQ27x00
 
 config I2C_EEPROM_AT24
        tristate "I2C EEPROMs AT24 support"
-       select PUV3_I2C
+       select I2C_PUV3
        select MISC_DEVICES
        select EEPROM_AT24
 
index ae2ec33..1a36262 100644 (file)
@@ -44,18 +44,4 @@ config DEBUG_OCD
          Say Y here if you want the debug print routines to direct their
          output to the UniCore On-Chip-Debugger channel using CP #1.
 
-config DEBUG_OCD_BREAKPOINT
-       bool "Breakpoint support via On-Chip-Debugger"
-       depends on DEBUG_OCD
-
-config DEBUG_UART
-       int "Kernel low-level debugging messages via serial port"
-       depends on DEBUG_LL
-       range 0 1
-       default "0"
-       help
-         Choice for UART for kernel low-level using PKUnity UARTS,
-         should be between zero and one. The port must have been
-         initialised by the boot-loader before use.
-
 endmenu
index b0954a2..950a9af 100644 (file)
@@ -10,8 +10,8 @@
 # Copyright (C) 2001~2010 GUAN Xue-tao
 #
 
-EXTRA_CFLAGS   := -fpic -fno-builtin
-EXTRA_AFLAGS   := -Wa,-march=all
+ccflags-y      := -fpic -fno-builtin
+asflags-y      := -Wa,-march=all
 
 OBJS           := misc.o
 
index 1628a63..401f597 100644 (file)
 #ifndef __UNICORE_BITOPS_H__
 #define __UNICORE_BITOPS_H__
 
-#define find_next_bit          __uc32_find_next_bit
-#define find_next_zero_bit     __uc32_find_next_zero_bit
-
-#define find_first_bit         __uc32_find_first_bit
-#define find_first_zero_bit    __uc32_find_first_zero_bit
-
 #define _ASM_GENERIC_BITOPS_FLS_H_
 #define _ASM_GENERIC_BITOPS___FLS_H_
 #define _ASM_GENERIC_BITOPS_FFS_H_
@@ -44,4 +38,10 @@ static inline int fls(int x)
 
 #include <asm-generic/bitops.h>
 
+/* following definitions: to avoid using codes in lib/find_*.c */
+#define find_next_bit          find_next_bit
+#define find_next_zero_bit     find_next_zero_bit
+#define find_first_bit         find_first_bit
+#define find_first_zero_bit    find_first_zero_bit
+
 #endif /* __UNICORE_BITOPS_H__ */
index e11cb07..f0d780a 100644 (file)
@@ -53,7 +53,6 @@ struct thread_struct {
 #define start_thread(regs, pc, sp)                                     \
 ({                                                                     \
        unsigned long *stack = (unsigned long *)sp;                     \
-       set_fs(USER_DS);                                                \
        memset(regs->uregs, 0, sizeof(regs->uregs));                    \
        regs->UCreg_asr = USER_MODE;                                    \
        regs->UCreg_pc = pc & ~1;       /* pc */                        \
index a897080..d98bd81 100644 (file)
@@ -24,8 +24,8 @@
 
 #include "ksyms.h"
 
-EXPORT_SYMBOL(__uc32_find_next_zero_bit);
-EXPORT_SYMBOL(__uc32_find_next_bit);
+EXPORT_SYMBOL(find_next_zero_bit);
+EXPORT_SYMBOL(find_next_bit);
 
 EXPORT_SYMBOL(__backtrace);
 
index c360ce9..c777462 100644 (file)
@@ -17,7 +17,7 @@
  * Purpose  : Find a 'zero' bit
  * Prototype: int find_first_zero_bit(void *addr, unsigned int maxbit);
  */
-__uc32_find_first_zero_bit:
+ENTRY(find_first_zero_bit)
                cxor.a  r1, #0
                beq     3f
                mov     r2, #0
@@ -29,13 +29,14 @@ __uc32_find_first_zero_bit:
                bub     1b
 3:             mov     r0, r1                  @ no free bits
                mov     pc, lr
+ENDPROC(find_first_zero_bit)
 
 /*
  * Purpose  : Find next 'zero' bit
  * Prototype: int find_next_zero_bit
  *             (void *addr, unsigned int maxbit, int offset)
  */
-ENTRY(__uc32_find_next_zero_bit)
+ENTRY(find_next_zero_bit)
                cxor.a  r1, #0
                beq     3b
                and.a   ip, r2, #7
@@ -47,14 +48,14 @@ ENTRY(__uc32_find_next_zero_bit)
                or      r2, r2, #7              @ if zero, then no bits here
                add     r2, r2, #1              @ align bit pointer
                b       2b                      @ loop for next bit
-ENDPROC(__uc32_find_next_zero_bit)
+ENDPROC(find_next_zero_bit)
 
 /*
  * Purpose  : Find a 'one' bit
  * Prototype: int find_first_bit
  *             (const unsigned long *addr, unsigned int maxbit);
  */
-__uc32_find_first_bit:
+ENTRY(find_first_bit)
                cxor.a  r1, #0
                beq     3f
                mov     r2, #0
@@ -66,13 +67,14 @@ __uc32_find_first_bit:
                bub     1b
 3:             mov     r0, r1                  @ no free bits
                mov     pc, lr
+ENDPROC(find_first_bit)
 
 /*
  * Purpose  : Find next 'one' bit
  * Prototype: int find_next_zero_bit
  *             (void *addr, unsigned int maxbit, int offset)
  */
-ENTRY(__uc32_find_next_bit)
+ENTRY(find_next_bit)
                cxor.a  r1, #0
                beq     3b
                and.a   ip, r2, #7
@@ -83,7 +85,7 @@ ENTRY(__uc32_find_next_bit)
                or      r2, r2, #7              @ if zero, then no bits here
                add     r2, r2, #1              @ align bit pointer
                b       2b                      @ loop for next bit
-ENDPROC(__uc32_find_next_bit)
+ENDPROC(find_next_bit)
 
 /*
  * One or more bits in the LSB of r3 are assumed to be set.
index 9b7273c..1a6c09a 100644 (file)
@@ -49,6 +49,7 @@ extern unsigned int apic_verbosity;
 extern int local_apic_timer_c2_ok;
 
 extern int disable_apic;
+extern unsigned int lapic_timer_frequency;
 
 #ifdef CONFIG_SMP
 extern void __inquire_remote_apic(int apicid);
index 72a8b52..a01e7ec 100644 (file)
@@ -17,7 +17,7 @@
 #define NMI_REASON_CLEAR_IOCHK 0x08
 #define NMI_REASON_CLEAR_MASK  0x0f
 
-static inline unsigned char get_nmi_reason(void)
+static inline unsigned char default_get_nmi_reason(void)
 {
        return inb(NMI_REASON_PORT);
 }
index c9321f3..0e8ae57 100644 (file)
@@ -201,7 +201,10 @@ int mce_notify_irq(void);
 void mce_notify_process(void);
 
 DECLARE_PER_CPU(struct mce, injectm);
-extern struct file_operations mce_chrdev_ops;
+
+extern void register_mce_write_callback(ssize_t (*)(struct file *filp,
+                                   const char __user *ubuf,
+                                   size_t usize, loff_t *off));
 
 /*
  * Exception handler
index 719f00b..e628312 100644 (file)
@@ -44,6 +44,13 @@ enum mrst_timer_options {
 
 extern enum mrst_timer_options mrst_timer_options;
 
+/*
+ * Penwell uses spread spectrum clock, so the freq number is not exactly
+ * the same as reported by MSR based on SDM.
+ */
+#define PENWELL_FSB_FREQ_83SKU         83200
+#define PENWELL_FSB_FREQ_100SKU        99840
+
 #define SFI_MTMR_MAX_NUM 8
 #define SFI_MRTC_MAX   8
 
index d3d8590..1971e65 100644 (file)
@@ -152,6 +152,7 @@ struct x86_cpuinit_ops {
 /**
  * struct x86_platform_ops - platform specific runtime functions
  * @calibrate_tsc:             calibrate TSC
+ * @wallclock_init:            init the wallclock device
  * @get_wallclock:             get time from HW clock like RTC etc.
  * @set_wallclock:             set time back to HW clock
  * @is_untracked_pat_range     exclude from PAT logic
@@ -160,11 +161,13 @@ struct x86_cpuinit_ops {
  */
 struct x86_platform_ops {
        unsigned long (*calibrate_tsc)(void);
+       void (*wallclock_init)(void);
        unsigned long (*get_wallclock)(void);
        int (*set_wallclock)(unsigned long nowtime);
        void (*iommu_shutdown)(void);
        bool (*is_untracked_pat_range)(u64 start, u64 end);
        void (*nmi_init)(void);
+       unsigned char (*get_nmi_reason)(void);
        int (*i8042_detect)(void);
 };
 
index c638228..1f84794 100644 (file)
@@ -738,5 +738,5 @@ void __kprobes text_poke_smp_batch(struct text_poke_param *params, int n)
 
        atomic_set(&stop_machine_first, 1);
        wrote_text = 0;
-       __stop_machine(stop_machine_text_poke, (void *)&tpp, NULL);
+       __stop_machine(stop_machine_text_poke, (void *)&tpp, cpu_online_mask);
 }
index a2fd72e..f98d84c 100644 (file)
@@ -186,7 +186,7 @@ static struct resource lapic_resource = {
        .flags = IORESOURCE_MEM | IORESOURCE_BUSY,
 };
 
-static unsigned int calibration_result;
+unsigned int lapic_timer_frequency = 0;
 
 static void apic_pm_activate(void);
 
@@ -454,7 +454,7 @@ static void lapic_timer_setup(enum clock_event_mode mode,
        switch (mode) {
        case CLOCK_EVT_MODE_PERIODIC:
        case CLOCK_EVT_MODE_ONESHOT:
-               __setup_APIC_LVTT(calibration_result,
+               __setup_APIC_LVTT(lapic_timer_frequency,
                                  mode != CLOCK_EVT_MODE_PERIODIC, 1);
                break;
        case CLOCK_EVT_MODE_UNUSED:
@@ -638,6 +638,25 @@ static int __init calibrate_APIC_clock(void)
        long delta, deltatsc;
        int pm_referenced = 0;
 
+       /**
+        * check if lapic timer has already been calibrated by platform
+        * specific routine, such as tsc calibration code. if so, we just fill
+        * in the clockevent structure and return.
+        */
+
+       if (lapic_timer_frequency) {
+               apic_printk(APIC_VERBOSE, "lapic timer already calibrated %d\n",
+                               lapic_timer_frequency);
+               lapic_clockevent.mult = div_sc(lapic_timer_frequency/APIC_DIVISOR,
+                                       TICK_NSEC, lapic_clockevent.shift);
+               lapic_clockevent.max_delta_ns =
+                       clockevent_delta2ns(0x7FFFFF, &lapic_clockevent);
+               lapic_clockevent.min_delta_ns =
+                       clockevent_delta2ns(0xF, &lapic_clockevent);
+               lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY;
+               return 0;
+       }
+
        local_irq_disable();
 
        /* Replace the global interrupt handler */
@@ -679,12 +698,12 @@ static int __init calibrate_APIC_clock(void)
        lapic_clockevent.min_delta_ns =
                clockevent_delta2ns(0xF, &lapic_clockevent);
 
-       calibration_result = (delta * APIC_DIVISOR) / LAPIC_CAL_LOOPS;
+       lapic_timer_frequency = (delta * APIC_DIVISOR) / LAPIC_CAL_LOOPS;
 
        apic_printk(APIC_VERBOSE, "..... delta %ld\n", delta);
        apic_printk(APIC_VERBOSE, "..... mult: %u\n", lapic_clockevent.mult);
        apic_printk(APIC_VERBOSE, "..... calibration result: %u\n",
-                   calibration_result);
+                   lapic_timer_frequency);
 
        if (cpu_has_tsc) {
                apic_printk(APIC_VERBOSE, "..... CPU clock speed is "
@@ -695,13 +714,13 @@ static int __init calibrate_APIC_clock(void)
 
        apic_printk(APIC_VERBOSE, "..... host bus clock speed is "
                    "%u.%04u MHz.\n",
-                   calibration_result / (1000000 / HZ),
-                   calibration_result % (1000000 / HZ));
+                   lapic_timer_frequency / (1000000 / HZ),
+                   lapic_timer_frequency % (1000000 / HZ));
 
        /*
         * Do a sanity check on the APIC calibration result
         */
-       if (calibration_result < (1000000 / HZ)) {
+       if (lapic_timer_frequency < (1000000 / HZ)) {
                local_irq_enable();
                pr_warning("APIC frequency too slow, disabling apic timer\n");
                return -1;
index 3c31fa9..6d939d7 100644 (file)
@@ -193,10 +193,8 @@ int __init arch_early_irq_init(void)
        struct irq_cfg *cfg;
        int count, node, i;
 
-       if (!legacy_pic->nr_legacy_irqs) {
-               nr_irqs_gsi = 0;
+       if (!legacy_pic->nr_legacy_irqs)
                io_apic_irqs = ~0UL;
-       }
 
        for (i = 0; i < nr_ioapics; i++) {
                ioapics[i].saved_registers =
@@ -1696,6 +1694,7 @@ __apicdebuginit(void) print_IO_APICs(void)
        int ioapic_idx;
        struct irq_cfg *cfg;
        unsigned int irq;
+       struct irq_chip *chip;
 
        printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries);
        for (ioapic_idx = 0; ioapic_idx < nr_ioapics; ioapic_idx++)
@@ -1716,6 +1715,10 @@ __apicdebuginit(void) print_IO_APICs(void)
        for_each_active_irq(irq) {
                struct irq_pin_list *entry;
 
+               chip = irq_get_chip(irq);
+               if (chip != &ioapic_chip)
+                       continue;
+
                cfg = irq_get_chip_data(irq);
                if (!cfg)
                        continue;
index 6199232..319882e 100644 (file)
@@ -208,7 +208,7 @@ static int inject_init(void)
        if (!alloc_cpumask_var(&mce_inject_cpumask, GFP_KERNEL))
                return -ENOMEM;
        printk(KERN_INFO "Machine check injector initialized\n");
-       mce_chrdev_ops.write = mce_write;
+       register_mce_write_callback(mce_write);
        register_nmi_handler(NMI_LOCAL, mce_raise_notify, 0,
                                "mce_notify");
        return 0;
index 362056a..2af127d 100644 (file)
@@ -1634,16 +1634,35 @@ static long mce_chrdev_ioctl(struct file *f, unsigned int cmd,
        }
 }
 
-/* Modified in mce-inject.c, so not static or const */
-struct file_operations mce_chrdev_ops = {
+static ssize_t (*mce_write)(struct file *filp, const char __user *ubuf,
+                           size_t usize, loff_t *off);
+
+void register_mce_write_callback(ssize_t (*fn)(struct file *filp,
+                            const char __user *ubuf,
+                            size_t usize, loff_t *off))
+{
+       mce_write = fn;
+}
+EXPORT_SYMBOL_GPL(register_mce_write_callback);
+
+ssize_t mce_chrdev_write(struct file *filp, const char __user *ubuf,
+                        size_t usize, loff_t *off)
+{
+       if (mce_write)
+               return mce_write(filp, ubuf, usize, off);
+       else
+               return -EINVAL;
+}
+
+static const struct file_operations mce_chrdev_ops = {
        .open                   = mce_chrdev_open,
        .release                = mce_chrdev_release,
        .read                   = mce_chrdev_read,
+       .write                  = mce_chrdev_write,
        .poll                   = mce_chrdev_poll,
        .unlocked_ioctl         = mce_chrdev_ioctl,
        .llseek                 = no_llseek,
 };
-EXPORT_SYMBOL_GPL(mce_chrdev_ops);
 
 static struct miscdevice mce_chrdev_device = {
        MISC_MCELOG_MINOR,
index c1a0188..44842d7 100644 (file)
@@ -74,9 +74,10 @@ static cycle_t kvm_clock_read(void)
        struct pvclock_vcpu_time_info *src;
        cycle_t ret;
 
-       src = &get_cpu_var(hv_clock);
+       preempt_disable_notrace();
+       src = &__get_cpu_var(hv_clock);
        ret = pvclock_clocksource_read(src);
-       put_cpu_var(hv_clock);
+       preempt_enable_notrace();
        return ret;
 }
 
index b9c8628..e88f37b 100644 (file)
@@ -29,6 +29,7 @@
 #include <asm/traps.h>
 #include <asm/mach_traps.h>
 #include <asm/nmi.h>
+#include <asm/x86_init.h>
 
 #define NMI_MAX_NAMELEN        16
 struct nmiaction {
@@ -348,7 +349,7 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs)
 
        /* Non-CPU-specific NMI: NMI sources can be processed on any CPU */
        raw_spin_lock(&nmi_reason_lock);
-       reason = get_nmi_reason();
+       reason = x86_platform.get_nmi_reason();
 
        if (reason & NMI_REASON_MASK) {
                if (reason & NMI_REASON_SERR)
index afaf384..cf0ef98 100644 (file)
@@ -1045,6 +1045,8 @@ void __init setup_arch(char **cmdline_p)
 
        x86_init.timers.wallclock_init();
 
+       x86_platform.wallclock_init();
+
        mcheck_init();
 
        arch_init_ideal_nops();
index 6f164bd..c1d6cd5 100644 (file)
 #include <asm/pat.h>
 #include <asm/tsc.h>
 #include <asm/iommu.h>
+#include <asm/mach_traps.h>
 
 void __cpuinit x86_init_noop(void) { }
 void __init x86_init_uint_noop(unsigned int unused) { }
 void __init x86_init_pgd_noop(pgd_t *unused) { }
 int __init iommu_init_noop(void) { return 0; }
 void iommu_shutdown_noop(void) { }
+void wallclock_init_noop(void) { }
 
 /*
  * The platform setup functions are preset with the default functions
@@ -97,11 +99,13 @@ static int default_i8042_detect(void) { return 1; };
 
 struct x86_platform_ops x86_platform = {
        .calibrate_tsc                  = native_calibrate_tsc,
+       .wallclock_init                 = wallclock_init_noop,
        .get_wallclock                  = mach_get_cmos_time,
        .set_wallclock                  = mach_set_rtc_mmss,
        .iommu_shutdown                 = iommu_shutdown_noop,
        .is_untracked_pat_range         = is_ISA_range,
        .nmi_init                       = default_nmi_init,
+       .get_nmi_reason                 = default_get_nmi_reason,
        .i8042_detect                   = default_i8042_detect
 };
 
index a0d6bd9..579a0b5 100644 (file)
@@ -39,6 +39,7 @@
 #include <asm/mce.h>
 #include <asm/i387.h>
 #include <asm/xcr.h>
+#include <asm/perf_event.h>
 
 #include "trace.h"
 
@@ -118,7 +119,7 @@ module_param(ple_gap, int, S_IRUGO);
 static int ple_window = KVM_VMX_DEFAULT_PLE_WINDOW;
 module_param(ple_window, int, S_IRUGO);
 
-#define NR_AUTOLOAD_MSRS 1
+#define NR_AUTOLOAD_MSRS 8
 #define VMCS02_POOL_SIZE 1
 
 struct vmcs {
@@ -622,6 +623,7 @@ static unsigned long *vmx_msr_bitmap_legacy;
 static unsigned long *vmx_msr_bitmap_longmode;
 
 static bool cpu_has_load_ia32_efer;
+static bool cpu_has_load_perf_global_ctrl;
 
 static DECLARE_BITMAP(vmx_vpid_bitmap, VMX_NR_VPIDS);
 static DEFINE_SPINLOCK(vmx_vpid_lock);
@@ -1191,15 +1193,34 @@ static void update_exception_bitmap(struct kvm_vcpu *vcpu)
        vmcs_write32(EXCEPTION_BITMAP, eb);
 }
 
+static void clear_atomic_switch_msr_special(unsigned long entry,
+               unsigned long exit)
+{
+       vmcs_clear_bits(VM_ENTRY_CONTROLS, entry);
+       vmcs_clear_bits(VM_EXIT_CONTROLS, exit);
+}
+
 static void clear_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr)
 {
        unsigned i;
        struct msr_autoload *m = &vmx->msr_autoload;
 
-       if (msr == MSR_EFER && cpu_has_load_ia32_efer) {
-               vmcs_clear_bits(VM_ENTRY_CONTROLS, VM_ENTRY_LOAD_IA32_EFER);
-               vmcs_clear_bits(VM_EXIT_CONTROLS, VM_EXIT_LOAD_IA32_EFER);
-               return;
+       switch (msr) {
+       case MSR_EFER:
+               if (cpu_has_load_ia32_efer) {
+                       clear_atomic_switch_msr_special(VM_ENTRY_LOAD_IA32_EFER,
+                                       VM_EXIT_LOAD_IA32_EFER);
+                       return;
+               }
+               break;
+       case MSR_CORE_PERF_GLOBAL_CTRL:
+               if (cpu_has_load_perf_global_ctrl) {
+                       clear_atomic_switch_msr_special(
+                                       VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL,
+                                       VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL);
+                       return;
+               }
+               break;
        }
 
        for (i = 0; i < m->nr; ++i)
@@ -1215,25 +1236,55 @@ static void clear_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr)
        vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, m->nr);
 }
 
+static void add_atomic_switch_msr_special(unsigned long entry,
+               unsigned long exit, unsigned long guest_val_vmcs,
+               unsigned long host_val_vmcs, u64 guest_val, u64 host_val)
+{
+       vmcs_write64(guest_val_vmcs, guest_val);
+       vmcs_write64(host_val_vmcs, host_val);
+       vmcs_set_bits(VM_ENTRY_CONTROLS, entry);
+       vmcs_set_bits(VM_EXIT_CONTROLS, exit);
+}
+
 static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
                                  u64 guest_val, u64 host_val)
 {
        unsigned i;
        struct msr_autoload *m = &vmx->msr_autoload;
 
-       if (msr == MSR_EFER && cpu_has_load_ia32_efer) {
-               vmcs_write64(GUEST_IA32_EFER, guest_val);
-               vmcs_write64(HOST_IA32_EFER, host_val);
-               vmcs_set_bits(VM_ENTRY_CONTROLS, VM_ENTRY_LOAD_IA32_EFER);
-               vmcs_set_bits(VM_EXIT_CONTROLS, VM_EXIT_LOAD_IA32_EFER);
-               return;
+       switch (msr) {
+       case MSR_EFER:
+               if (cpu_has_load_ia32_efer) {
+                       add_atomic_switch_msr_special(VM_ENTRY_LOAD_IA32_EFER,
+                                       VM_EXIT_LOAD_IA32_EFER,
+                                       GUEST_IA32_EFER,
+                                       HOST_IA32_EFER,
+                                       guest_val, host_val);
+                       return;
+               }
+               break;
+       case MSR_CORE_PERF_GLOBAL_CTRL:
+               if (cpu_has_load_perf_global_ctrl) {
+                       add_atomic_switch_msr_special(
+                                       VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL,
+                                       VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL,
+                                       GUEST_IA32_PERF_GLOBAL_CTRL,
+                                       HOST_IA32_PERF_GLOBAL_CTRL,
+                                       guest_val, host_val);
+                       return;
+               }
+               break;
        }
 
        for (i = 0; i < m->nr; ++i)
                if (m->guest[i].index == msr)
                        break;
 
-       if (i == m->nr) {
+       if (i == NR_AUTOLOAD_MSRS) {
+               printk_once(KERN_WARNING"Not enough mst switch entries. "
+                               "Can't add msr %x\n", msr);
+               return;
+       } else if (i == m->nr) {
                ++m->nr;
                vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, m->nr);
                vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, m->nr);
@@ -2455,6 +2506,42 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
                && allow_1_setting(MSR_IA32_VMX_EXIT_CTLS,
                                   VM_EXIT_LOAD_IA32_EFER);
 
+       cpu_has_load_perf_global_ctrl =
+               allow_1_setting(MSR_IA32_VMX_ENTRY_CTLS,
+                               VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL)
+               && allow_1_setting(MSR_IA32_VMX_EXIT_CTLS,
+                                  VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL);
+
+       /*
+        * Some cpus support VM_ENTRY_(LOAD|SAVE)_IA32_PERF_GLOBAL_CTRL
+        * but due to arrata below it can't be used. Workaround is to use
+        * msr load mechanism to switch IA32_PERF_GLOBAL_CTRL.
+        *
+        * VM Exit May Incorrectly Clear IA32_PERF_GLOBAL_CTRL [34:32]
+        *
+        * AAK155             (model 26)
+        * AAP115             (model 30)
+        * AAT100             (model 37)
+        * BC86,AAY89,BD102   (model 44)
+        * BA97               (model 46)
+        *
+        */
+       if (cpu_has_load_perf_global_ctrl && boot_cpu_data.x86 == 0x6) {
+               switch (boot_cpu_data.x86_model) {
+               case 26:
+               case 30:
+               case 37:
+               case 44:
+               case 46:
+                       cpu_has_load_perf_global_ctrl = false;
+                       printk_once(KERN_WARNING"kvm: VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL "
+                                       "does not work properly. Using workaround\n");
+                       break;
+               default:
+                       break;
+               }
+       }
+
        return 0;
 }
 
@@ -5968,6 +6055,24 @@ static void vmx_cancel_injection(struct kvm_vcpu *vcpu)
        vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0);
 }
 
+static void atomic_switch_perf_msrs(struct vcpu_vmx *vmx)
+{
+       int i, nr_msrs;
+       struct perf_guest_switch_msr *msrs;
+
+       msrs = perf_guest_get_msrs(&nr_msrs);
+
+       if (!msrs)
+               return;
+
+       for (i = 0; i < nr_msrs; i++)
+               if (msrs[i].host == msrs[i].guest)
+                       clear_atomic_switch_msr(vmx, msrs[i].msr);
+               else
+                       add_atomic_switch_msr(vmx, msrs[i].msr, msrs[i].guest,
+                                       msrs[i].host);
+}
+
 #ifdef CONFIG_X86_64
 #define R "r"
 #define Q "q"
@@ -6017,6 +6122,8 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
        if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
                vmx_set_interrupt_shadow(vcpu, 0);
 
+       atomic_switch_perf_msrs(vmx);
+
        vmx->__launched = vmx->loaded_vmcs->launched;
        asm(
                /* Store host registers */
index 28071bb..4c61b52 100644 (file)
@@ -109,7 +109,7 @@ static __init void sdv_serial_fixup(void)
 }
 
 #else
-static inline void sdv_serial_fixup(void);
+static inline void sdv_serial_fixup(void) {};
 #endif
 
 static void __init sdv_arch_setup(void)
index 6ed7afd..b1489a0 100644 (file)
@@ -187,11 +187,34 @@ int __init sfi_parse_mrtc(struct sfi_table_header *table)
 static unsigned long __init mrst_calibrate_tsc(void)
 {
        unsigned long flags, fast_calibrate;
-
-       local_irq_save(flags);
-       fast_calibrate = apbt_quick_calibrate();
-       local_irq_restore(flags);
-
+       if (__mrst_cpu_chip == MRST_CPU_CHIP_PENWELL) {
+               u32 lo, hi, ratio, fsb;
+
+               rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
+               pr_debug("IA32 perf status is 0x%x, 0x%0x\n", lo, hi);
+               ratio = (hi >> 8) & 0x1f;
+               pr_debug("ratio is %d\n", ratio);
+               if (!ratio) {
+                       pr_err("read a zero ratio, should be incorrect!\n");
+                       pr_err("force tsc ratio to 16 ...\n");
+                       ratio = 16;
+               }
+               rdmsr(MSR_FSB_FREQ, lo, hi);
+               if ((lo & 0x7) == 0x7)
+                       fsb = PENWELL_FSB_FREQ_83SKU;
+               else
+                       fsb = PENWELL_FSB_FREQ_100SKU;
+               fast_calibrate = ratio * fsb;
+               pr_debug("read penwell tsc %lu khz\n", fast_calibrate);
+               lapic_timer_frequency = fsb * 1000 / HZ;
+               /* mark tsc clocksource as reliable */
+               set_cpu_cap(&boot_cpu_data, X86_FEATURE_TSC_RELIABLE);
+       } else {
+               local_irq_save(flags);
+               fast_calibrate = apbt_quick_calibrate();
+               local_irq_restore(flags);
+       }
+       
        if (fast_calibrate)
                return fast_calibrate;
 
@@ -254,6 +277,17 @@ static void mrst_reboot(void)
 }
 
 /*
+ * Moorestown does not have external NMI source nor port 0x61 to report
+ * NMI status. The possible NMI sources are from pmu as a result of NMI
+ * watchdog or lock debug. Reading io port 0x61 results in 0xff which
+ * misled NMI handler.
+ */
+static unsigned char mrst_get_nmi_reason(void)
+{
+       return 0;
+}
+
+/*
  * Moorestown specific x86_init function overrides and early setup
  * calls.
  */
@@ -274,6 +308,8 @@ void __init x86_mrst_early_setup(void)
        x86_platform.calibrate_tsc = mrst_calibrate_tsc;
        x86_platform.i8042_detect = mrst_i8042_detect;
        x86_init.timers.wallclock_init = mrst_rtc_init;
+       x86_platform.get_nmi_reason = mrst_get_nmi_reason;
+
        x86_init.pci.init = pci_mrst_init;
        x86_init.pci.fixup_irqs = x86_init_noop;
 
@@ -608,6 +644,7 @@ static void *msic_ocd_platform_data(void *info)
 }
 
 static const struct devs_id __initconst device_ids[] = {
+       {"bma023", SFI_DEV_TYPE_I2C, 1, &no_platform_data},
        {"pmic_gpio", SFI_DEV_TYPE_SPI, 1, &pmic_gpio_platform_data},
        {"spi_max3111", SFI_DEV_TYPE_SPI, 0, &max3111_platform_data},
        {"i2c_max7315", SFI_DEV_TYPE_I2C, 1, &max7315_platform_data},
index a8ac6f1..225bd0f 100644 (file)
@@ -76,8 +76,8 @@ unsigned long vrtc_get_time(void)
 
        spin_unlock_irqrestore(&rtc_lock, flags);
 
-       /* vRTC YEAR reg contains the offset to 1960 */
-       year += 1960;
+       /* vRTC YEAR reg contains the offset to 1972 */
+       year += 1972;
 
        printk(KERN_INFO "vRTC: sec: %d min: %d hour: %d day: %d "
                "mon: %d year: %d\n", sec, min, hour, mday, mon, year);
index da8afd5..1f92865 100644 (file)
@@ -1356,7 +1356,7 @@ static int __cpuinit xen_hvm_cpu_notify(struct notifier_block *self,
        int cpu = (long)hcpu;
        switch (action) {
        case CPU_UP_PREPARE:
-               per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu];
+               xen_vcpu_setup(cpu);
                if (xen_have_vector_callback)
                        xen_init_lock_cpu(cpu);
                break;
@@ -1386,7 +1386,6 @@ static void __init xen_hvm_guest_init(void)
        xen_hvm_smp_init();
        register_cpu_notifier(&xen_hvm_cpu_notifier);
        xen_unplug_emulated_devices();
-       have_vcpu_info_placement = 0;
        x86_init.irqs.intr_init = xen_init_IRQ;
        xen_hvm_init_time_ops();
        xen_hvm_init_mmu_ops();
index 6bbfd7a..5a40d24 100644 (file)
@@ -71,7 +71,7 @@ int arch_gnttab_map_shared(unsigned long *frames, unsigned long nr_gframes,
 
        if (shared == NULL) {
                struct vm_struct *area =
-                       alloc_vm_area(PAGE_SIZE * max_nr_gframes);
+                       alloc_vm_area(PAGE_SIZE * max_nr_gframes, NULL);
                BUG_ON(area == NULL);
                shared = area->addr;
                *__shared = shared;
index cbdf2ff..bb06968 100644 (file)
@@ -73,4 +73,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #endif /* _XTENSA_SOCKET_H */
index f43c8a5..ea70e6c 100644 (file)
@@ -1379,15 +1379,19 @@ get_rq:
                 */
                if (list_empty(&plug->list))
                        trace_block_plug(q);
-               else if (!plug->should_sort) {
-                       struct request *__rq;
+               else {
+                       if (!plug->should_sort) {
+                               struct request *__rq;
 
-                       __rq = list_entry_rq(plug->list.prev);
-                       if (__rq->q != q)
-                               plug->should_sort = 1;
+                               __rq = list_entry_rq(plug->list.prev);
+                               if (__rq->q != q)
+                                       plug->should_sort = 1;
+                       }
+                       if (request_count >= BLK_MAX_REQUEST_COUNT) {
+                               blk_flush_plug_list(plug, false);
+                               trace_block_plug(q);
+                       }
                }
-               if (request_count >= BLK_MAX_REQUEST_COUNT)
-                       blk_flush_plug_list(plug, false);
                list_add_tail(&req->queuelist, &plug->list);
                drive_stat_acct(req, 1);
        } else {
index e663ac2..164cd00 100644 (file)
@@ -204,10 +204,11 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq,
                if (!iov[i].iov_len)
                        return -EINVAL;
 
-               if (uaddr & queue_dma_alignment(q)) {
+               /*
+                * Keep going so we check length of all segments
+                */
+               if (uaddr & queue_dma_alignment(q))
                        unaligned = 1;
-                       break;
-               }
        }
 
        if (unaligned || (q->dma_pad_mask & len) || map_data)
index 9253839..02e9fca 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/mutex.h>
 #include <linux/idr.h>
 #include <linux/log2.h>
-#include <linux/ctype.h>
 
 #include "blk.h"
 
@@ -916,74 +915,6 @@ static int __init genhd_device_init(void)
 
 subsys_initcall(genhd_device_init);
 
-static ssize_t alias_show(struct device *dev,
-                              struct device_attribute *attr, char *buf)
-{
-       struct gendisk *disk = dev_to_disk(dev);
-       ssize_t ret = 0;
-
-       if (disk->alias)
-               ret = snprintf(buf, ALIAS_LEN, "%s\n", disk->alias);
-       return ret;
-}
-
-static ssize_t alias_store(struct device *dev, struct device_attribute *attr,
-                          const char *buf, size_t count)
-{
-       struct gendisk *disk = dev_to_disk(dev);
-       char *alias;
-       char *envp[] = { NULL, NULL };
-       unsigned char c;
-       int i;
-       ssize_t ret = count;
-
-       if (!count)
-               return -EINVAL;
-
-       if (count >= ALIAS_LEN) {
-               printk(KERN_ERR "alias: alias is too long\n");
-               return -EINVAL;
-       }
-
-       /* Validation check */
-       for (i = 0; i < count; i++) {
-               c = buf[i];
-               if (i == count - 1 && c == '\n')
-                       break;
-               if (!isalnum(c) && c != '_' && c != '-') {
-                       printk(KERN_ERR "alias: invalid alias\n");
-                       return -EINVAL;
-               }
-       }
-
-       if (disk->alias) {
-               printk(KERN_INFO "alias: %s is already assigned (%s)\n",
-                      disk->disk_name, disk->alias);
-               return -EINVAL;
-       }
-
-       alias = kasprintf(GFP_KERNEL, "%s", buf);
-       if (!alias)
-               return -ENOMEM;
-
-       if (alias[count - 1] == '\n')
-               alias[count - 1] = '\0';
-
-       envp[0] = kasprintf(GFP_KERNEL, "ALIAS=%s", alias);
-       if (!envp[0]) {
-               kfree(alias);
-               return -ENOMEM;
-       }
-
-       disk->alias = alias;
-       printk(KERN_INFO "alias: assigned %s to %s\n", alias, disk->disk_name);
-
-       kobject_uevent_env(&dev->kobj, KOBJ_ADD, envp);
-
-       kfree(envp[0]);
-       return ret;
-}
-
 static ssize_t disk_range_show(struct device *dev,
                               struct device_attribute *attr, char *buf)
 {
@@ -1043,7 +974,6 @@ static ssize_t disk_discard_alignment_show(struct device *dev,
        return sprintf(buf, "%d\n", queue_discard_alignment(disk->queue));
 }
 
-static DEVICE_ATTR(alias, S_IRUGO|S_IWUSR, alias_show, alias_store);
 static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL);
 static DEVICE_ATTR(ext_range, S_IRUGO, disk_ext_range_show, NULL);
 static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL);
@@ -1066,7 +996,6 @@ static struct device_attribute dev_attr_fail_timeout =
 #endif
 
 static struct attribute *disk_attrs[] = {
-       &dev_attr_alias.attr,
        &dev_attr_range.attr,
        &dev_attr_ext_range.attr,
        &dev_attr_removable.attr,
index a816f24..a0f768c 100644 (file)
@@ -383,6 +383,7 @@ static int crypto_init_ablkcipher_ops(struct crypto_tfm *tfm, u32 type,
        return 0;
 }
 
+#ifdef CONFIG_NET
 static int crypto_ablkcipher_report(struct sk_buff *skb, struct crypto_alg *alg)
 {
        struct crypto_report_blkcipher rblkcipher;
@@ -404,6 +405,12 @@ static int crypto_ablkcipher_report(struct sk_buff *skb, struct crypto_alg *alg)
 nla_put_failure:
        return -EMSGSIZE;
 }
+#else
+static int crypto_ablkcipher_report(struct sk_buff *skb, struct crypto_alg *alg)
+{
+       return -ENOSYS;
+}
+#endif
 
 static void crypto_ablkcipher_show(struct seq_file *m, struct crypto_alg *alg)
        __attribute__ ((unused));
@@ -457,6 +464,7 @@ static int crypto_init_givcipher_ops(struct crypto_tfm *tfm, u32 type,
        return 0;
 }
 
+#ifdef CONFIG_NET
 static int crypto_givcipher_report(struct sk_buff *skb, struct crypto_alg *alg)
 {
        struct crypto_report_blkcipher rblkcipher;
@@ -478,6 +486,12 @@ static int crypto_givcipher_report(struct sk_buff *skb, struct crypto_alg *alg)
 nla_put_failure:
        return -EMSGSIZE;
 }
+#else
+static int crypto_givcipher_report(struct sk_buff *skb, struct crypto_alg *alg)
+{
+       return -ENOSYS;
+}
+#endif
 
 static void crypto_givcipher_show(struct seq_file *m, struct crypto_alg *alg)
        __attribute__ ((unused));
index 701556f..04add3d 100644 (file)
@@ -111,6 +111,7 @@ static int crypto_init_aead_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
        return 0;
 }
 
+#ifdef CONFIG_NET
 static int crypto_aead_report(struct sk_buff *skb, struct crypto_alg *alg)
 {
        struct crypto_report_aead raead;
@@ -132,6 +133,12 @@ static int crypto_aead_report(struct sk_buff *skb, struct crypto_alg *alg)
 nla_put_failure:
        return -EMSGSIZE;
 }
+#else
+static int crypto_aead_report(struct sk_buff *skb, struct crypto_alg *alg)
+{
+       return -ENOSYS;
+}
+#endif
 
 static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg)
        __attribute__ ((unused));
@@ -190,6 +197,7 @@ static int crypto_init_nivaead_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
        return 0;
 }
 
+#ifdef CONFIG_NET
 static int crypto_nivaead_report(struct sk_buff *skb, struct crypto_alg *alg)
 {
        struct crypto_report_aead raead;
@@ -210,6 +218,12 @@ static int crypto_nivaead_report(struct sk_buff *skb, struct crypto_alg *alg)
 nla_put_failure:
        return -EMSGSIZE;
 }
+#else
+static int crypto_nivaead_report(struct sk_buff *skb, struct crypto_alg *alg)
+{
+       return -ENOSYS;
+}
+#endif
 
 
 static void crypto_nivaead_show(struct seq_file *m, struct crypto_alg *alg)
index a3e6ef9..ac93c99 100644 (file)
@@ -399,6 +399,7 @@ static unsigned int crypto_ahash_extsize(struct crypto_alg *alg)
        return sizeof(struct crypto_shash *);
 }
 
+#ifdef CONFIG_NET
 static int crypto_ahash_report(struct sk_buff *skb, struct crypto_alg *alg)
 {
        struct crypto_report_hash rhash;
@@ -416,6 +417,12 @@ static int crypto_ahash_report(struct sk_buff *skb, struct crypto_alg *alg)
 nla_put_failure:
        return -EMSGSIZE;
 }
+#else
+static int crypto_ahash_report(struct sk_buff *skb, struct crypto_alg *alg)
+{
+       return -ENOSYS;
+}
+#endif
 
 static void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg)
        __attribute__ ((unused));
index 2572d26..1e61d1a 100644 (file)
@@ -494,6 +494,7 @@ static int crypto_init_blkcipher_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
                return crypto_init_blkcipher_ops_async(tfm);
 }
 
+#ifdef CONFIG_NET
 static int crypto_blkcipher_report(struct sk_buff *skb, struct crypto_alg *alg)
 {
        struct crypto_report_blkcipher rblkcipher;
@@ -515,6 +516,12 @@ static int crypto_blkcipher_report(struct sk_buff *skb, struct crypto_alg *alg)
 nla_put_failure:
        return -EMSGSIZE;
 }
+#else
+static int crypto_blkcipher_report(struct sk_buff *skb, struct crypto_alg *alg)
+{
+       return -ENOSYS;
+}
+#endif
 
 static void crypto_blkcipher_show(struct seq_file *m, struct crypto_alg *alg)
        __attribute__ ((unused));
index 2abca78..0605a2b 100644 (file)
@@ -44,9 +44,6 @@ static struct crypto_alg *crypto_alg_match(struct crypto_user_alg *p, int exact)
 
        down_read(&crypto_alg_sem);
 
-       if (list_empty(&crypto_alg_list))
-               return NULL;
-
        list_for_each_entry(q, &crypto_alg_list, cra_list) {
                int match = 0;
 
index fefda78..2e458e5 100644 (file)
@@ -48,6 +48,7 @@ static int crypto_pcomp_init_tfm(struct crypto_tfm *tfm)
        return 0;
 }
 
+#ifdef CONFIG_NET
 static int crypto_pcomp_report(struct sk_buff *skb, struct crypto_alg *alg)
 {
        struct crypto_report_comp rpcomp;
@@ -62,6 +63,12 @@ static int crypto_pcomp_report(struct sk_buff *skb, struct crypto_alg *alg)
 nla_put_failure:
        return -EMSGSIZE;
 }
+#else
+static int crypto_pcomp_report(struct sk_buff *skb, struct crypto_alg *alg)
+{
+       return -ENOSYS;
+}
+#endif
 
 static void crypto_pcomp_show(struct seq_file *m, struct crypto_alg *alg)
        __attribute__ ((unused));
index feb7de0..64f864f 100644 (file)
@@ -60,6 +60,7 @@ static int crypto_init_rng_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
        return 0;
 }
 
+#ifdef CONFIG_NET
 static int crypto_rng_report(struct sk_buff *skb, struct crypto_alg *alg)
 {
        struct crypto_report_rng rrng;
@@ -76,6 +77,12 @@ static int crypto_rng_report(struct sk_buff *skb, struct crypto_alg *alg)
 nla_put_failure:
        return -EMSGSIZE;
 }
+#else
+static int crypto_rng_report(struct sk_buff *skb, struct crypto_alg *alg)
+{
+       return -ENOSYS;
+}
+#endif
 
 static void crypto_rng_show(struct seq_file *m, struct crypto_alg *alg)
        __attribute__ ((unused));
index ea8a9c6..9100912 100644 (file)
@@ -524,6 +524,7 @@ static unsigned int crypto_shash_extsize(struct crypto_alg *alg)
        return alg->cra_ctxsize;
 }
 
+#ifdef CONFIG_NET
 static int crypto_shash_report(struct sk_buff *skb, struct crypto_alg *alg)
 {
        struct crypto_report_hash rhash;
@@ -541,6 +542,12 @@ static int crypto_shash_report(struct sk_buff *skb, struct crypto_alg *alg)
 nla_put_failure:
        return -EMSGSIZE;
 }
+#else
+static int crypto_shash_report(struct sk_buff *skb, struct crypto_alg *alg)
+{
+       return -ENOSYS;
+}
+#endif
 
 static void crypto_shash_show(struct seq_file *m, struct crypto_alg *alg)
        __attribute__ ((unused));
index 73b2909..0e8e2de 100644 (file)
@@ -224,7 +224,6 @@ static void lapic_timer_state_broadcast(struct acpi_processor *pr,
 /*
  * Suspend / resume control
  */
-static int acpi_idle_suspend;
 static u32 saved_bm_rld;
 
 static void acpi_idle_bm_rld_save(void)
@@ -243,21 +242,13 @@ static void acpi_idle_bm_rld_restore(void)
 
 int acpi_processor_suspend(struct acpi_device * device, pm_message_t state)
 {
-       if (acpi_idle_suspend == 1)
-               return 0;
-
        acpi_idle_bm_rld_save();
-       acpi_idle_suspend = 1;
        return 0;
 }
 
 int acpi_processor_resume(struct acpi_device * device)
 {
-       if (acpi_idle_suspend == 0)
-               return 0;
-
        acpi_idle_bm_rld_restore();
-       acpi_idle_suspend = 0;
        return 0;
 }
 
@@ -763,13 +754,6 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev,
 
        local_irq_disable();
 
-       /* Do not access any ACPI IO ports in suspend path */
-       if (acpi_idle_suspend) {
-               local_irq_enable();
-               cpu_relax();
-               return -EINVAL;
-       }
-
        lapic_timer_state_broadcast(pr, cx, 1);
        kt1 = ktime_get_real();
        acpi_idle_do_entry(cx);
@@ -810,13 +794,6 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
 
        local_irq_disable();
 
-       if (acpi_idle_suspend) {
-               local_irq_enable();
-               cpu_relax();
-               return -EINVAL;
-       }
-
-
        if (cx->entry_method != ACPI_CSTATE_FFH) {
                current_thread_info()->status &= ~TS_POLLING;
                /*
@@ -895,12 +872,6 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
        if (unlikely(!pr))
                return -EINVAL;
 
-
-       if (acpi_idle_suspend) {
-               cpu_relax();
-               return -EINVAL;
-       }
-
        if (!cx->bm_sts_skip && acpi_idle_bm_check()) {
                if (drv->safe_state_index >= 0) {
                        return drv->states[drv->safe_state_index].enter(dev,
index fb7b90b..cf26222 100644 (file)
@@ -390,6 +390,9 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        /* Promise */
        { PCI_VDEVICE(PROMISE, 0x3f20), board_ahci },   /* PDC42819 */
 
+       /* Asmedia */
+       { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci },   /* ASM1061 */
+
        /* Generic, PCI class code for AHCI */
        { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
          PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci },
index 004f2ce..ec55595 100644 (file)
@@ -65,7 +65,7 @@ static struct scsi_host_template ahci_platform_sht = {
 static int __init ahci_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct ahci_platform_data *pdata = dev->platform_data;
+       struct ahci_platform_data *pdata = dev_get_platdata(dev);
        const struct platform_device_id *id = platform_get_device_id(pdev);
        struct ata_port_info pi = ahci_port_info[id->driver_data];
        const struct ata_port_info *ppi[] = { &pi, NULL };
@@ -191,7 +191,7 @@ err0:
 static int __devexit ahci_remove(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct ahci_platform_data *pdata = dev->platform_data;
+       struct ahci_platform_data *pdata = dev_get_platdata(dev);
        struct ata_host *host = dev_get_drvdata(dev);
 
        ata_host_detach(host);
index f22957c..a9b2820 100644 (file)
@@ -2883,7 +2883,7 @@ int ata_eh_reset(struct ata_link *link, int classify,
            sata_scr_read(link, SCR_STATUS, &sstatus))
                rc = -ERESTART;
 
-       if (rc == -ERESTART || try >= max_tries) {
+       if (try >= max_tries) {
                /*
                 * Thaw host port even if reset failed, so that the port
                 * can be retried on the next phy event.  This risks
@@ -2909,6 +2909,16 @@ int ata_eh_reset(struct ata_link *link, int classify,
                ata_eh_acquire(ap);
        }
 
+       /*
+        * While disks spinup behind PMP, some controllers fail sending SRST.
+        * They need to be reset - as well as the PMP - before retrying.
+        */
+       if (rc == -ERESTART) {
+               if (ata_is_host_link(link))
+                       ata_eh_thaw_port(ap);
+               goto out;
+       }
+
        if (try == max_tries - 1) {
                sata_down_spd_limit(link, 0);
                if (slave)
index 104462d..21b80c5 100644 (file)
@@ -389,12 +389,9 @@ static void sata_pmp_quirks(struct ata_port *ap)
                        /* link reports offline after LPM */
                        link->flags |= ATA_LFLAG_NO_LPM;
 
-                       /* Class code report is unreliable and SRST
-                        * times out under certain configurations.
-                        */
+                       /* Class code report is unreliable. */
                        if (link->pmp < 5)
-                               link->flags |= ATA_LFLAG_NO_SRST |
-                                              ATA_LFLAG_ASSUME_ATA;
+                               link->flags |= ATA_LFLAG_ASSUME_ATA;
 
                        /* port 5 is for SEMB device and it doesn't like SRST */
                        if (link->pmp == 5)
index 72a9770..2a5412e 100644 (file)
@@ -1217,6 +1217,10 @@ void ata_scsi_slave_destroy(struct scsi_device *sdev)
 
 /**
  *     __ata_change_queue_depth - helper for ata_scsi_change_queue_depth
+ *     @ap: ATA port to which the device change the queue depth
+ *     @sdev: SCSI device to configure queue depth for
+ *     @queue_depth: new queue depth
+ *     @reason: calling context
  *
  *     libsas and libata have different approaches for associating a sdev to
  *     its ata_port.
index a72ab0d..2a472c5 100644 (file)
@@ -52,7 +52,7 @@ static int __devinit pata_of_platform_probe(struct platform_device *ofdev)
        }
 
        ret = of_irq_to_resource(dn, 0, &irq_res);
-       if (ret == NO_IRQ)
+       if (!ret)
                irq_res.start = irq_res.end = 0;
        else
                irq_res.flags = 0;
index 447d9c0..95ec435 100644 (file)
@@ -104,7 +104,7 @@ static const struct ata_port_info sis_port_info = {
 };
 
 MODULE_AUTHOR("Uwe Koziolek");
-MODULE_DESCRIPTION("low-level driver for Silicon Integratad Systems SATA controller");
+MODULE_DESCRIPTION("low-level driver for Silicon Integrated Systems SATA controller");
 MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(pci, sis_pci_tbl);
 MODULE_VERSION(DRV_VERSION);
index 82c8654..d8b3d89 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/kallsyms.h>
 #include <linux/mutex.h>
 #include <linux/async.h>
+#include <linux/pm_runtime.h>
 
 #include "base.h"
 #include "power/power.h"
@@ -1742,6 +1743,8 @@ void device_shutdown(void)
                 */
                list_del_init(&dev->kobj.entry);
                spin_unlock(&devices_kset->list_lock);
+               /* Disable all device's runtime power management */
+               pm_runtime_disable(dev);
 
                if (dev->bus && dev->bus->shutdown) {
                        dev_dbg(dev, "shutdown\n");
index 5f0f85d..428e55e 100644 (file)
@@ -229,7 +229,8 @@ int pm_clk_suspend(struct device *dev)
 
        list_for_each_entry_reverse(ce, &psd->clock_list, node) {
                if (ce->status < PCE_STATUS_ERROR) {
-                       clk_disable(ce->clk);
+                       if (ce->status == PCE_STATUS_ENABLED)
+                               clk_disable(ce->clk);
                        ce->status = PCE_STATUS_ACQUIRED;
                }
        }
index 7fa0984..c3d2dfc 100644 (file)
@@ -920,7 +920,8 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
  End:
        if (!error) {
                dev->power.is_suspended = true;
-               if (dev->power.wakeup_path && dev->parent)
+               if (dev->power.wakeup_path
+                   && dev->parent && !dev->parent->power.ignore_children)
                        dev->parent->power.wakeup_path = true;
        }
 
index 434a6c0..95706fa 100644 (file)
@@ -669,7 +669,7 @@ struct srcu_notifier_head *opp_get_notifier(struct device *dev)
        struct device_opp *dev_opp = find_device_opp(dev);
 
        if (IS_ERR(dev_opp))
-               return ERR_PTR(PTR_ERR(dev_opp)); /* matching type */
+               return ERR_CAST(dev_opp); /* matching type */
 
        return &dev_opp->head;
 }
index 30a94ea..86de6c5 100644 (file)
@@ -212,11 +212,9 @@ int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
        if (!dev || !req) /*guard against callers passing in null */
                return -EINVAL;
 
-       if (dev_pm_qos_request_active(req)) {
-               WARN(1, KERN_ERR "dev_pm_qos_add_request() called for already "
-                       "added request\n");
+       if (WARN(dev_pm_qos_request_active(req),
+                "%s() called for already added request\n", __func__))
                return -EINVAL;
-       }
 
        req->dev = dev;
 
@@ -271,11 +269,9 @@ int dev_pm_qos_update_request(struct dev_pm_qos_request *req,
        if (!req) /*guard against callers passing in null */
                return -EINVAL;
 
-       if (!dev_pm_qos_request_active(req)) {
-               WARN(1, KERN_ERR "dev_pm_qos_update_request() called for "
-                       "unknown object\n");
+       if (WARN(!dev_pm_qos_request_active(req),
+                "%s() called for unknown object\n", __func__))
                return -EINVAL;
-       }
 
        mutex_lock(&dev_pm_qos_mtx);
 
@@ -312,11 +308,9 @@ int dev_pm_qos_remove_request(struct dev_pm_qos_request *req)
        if (!req) /*guard against callers passing in null */
                return -EINVAL;
 
-       if (!dev_pm_qos_request_active(req)) {
-               WARN(1, KERN_ERR "dev_pm_qos_remove_request() called for "
-                       "unknown object\n");
+       if (WARN(!dev_pm_qos_request_active(req),
+                "%s() called for unknown object\n", __func__))
                return -EINVAL;
-       }
 
        mutex_lock(&dev_pm_qos_mtx);
 
index 486f94e..8004ac3 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/interrupt.h>
 #include <linux/types.h>
 #include <linux/pci.h>
+#include <linux/pci-aspm.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
@@ -4319,6 +4320,10 @@ static int __devinit cciss_pci_init(ctlr_info_t *h)
                dev_warn(&h->pdev->dev, "controller appears to be disabled\n");
                return -ENODEV;
        }
+
+       pci_disable_link_state(h->pdev, PCIE_LINK_STATE_L0S |
+                               PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_CLKPM);
+
        err = pci_enable_device(h->pdev);
        if (err) {
                dev_warn(&h->pdev->dev, "Unable to Enable PCI device\n");
@@ -5158,6 +5163,7 @@ reinit_after_soft_reset:
        h->cciss_max_sectors = 8192;
 
        rebuild_lun_table(h, 1, 0);
+       cciss_engage_scsi(h);
        h->busy_initializing = 0;
        return 1;
 
index 951a4e3..e820b68 100644 (file)
@@ -1720,5 +1720,6 @@ static int  cciss_eh_abort_handler(struct scsi_cmnd *scsicmd)
 /* If no tape support, then these become defined out of existence */
 
 #define cciss_scsi_setup(cntl_num)
+#define cciss_engage_scsi(h)
 
 #endif /* CONFIG_CISS_SCSI_TAPE */
index 3d80682..68b205a 100644 (file)
@@ -161,17 +161,19 @@ static struct loop_func_table *xfer_funcs[MAX_LO_CRYPT] = {
        &xor_funcs
 };
 
-static loff_t get_loop_size(struct loop_device *lo, struct file *file)
+static loff_t get_size(loff_t offset, loff_t sizelimit, struct file *file)
 {
-       loff_t size, offset, loopsize;
+       loff_t size, loopsize;
 
        /* Compute loopsize in bytes */
        size = i_size_read(file->f_mapping->host);
-       offset = lo->lo_offset;
        loopsize = size - offset;
-       if (lo->lo_sizelimit > 0 && lo->lo_sizelimit < loopsize)
-               loopsize = lo->lo_sizelimit;
+       /* offset is beyond i_size, wierd but possible */
+       if (loopsize < 0)
+               return 0;
 
+       if (sizelimit > 0 && sizelimit < loopsize)
+               loopsize = sizelimit;
        /*
         * Unfortunately, if we want to do I/O on the device,
         * the number of 512-byte sectors has to fit into a sector_t.
@@ -179,17 +181,25 @@ static loff_t get_loop_size(struct loop_device *lo, struct file *file)
        return loopsize >> 9;
 }
 
+static loff_t get_loop_size(struct loop_device *lo, struct file *file)
+{
+       return get_size(lo->lo_offset, lo->lo_sizelimit, file);
+}
+
 static int
-figure_loop_size(struct loop_device *lo)
+figure_loop_size(struct loop_device *lo, loff_t offset, loff_t sizelimit)
 {
-       loff_t size = get_loop_size(lo, lo->lo_backing_file);
+       loff_t size = get_size(offset, sizelimit, lo->lo_backing_file);
        sector_t x = (sector_t)size;
 
        if (unlikely((loff_t)x != size))
                return -EFBIG;
-
+       if (lo->lo_offset != offset)
+               lo->lo_offset = offset;
+       if (lo->lo_sizelimit != sizelimit)
+               lo->lo_sizelimit = sizelimit;
        set_capacity(lo->lo_disk, x);
-       return 0;                                       
+       return 0;
 }
 
 static inline int
@@ -372,7 +382,8 @@ do_lo_receive(struct loop_device *lo,
 
        if (retval < 0)
                return retval;
-
+       if (retval != bvec->bv_len)
+               return -EIO;
        return 0;
 }
 
@@ -1058,9 +1069,7 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
 
        if (lo->lo_offset != info->lo_offset ||
            lo->lo_sizelimit != info->lo_sizelimit) {
-               lo->lo_offset = info->lo_offset;
-               lo->lo_sizelimit = info->lo_sizelimit;
-               if (figure_loop_size(lo))
+               if (figure_loop_size(lo, info->lo_offset, info->lo_sizelimit))
                        return -EFBIG;
        }
        loop_config_discard(lo);
@@ -1246,7 +1255,7 @@ static int loop_set_capacity(struct loop_device *lo, struct block_device *bdev)
        err = -ENXIO;
        if (unlikely(lo->lo_state != Lo_bound))
                goto out;
-       err = figure_loop_size(lo);
+       err = figure_loop_size(lo, lo->lo_offset, lo->lo_sizelimit);
        if (unlikely(err))
                goto out;
        sec = get_capacity(lo->lo_disk);
@@ -1284,13 +1293,19 @@ static int lo_ioctl(struct block_device *bdev, fmode_t mode,
                        goto out_unlocked;
                break;
        case LOOP_SET_STATUS:
-               err = loop_set_status_old(lo, (struct loop_info __user *) arg);
+               err = -EPERM;
+               if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN))
+                       err = loop_set_status_old(lo,
+                                       (struct loop_info __user *)arg);
                break;
        case LOOP_GET_STATUS:
                err = loop_get_status_old(lo, (struct loop_info __user *) arg);
                break;
        case LOOP_SET_STATUS64:
-               err = loop_set_status64(lo, (struct loop_info64 __user *) arg);
+               err = -EPERM;
+               if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN))
+                       err = loop_set_status64(lo,
+                                       (struct loop_info64 __user *) arg);
                break;
        case LOOP_GET_STATUS64:
                err = loop_get_status64(lo, (struct loop_info64 __user *) arg);
index 6b9a200..a79fb4f 100644 (file)
@@ -630,6 +630,7 @@ static ssize_t pg_read(struct file *filp, char __user *buf, size_t count, loff_t
                if (dev->status & 0x10)
                        return -ETIME;
 
+       memset(&hdr, 0, sizeof(hdr));
        hdr.magic = PG_MAGIC;
        hdr.dlen = dev->dlen;
        copy = 0;
index 106beb1..1622772 100644 (file)
@@ -30,6 +30,7 @@
 #include <net/bluetooth/bluetooth.h>
 
 #define VERSION "1.0"
+#define ATH3K_FIRMWARE "ath3k-1.fw"
 
 #define ATH3K_DNLOAD                           0x01
 #define ATH3K_GETSTATE                         0x05
@@ -400,9 +401,15 @@ static int ath3k_probe(struct usb_interface *intf,
                return 0;
        }
 
-       if (request_firmware(&firmware, "ath3k-1.fw", &udev->dev) < 0) {
-               BT_ERR("Error loading firmware");
-               return -EIO;
+       ret = request_firmware(&firmware, ATH3K_FIRMWARE, &udev->dev);
+       if (ret < 0) {
+               if (ret == -ENOENT)
+                       BT_ERR("Firmware file \"%s\" not found",
+                                                       ATH3K_FIRMWARE);
+               else
+                       BT_ERR("Firmware file \"%s\" request failed (err=%d)",
+                                                       ATH3K_FIRMWARE, ret);
+               return ret;
        }
 
        ret = ath3k_load_firmware(udev, firmware);
@@ -441,4 +448,4 @@ MODULE_AUTHOR("Atheros Communications");
 MODULE_DESCRIPTION("Atheros AR30xx firmware driver");
 MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");
-MODULE_FIRMWARE("ath3k-1.fw");
+MODULE_FIRMWARE(ATH3K_FIRMWARE);
index 61b5914..a936763 100644 (file)
@@ -751,9 +751,7 @@ static void bfusb_disconnect(struct usb_interface *intf)
 
        bfusb_close(hdev);
 
-       if (hci_unregister_dev(hdev) < 0)
-               BT_ERR("Can't unregister HCI device %s", hdev->name);
-
+       hci_unregister_dev(hdev);
        hci_free_dev(hdev);
 }
 
index aed1904..c6a0c61 100644 (file)
@@ -844,9 +844,7 @@ static int bluecard_close(bluecard_info_t *info)
        /* Turn FPGA off */
        outb(0x80, iobase + 0x30);
 
-       if (hci_unregister_dev(hdev) < 0)
-               BT_ERR("Can't unregister HCI device %s", hdev->name);
-
+       hci_unregister_dev(hdev);
        hci_free_dev(hdev);
 
        return 0;
index 4fc0194..0c97e5d 100644 (file)
@@ -636,9 +636,7 @@ static int bt3c_close(bt3c_info_t *info)
 
        bt3c_hci_close(hdev);
 
-       if (hci_unregister_dev(hdev) < 0)
-               BT_ERR("Can't unregister HCI device %s", hdev->name);
-
+       hci_unregister_dev(hdev);
        hci_free_dev(hdev);
 
        return 0;
index 526b618..200b3a2 100644 (file)
@@ -565,9 +565,7 @@ static int btuart_close(btuart_info_t *info)
 
        spin_unlock_irqrestore(&(info->lock), flags);
 
-       if (hci_unregister_dev(hdev) < 0)
-               BT_ERR("Can't unregister HCI device %s", hdev->name);
-
+       hci_unregister_dev(hdev);
        hci_free_dev(hdev);
 
        return 0;
index f9b7260..2bd87d4 100644 (file)
@@ -100,6 +100,9 @@ static struct usb_device_id btusb_table[] = {
        /* Canyon CN-BTU1 with HID interfaces */
        { USB_DEVICE(0x0c10, 0x0000) },
 
+       /* Broadcom BCM20702A0 */
+       { USB_DEVICE(0x413c, 0x8197) },
+
        { }     /* Terminating entry */
 };
 
@@ -312,7 +315,8 @@ static int btusb_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags)
 
        err = usb_submit_urb(urb, mem_flags);
        if (err < 0) {
-               BT_ERR("%s urb %p submission failed (%d)",
+               if (err != -EPERM && err != -ENODEV)
+                       BT_ERR("%s urb %p submission failed (%d)",
                                                hdev->name, urb, -err);
                usb_unanchor_urb(urb);
        }
@@ -397,7 +401,8 @@ static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags)
 
        err = usb_submit_urb(urb, mem_flags);
        if (err < 0) {
-               BT_ERR("%s urb %p submission failed (%d)",
+               if (err != -EPERM && err != -ENODEV)
+                       BT_ERR("%s urb %p submission failed (%d)",
                                                hdev->name, urb, -err);
                usb_unanchor_urb(urb);
        }
@@ -520,7 +525,8 @@ static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags)
 
        err = usb_submit_urb(urb, mem_flags);
        if (err < 0) {
-               BT_ERR("%s urb %p submission failed (%d)",
+               if (err != -EPERM && err != -ENODEV)
+                       BT_ERR("%s urb %p submission failed (%d)",
                                                hdev->name, urb, -err);
                usb_unanchor_urb(urb);
        }
@@ -724,6 +730,9 @@ static int btusb_send_frame(struct sk_buff *skb)
                usb_fill_bulk_urb(urb, data->udev, pipe,
                                skb->data, skb->len, btusb_tx_complete, skb);
 
+               if (skb->priority >= HCI_PRIO_MAX - 1)
+                       urb->transfer_flags  = URB_ISO_ASAP;
+
                hdev->stat.acl_tx++;
                break;
 
@@ -767,7 +776,9 @@ skip_waking:
 
        err = usb_submit_urb(urb, GFP_ATOMIC);
        if (err < 0) {
-               BT_ERR("%s urb %p submission failed", hdev->name, urb);
+               if (err != -EPERM && err != -ENODEV)
+                       BT_ERR("%s urb %p submission failed (%d)",
+                                               hdev->name, urb, -err);
                kfree(urb->setup_packet);
                usb_unanchor_urb(urb);
        } else {
index 5e4c2de..969bb22 100644 (file)
@@ -551,9 +551,7 @@ static int dtl1_close(dtl1_info_t *info)
 
        spin_unlock_irqrestore(&(info->lock), flags);
 
-       if (hci_unregister_dev(hdev) < 0)
-               BT_ERR("Can't unregister HCI device %s", hdev->name);
-
+       hci_unregister_dev(hdev);
        hci_free_dev(hdev);
 
        return 0;
index 67c180c..2e302a1 100644 (file)
@@ -264,10 +264,7 @@ static int vhci_release(struct inode *inode, struct file *file)
        struct vhci_data *data = file->private_data;
        struct hci_dev *hdev = data->hdev;
 
-       if (hci_unregister_dev(hdev) < 0) {
-               BT_ERR("Can't unregister HCI device %s", hdev->name);
-       }
-
+       hci_unregister_dev(hdev);
        hci_free_dev(hdev);
 
        file->private_data = NULL;
index 66cd0b8..c92424c 100644 (file)
@@ -1186,10 +1186,11 @@ static void gen6_cleanup(void)
 /* Certain Gen5 chipsets require require idling the GPU before
  * unmapping anything from the GTT when VT-d is enabled.
  */
-extern int intel_iommu_gfx_mapped;
 static inline int needs_idle_maps(void)
 {
+#ifdef CONFIG_INTEL_IOMMU
        const unsigned short gpu_devid = intel_private.pcidev->device;
+       extern int intel_iommu_gfx_mapped;
 
        /* Query intel_iommu to see if we need the workaround. Presumably that
         * was loaded first.
@@ -1198,7 +1199,7 @@ static inline int needs_idle_maps(void)
             gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG) &&
             intel_iommu_gfx_mapped)
                return 1;
-
+#endif
        return 0;
 }
 
@@ -1236,7 +1237,7 @@ static int i9xx_setup(void)
                intel_private.gtt_bus_addr = reg_addr + gtt_offset;
        }
 
-       if (needs_idle_maps());
+       if (needs_idle_maps())
                intel_private.base.do_idle_maps = 1;
 
        intel_i9xx_setup_flush();
index 63e19ba..6035ab8 100644 (file)
@@ -941,7 +941,7 @@ void get_random_bytes(void *buf, int nbytes)
                if (!arch_get_random_long(&v))
                        break;
                
-               memcpy(buf, &v, chunk);
+               memcpy(p, &v, chunk);
                p += chunk;
                nbytes -= chunk;
        }
index edaa987..f500201 100644 (file)
@@ -109,7 +109,7 @@ static unsigned int db8500_cpufreq_getspeed(unsigned int cpu)
 
 static int __cpuinit db8500_cpufreq_init(struct cpufreq_policy *policy)
 {
-       int res;
+       int i, res;
 
        BUILD_BUG_ON(ARRAY_SIZE(idx2opp) + 1 != ARRAY_SIZE(freq_table));
 
@@ -120,8 +120,8 @@ static int __cpuinit db8500_cpufreq_init(struct cpufreq_policy *policy)
                        freq_table[3].frequency = 1000000;
        }
        pr_info("db8500-cpufreq : Available frequencies:\n");
-       while (freq_table[i].frequency != CPUFREQ_TABLE_END)
-               pr_info("  %d Mhz\n", freq_table[i++].frequency/1000);
+       for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++)
+               pr_info("  %d Mhz\n", freq_table[i].frequency/1000);
 
        /* get policy fields based on the table */
        res = cpufreq_frequency_table_cpuinfo(policy, freq_table);
index 643b055..8f04910 100644 (file)
@@ -1,36 +1,29 @@
-config ARCH_HAS_DEVFREQ
-       bool
-       depends on ARCH_HAS_OPP
-       help
-         Denotes that the architecture supports DEVFREQ. If the architecture
-         supports multiple OPP entries per device and the frequency of the
-         devices with OPPs may be altered dynamically, the architecture
-         supports DEVFREQ.
-
 menuconfig PM_DEVFREQ
        bool "Generic Dynamic Voltage and Frequency Scaling (DVFS) support"
-       depends on PM_OPP && ARCH_HAS_DEVFREQ
        help
-         With OPP support, a device may have a list of frequencies and
-         voltages available. DEVFREQ, a generic DVFS framework can be
-         registered for a device with OPP support in order to let the
-         governor provided to DEVFREQ choose an operating frequency
-         based on the OPP's list and the policy given with DEVFREQ.
+         A device may have a list of frequencies and voltages available.
+         devfreq, a generic DVFS framework can be registered for a device
+         in order to let the governor provided to devfreq choose an
+         operating frequency based on the device driver's policy.
 
-         Each device may have its own governor and policy. DEVFREQ can
+         Each device may have its own governor and policy. Devfreq can
          reevaluate the device state periodically and/or based on the
-         OPP list changes (each frequency/voltage pair in OPP may be
-         disabled or enabled).
+         notification to "nb", a notifier block, of devfreq.
 
-         Like some CPUs with CPUFREQ, a device may have multiple clocks.
+         Like some CPUs with CPUfreq, a device may have multiple clocks.
          However, because the clock frequencies of a single device are
-         determined by the single device's state, an instance of DEVFREQ
+         determined by the single device's state, an instance of devfreq
          is attached to a single device and returns a "representative"
-         clock frequency from the OPP of the device, which is also attached
-         to a device by 1-to-1. The device registering DEVFREQ takes the
-         responsiblity to "interpret" the frequency listed in OPP and
+         clock frequency of the device, which is also attached
+         to a device by 1-to-1. The device registering devfreq takes the
+         responsiblity to "interpret" the representative frequency and
          to set its every clock accordingly with the "target" callback
-         given to DEVFREQ.
+         given to devfreq.
+
+         When OPP is used with the devfreq device, it is recommended to
+         register devfreq's nb to the OPP's notifier head.  If OPP is
+         used with the devfreq device, you may use OPP helper
+         functions defined in devfreq.h.
 
 if PM_DEVFREQ
 
index 5d15b81..59d24e9 100644 (file)
@@ -15,7 +15,9 @@
 #include <linux/errno.h>
 #include <linux/err.h>
 #include <linux/init.h>
+#include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/stat.h>
 #include <linux/opp.h>
 #include <linux/devfreq.h>
 #include <linux/workqueue.h>
@@ -416,10 +418,14 @@ out:
  */
 int devfreq_remove_device(struct devfreq *devfreq)
 {
+       bool central_polling;
+
        if (!devfreq)
                return -EINVAL;
 
-       if (!devfreq->governor->no_central_polling) {
+       central_polling = !devfreq->governor->no_central_polling;
+
+       if (central_polling) {
                mutex_lock(&devfreq_list_lock);
                while (wait_remove_device == devfreq) {
                        mutex_unlock(&devfreq_list_lock);
@@ -431,7 +437,7 @@ int devfreq_remove_device(struct devfreq *devfreq)
        mutex_lock(&devfreq->lock);
        _remove_devfreq(devfreq, false); /* it unlocks devfreq->lock */
 
-       if (!devfreq->governor->no_central_polling)
+       if (central_polling)
                mutex_unlock(&devfreq_list_lock);
 
        return 0;
index bcb1126..153980b 100644 (file)
@@ -585,14 +585,12 @@ int dmi_name_in_serial(const char *str)
 }
 
 /**
- *     dmi_name_in_vendors - Check if string is anywhere in the DMI vendor information.
+ *     dmi_name_in_vendors - Check if string is in the DMI system or board vendor name
  *     @str:   Case sensitive Name
  */
 int dmi_name_in_vendors(const char *str)
 {
-       static int fields[] = { DMI_BIOS_VENDOR, DMI_BIOS_VERSION, DMI_SYS_VENDOR,
-                               DMI_PRODUCT_NAME, DMI_PRODUCT_VERSION, DMI_BOARD_VENDOR,
-                               DMI_BOARD_NAME, DMI_BOARD_VERSION, DMI_NONE };
+       static int fields[] = { DMI_SYS_VENDOR, DMI_BOARD_VENDOR, DMI_NONE };
        int i;
        for (i = 0; fields[i] != DMI_NONE; i++) {
                int f = fields[i];
index 0e49d87..0b05629 100644 (file)
@@ -148,13 +148,17 @@ static int _get_gpio_dataout(struct gpio_bank *bank, int gpio)
        return (__raw_readl(reg) & GPIO_BIT(bank, gpio)) != 0;
 }
 
-#define MOD_REG_BIT(reg, bit_mask, set)        \
-do {   \
-       int l = __raw_readl(base + reg); \
-       if (set) l |= bit_mask; \
-       else l &= ~bit_mask; \
-       __raw_writel(l, base + reg); \
-} while(0)
+static inline void _gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set)
+{
+       int l = __raw_readl(base + reg);
+
+       if (set) 
+               l |= mask;
+       else
+               l &= ~mask;
+
+       __raw_writel(l, base + reg);
+}
 
 /**
  * _set_gpio_debounce - low level gpio debounce time
@@ -210,28 +214,28 @@ static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio,
        u32 gpio_bit = 1 << gpio;
 
        if (cpu_is_omap44xx()) {
-               MOD_REG_BIT(OMAP4_GPIO_LEVELDETECT0, gpio_bit,
-                       trigger & IRQ_TYPE_LEVEL_LOW);
-               MOD_REG_BIT(OMAP4_GPIO_LEVELDETECT1, gpio_bit,
-                       trigger & IRQ_TYPE_LEVEL_HIGH);
-               MOD_REG_BIT(OMAP4_GPIO_RISINGDETECT, gpio_bit,
-                       trigger & IRQ_TYPE_EDGE_RISING);
-               MOD_REG_BIT(OMAP4_GPIO_FALLINGDETECT, gpio_bit,
-                       trigger & IRQ_TYPE_EDGE_FALLING);
+               _gpio_rmw(base, OMAP4_GPIO_LEVELDETECT0, gpio_bit,
+                         trigger & IRQ_TYPE_LEVEL_LOW);
+               _gpio_rmw(base, OMAP4_GPIO_LEVELDETECT1, gpio_bit,
+                         trigger & IRQ_TYPE_LEVEL_HIGH);
+               _gpio_rmw(base, OMAP4_GPIO_RISINGDETECT, gpio_bit,
+                         trigger & IRQ_TYPE_EDGE_RISING);
+               _gpio_rmw(base, OMAP4_GPIO_FALLINGDETECT, gpio_bit,
+                         trigger & IRQ_TYPE_EDGE_FALLING);
        } else {
-               MOD_REG_BIT(OMAP24XX_GPIO_LEVELDETECT0, gpio_bit,
-                       trigger & IRQ_TYPE_LEVEL_LOW);
-               MOD_REG_BIT(OMAP24XX_GPIO_LEVELDETECT1, gpio_bit,
-                       trigger & IRQ_TYPE_LEVEL_HIGH);
-               MOD_REG_BIT(OMAP24XX_GPIO_RISINGDETECT, gpio_bit,
-                       trigger & IRQ_TYPE_EDGE_RISING);
-               MOD_REG_BIT(OMAP24XX_GPIO_FALLINGDETECT, gpio_bit,
-                       trigger & IRQ_TYPE_EDGE_FALLING);
+               _gpio_rmw(base, OMAP24XX_GPIO_LEVELDETECT0, gpio_bit,
+                         trigger & IRQ_TYPE_LEVEL_LOW);
+               _gpio_rmw(base, OMAP24XX_GPIO_LEVELDETECT1, gpio_bit,
+                         trigger & IRQ_TYPE_LEVEL_HIGH);
+               _gpio_rmw(base, OMAP24XX_GPIO_RISINGDETECT, gpio_bit,
+                         trigger & IRQ_TYPE_EDGE_RISING);
+               _gpio_rmw(base, OMAP24XX_GPIO_FALLINGDETECT, gpio_bit,
+                         trigger & IRQ_TYPE_EDGE_FALLING);
        }
        if (likely(!(bank->non_wakeup_gpios & gpio_bit))) {
                if (cpu_is_omap44xx()) {
-                       MOD_REG_BIT(OMAP4_GPIO_IRQWAKEN0, gpio_bit,
-                               trigger != 0);
+                       _gpio_rmw(base, OMAP4_GPIO_IRQWAKEN0, gpio_bit,
+                                 trigger != 0);
                } else {
                        /*
                         * GPIO wakeup request can only be generated on edge
@@ -1086,6 +1090,11 @@ omap_mpuio_alloc_gc(struct gpio_bank *bank, unsigned int irq_start,
 
        gc = irq_alloc_generic_chip("MPUIO", 1, irq_start, bank->base,
                                    handle_simple_irq);
+       if (!gc) {
+               dev_err(bank->dev, "Memory alloc failed for gc\n");
+               return;
+       }
+
        ct = gc->chip_types;
 
        /* NOTE: No ack required, reading IRQ status clears it. */
index 0550dcb..147df8a 100644 (file)
@@ -596,9 +596,6 @@ static int __devinit device_pca953x_init(struct pca953x_chip *chip, int invert)
 
        /* set platform specific polarity inversion */
        ret = pca953x_write_reg(chip, PCA953X_INVERT, invert);
-       if (ret)
-               goto out;
-       return 0;
 out:
        return ret;
 }
@@ -640,7 +637,7 @@ static int __devinit pca953x_probe(struct i2c_client *client,
        struct pca953x_platform_data *pdata;
        struct pca953x_chip *chip;
        int irq_base=0, invert=0;
-       int ret = 0;
+       int ret;
 
        chip = kzalloc(sizeof(struct pca953x_chip), GFP_KERNEL);
        if (chip == NULL)
@@ -673,10 +670,10 @@ static int __devinit pca953x_probe(struct i2c_client *client,
        pca953x_setup_gpio(chip, id->driver_data & PCA_GPIO_MASK);
 
        if (chip->chip_type == PCA953X_TYPE)
-               device_pca953x_init(chip, invert);
-       else if (chip->chip_type == PCA957X_TYPE)
-               device_pca957x_init(chip, invert);
+               ret = device_pca953x_init(chip, invert);
        else
+               ret = device_pca957x_init(chip, invert);
+       if (ret)
                goto out_failed;
 
        ret = pca953x_irq_setup(chip, id, irq_base);
index 785127c..1368826 100644 (file)
@@ -9,7 +9,6 @@ menuconfig DRM
        depends on (AGP || AGP=n) && !EMULATED_CMPXCHG && MMU
        select I2C
        select I2C_ALGOBIT
-       select SLOW_WORK
        help
          Kernel-level support for the Direct Rendering Infrastructure (DRI)
          introduced in XFree86 4.0. If you say Y here, you need to select
@@ -96,6 +95,7 @@ config DRM_I915
        select FB_CFB_IMAGEBLIT
        # i915 depends on ACPI_VIDEO when ACPI is enabled
        # but for select to work, need to select ACPI_VIDEO's dependencies, ick
+       select BACKLIGHT_LCD_SUPPORT if ACPI
        select BACKLIGHT_CLASS_DEVICE if ACPI
        select VIDEO_OUTPUT_CONTROL if ACPI
        select INPUT if ACPI
index 9a2e2a1..405c63b 100644 (file)
@@ -2118,8 +2118,10 @@ struct drm_property *drm_property_create(struct drm_device *dev, int flags,
        property->num_values = num_values;
        INIT_LIST_HEAD(&property->enum_blob_list);
 
-       if (name)
+       if (name) {
                strncpy(property->name, name, DRM_PROP_NAME_LEN);
+               property->name[DRM_PROP_NAME_LEN-1] = '\0';
+       }
 
        list_add_tail(&property->head, &dev->mode_config.property_list);
        return property;
index 2957636..3969f75 100644 (file)
@@ -484,6 +484,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
        struct drm_connector *save_connectors, *connector;
        int count = 0, ro, fail = 0;
        struct drm_crtc_helper_funcs *crtc_funcs;
+       struct drm_mode_set save_set;
        int ret = 0;
        int i;
 
@@ -556,6 +557,12 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
                save_connectors[count++] = *connector;
        }
 
+       save_set.crtc = set->crtc;
+       save_set.mode = &set->crtc->mode;
+       save_set.x = set->crtc->x;
+       save_set.y = set->crtc->y;
+       save_set.fb = set->crtc->fb;
+
        /* We should be able to check here if the fb has the same properties
         * and then just flip_or_move it */
        if (set->crtc->fb != set->fb) {
@@ -721,6 +728,12 @@ fail:
                *connector = save_connectors[count++];
        }
 
+       /* Try to restore the config */
+       if (mode_changed &&
+           !drm_crtc_helper_set_mode(save_set.crtc, save_set.mode, save_set.x,
+                                     save_set.y, save_set.fb))
+               DRM_ERROR("failed to restore config after modeset failure\n");
+
        kfree(save_connectors);
        kfree(save_encoders);
        kfree(save_crtcs);
index d067c12..1c7a1c0 100644 (file)
@@ -118,7 +118,10 @@ int drm_debugfs_create_files(struct drm_info_list *files, int count,
                tmp->minor = minor;
                tmp->dent = ent;
                tmp->info_ent = &files[i];
-               list_add(&(tmp->list), &(minor->debugfs_nodes.list));
+
+               mutex_lock(&minor->debugfs_lock);
+               list_add(&tmp->list, &minor->debugfs_list);
+               mutex_unlock(&minor->debugfs_lock);
        }
        return 0;
 
@@ -146,7 +149,8 @@ int drm_debugfs_init(struct drm_minor *minor, int minor_id,
        char name[64];
        int ret;
 
-       INIT_LIST_HEAD(&minor->debugfs_nodes.list);
+       INIT_LIST_HEAD(&minor->debugfs_list);
+       mutex_init(&minor->debugfs_lock);
        sprintf(name, "%d", minor_id);
        minor->debugfs_root = debugfs_create_dir(name, root);
        if (!minor->debugfs_root) {
@@ -192,8 +196,9 @@ int drm_debugfs_remove_files(struct drm_info_list *files, int count,
        struct drm_info_node *tmp;
        int i;
 
+       mutex_lock(&minor->debugfs_lock);
        for (i = 0; i < count; i++) {
-               list_for_each_safe(pos, q, &minor->debugfs_nodes.list) {
+               list_for_each_safe(pos, q, &minor->debugfs_list) {
                        tmp = list_entry(pos, struct drm_info_node, list);
                        if (tmp->info_ent == &files[i]) {
                                debugfs_remove(tmp->dent);
@@ -202,6 +207,7 @@ int drm_debugfs_remove_files(struct drm_info_list *files, int count,
                        }
                }
        }
+       mutex_unlock(&minor->debugfs_lock);
        return 0;
 }
 EXPORT_SYMBOL(drm_debugfs_remove_files);
index fc81af9..40c187c 100644 (file)
@@ -125,7 +125,7 @@ static struct drm_ioctl_desc drm_ioctls[] = {
        DRM_IOCTL_DEF(DRM_IOCTL_SG_ALLOC, drm_sg_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
        DRM_IOCTL_DEF(DRM_IOCTL_SG_FREE, drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
 
-       DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, 0),
+       DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, DRM_UNLOCKED),
 
        DRM_IOCTL_DEF(DRM_IOCTL_MODESET_CTL, drm_modeset_ctl, 0),
 
index cb3794a..44a5d0a 100644 (file)
@@ -110,10 +110,7 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc)
        /* Prevent vblank irq processing while disabling vblank irqs,
         * so no updates of timestamps or count can happen after we've
         * disabled. Needed to prevent races in case of delayed irq's.
-        * Disable preemption, so vblank_time_lock is held as short as
-        * possible, even under a kernel with PREEMPT_RT patches.
         */
-       preempt_disable();
        spin_lock_irqsave(&dev->vblank_time_lock, irqflags);
 
        dev->driver->disable_vblank(dev, crtc);
@@ -164,7 +161,6 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc)
        clear_vblank_timestamps(dev, crtc);
 
        spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);
-       preempt_enable();
 }
 
 static void vblank_disable_fn(unsigned long arg)
@@ -407,13 +403,16 @@ int drm_irq_uninstall(struct drm_device *dev)
        /*
         * Wake up any waiters so they don't hang.
         */
-       spin_lock_irqsave(&dev->vbl_lock, irqflags);
-       for (i = 0; i < dev->num_crtcs; i++) {
-               DRM_WAKEUP(&dev->vbl_queue[i]);
-               dev->vblank_enabled[i] = 0;
-               dev->last_vblank[i] = dev->driver->get_vblank_counter(dev, i);
+       if (dev->num_crtcs) {
+               spin_lock_irqsave(&dev->vbl_lock, irqflags);
+               for (i = 0; i < dev->num_crtcs; i++) {
+                       DRM_WAKEUP(&dev->vbl_queue[i]);
+                       dev->vblank_enabled[i] = 0;
+                       dev->last_vblank[i] =
+                               dev->driver->get_vblank_counter(dev, i);
+               }
+               spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
        }
-       spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
 
        if (!irq_enabled)
                return -EINVAL;
@@ -886,10 +885,6 @@ int drm_vblank_get(struct drm_device *dev, int crtc)
        spin_lock_irqsave(&dev->vbl_lock, irqflags);
        /* Going from 0->1 means we have to enable interrupts again */
        if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1) {
-               /* Disable preemption while holding vblank_time_lock. Do
-                * it explicitely to guard against PREEMPT_RT kernel.
-                */
-               preempt_disable();
                spin_lock_irqsave(&dev->vblank_time_lock, irqflags2);
                if (!dev->vblank_enabled[crtc]) {
                        /* Enable vblank irqs under vblank_time_lock protection.
@@ -909,7 +904,6 @@ int drm_vblank_get(struct drm_device *dev, int crtc)
                        }
                }
                spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags2);
-               preempt_enable();
        } else {
                if (!dev->vblank_enabled[crtc]) {
                        atomic_dec(&dev->vblank_refcount[crtc]);
@@ -1125,6 +1119,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe,
                trace_drm_vblank_event_delivered(current->pid, pipe,
                                                 vblwait->request.sequence);
        } else {
+               /* drm_handle_vblank_events will call drm_vblank_put */
                list_add_tail(&e->base.link, &dev->vblank_event_list);
                vblwait->reply.sequence = vblwait->request.sequence;
        }
@@ -1205,8 +1200,12 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
                goto done;
        }
 
-       if (flags & _DRM_VBLANK_EVENT)
+       if (flags & _DRM_VBLANK_EVENT) {
+               /* must hold on to the vblank ref until the event fires
+                * drm_vblank_put will be called asynchronously
+                */
                return drm_queue_vblank_event(dev, crtc, vblwait, file_priv);
+       }
 
        if ((flags & _DRM_VBLANK_NEXTONMISS) &&
            (seq - vblwait->request.sequence) <= (1<<23)) {
index d14b44e..4f40f1c 100644 (file)
@@ -1506,7 +1506,10 @@ drm_add_fake_info_node(struct drm_minor *minor,
        node->minor = minor;
        node->dent = ent;
        node->info_ent = (void *) key;
-       list_add(&node->list, &minor->debugfs_nodes.list);
+
+       mutex_lock(&minor->debugfs_lock);
+       list_add(&node->list, &minor->debugfs_list);
+       mutex_unlock(&minor->debugfs_lock);
 
        return 0;
 }
index cc531bb..e9c2cfe 100644 (file)
@@ -789,8 +789,8 @@ static struct vm_operations_struct i915_gem_vm_ops = {
 };
 
 static struct drm_driver driver = {
-       /* don't use mtrr's here, the Xserver or user space app should
-        * deal with them for intel hardware.
+       /* Don't use MTRRs here; the Xserver or userspace app should
+        * deal with them for Intel hardware.
         */
        .driver_features =
            DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | /* DRIVER_USE_MTRR |*/
index 6651c36..d18b07a 100644 (file)
@@ -1396,7 +1396,7 @@ i915_gem_mmap_gtt(struct drm_file *file,
 
        if (obj->base.size > dev_priv->mm.gtt_mappable_end) {
                ret = -E2BIG;
-               goto unlock;
+               goto out;
        }
 
        if (obj->madv != I915_MADV_WILLNEED) {
index 032a820..5fc201b 100644 (file)
@@ -640,10 +640,9 @@ static int
 nv50_pll_set(struct drm_device *dev, uint32_t reg, uint32_t clk)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       uint32_t reg0 = nv_rd32(dev, reg + 0);
-       uint32_t reg1 = nv_rd32(dev, reg + 4);
        struct nouveau_pll_vals pll;
        struct pll_lims pll_limits;
+       u32 ctrl, mask, coef;
        int ret;
 
        ret = get_pll_limits(dev, reg, &pll_limits);
@@ -654,15 +653,20 @@ nv50_pll_set(struct drm_device *dev, uint32_t reg, uint32_t clk)
        if (!clk)
                return -ERANGE;
 
-       reg0 = (reg0 & 0xfff8ffff) | (pll.log2P << 16);
-       reg1 = (reg1 & 0xffff0000) | (pll.N1 << 8) | pll.M1;
-
-       if (dev_priv->vbios.execute) {
-               still_alive();
-               nv_wr32(dev, reg + 4, reg1);
-               nv_wr32(dev, reg + 0, reg0);
+       coef = pll.N1 << 8 | pll.M1;
+       ctrl = pll.log2P << 16;
+       mask = 0x00070000;
+       if (reg == 0x004008) {
+               mask |= 0x01f80000;
+               ctrl |= (pll_limits.log2p_bias << 19);
+               ctrl |= (pll.log2P << 22);
        }
 
+       if (!dev_priv->vbios.execute)
+               return 0;
+
+       nv_mask(dev, reg + 0, mask, ctrl);
+       nv_wr32(dev, reg + 4, coef);
        return 0;
 }
 
index 7226f41..7cc37e6 100644 (file)
@@ -148,7 +148,7 @@ set_placement_range(struct nouveau_bo *nvbo, uint32_t type)
 
        if (dev_priv->card_type == NV_10 &&
            nvbo->tile_mode && (type & TTM_PL_FLAG_VRAM) &&
-           nvbo->bo.mem.num_pages < vram_pages / 2) {
+           nvbo->bo.mem.num_pages < vram_pages / 4) {
                /*
                 * Make sure that the color and depth buffers are handled
                 * by independent memory controller units. Up to a 9x
index a319d56..bb6ec9e 100644 (file)
@@ -158,6 +158,7 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret,
        INIT_LIST_HEAD(&chan->nvsw.vbl_wait);
        INIT_LIST_HEAD(&chan->nvsw.flip);
        INIT_LIST_HEAD(&chan->fence.pending);
+       spin_lock_init(&chan->fence.lock);
 
        /* setup channel's memory and vm */
        ret = nouveau_gpuobj_channel_init(chan, vram_handle, gart_handle);
index e0d275e..cea6696 100644 (file)
@@ -710,7 +710,7 @@ nouveau_connector_mode_valid(struct drm_connector *connector,
        case OUTPUT_DP:
                max_clock  = nv_encoder->dp.link_nr;
                max_clock *= nv_encoder->dp.link_bw;
-               clock = clock * nouveau_connector_bpp(connector) / 8;
+               clock = clock * nouveau_connector_bpp(connector) / 10;
                break;
        default:
                BUG_ON(1);
index 14a8627..3a4cc32 100644 (file)
@@ -487,6 +487,7 @@ int nouveau_fbcon_init(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_fbdev *nfbdev;
+       int preferred_bpp;
        int ret;
 
        nfbdev = kzalloc(sizeof(struct nouveau_fbdev), GFP_KERNEL);
@@ -505,7 +506,15 @@ int nouveau_fbcon_init(struct drm_device *dev)
        }
 
        drm_fb_helper_single_add_all_connectors(&nfbdev->helper);
-       drm_fb_helper_initial_config(&nfbdev->helper, 32);
+
+       if (dev_priv->vram_size <= 32 * 1024 * 1024)
+               preferred_bpp = 8;
+       else if (dev_priv->vram_size <= 64 * 1024 * 1024)
+               preferred_bpp = 16;
+       else
+               preferred_bpp = 32;
+
+       drm_fb_helper_initial_config(&nfbdev->helper, preferred_bpp);
        return 0;
 }
 
index 81116cf..2f6daae 100644 (file)
@@ -539,8 +539,6 @@ nouveau_fence_channel_init(struct nouveau_channel *chan)
                        return ret;
        }
 
-       INIT_LIST_HEAD(&chan->fence.pending);
-       spin_lock_init(&chan->fence.lock);
        atomic_set(&chan->fence.last_sequence_irq, 0);
        return 0;
 }
index c6143df..d39b220 100644 (file)
@@ -333,7 +333,7 @@ nouveau_i2c_identify(struct drm_device *dev, const char *what,
 
        NV_DEBUG(dev, "Probing %ss on I2C bus: %d\n", what, index);
 
-       for (i = 0; info[i].addr; i++) {
+       for (i = 0; i2c && info[i].addr; i++) {
                if (nouveau_probe_i2c_addr(i2c, info[i].addr) &&
                    (!match || match(i2c, &info[i]))) {
                        NV_INFO(dev, "Detected %s: %s\n", what, info[i].type);
index 9f178aa..33d03fb 100644 (file)
@@ -239,7 +239,7 @@ nouveau_perf_init(struct drm_device *dev)
        if(version == 0x15) {
                memtimings->timing =
                                kcalloc(entries, sizeof(*memtimings->timing), GFP_KERNEL);
-               if(!memtimings) {
+               if (!memtimings->timing) {
                        NV_WARN(dev,"Could not allocate memtiming table\n");
                        return;
                }
index 82478e0..d8831ab 100644 (file)
@@ -579,6 +579,14 @@ nouveau_card_init(struct drm_device *dev)
        if (ret)
                goto out_display_early;
 
+       /* workaround an odd issue on nvc1 by disabling the device's
+        * nosnoop capability.  hopefully won't cause issues until a
+        * better fix is found - assuming there is one...
+        */
+       if (dev_priv->chipset == 0xc1) {
+               nv_mask(dev, 0x00088080, 0x00000800, 0x00000000);
+       }
+
        nouveau_pm_init(dev);
 
        ret = engine->vram.init(dev);
@@ -1102,12 +1110,13 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
        dev_priv->noaccel = !!nouveau_noaccel;
        if (nouveau_noaccel == -1) {
                switch (dev_priv->chipset) {
-               case 0xc1: /* known broken */
-               case 0xc8: /* never tested */
+#if 0
+               case 0xXX: /* known broken */
                        NV_INFO(dev, "acceleration disabled by default, pass "
                                     "noaccel=0 to force enable\n");
                        dev_priv->noaccel = true;
                        break;
+#endif
                default:
                        dev_priv->noaccel = false;
                        break;
index bbc0b9c..e676b0d 100644 (file)
@@ -57,12 +57,14 @@ read_pll_2(struct drm_device *dev, u32 reg)
        int P = (ctrl & 0x00070000) >> 16;
        u32 ref = 27000, clk = 0;
 
-       if (ctrl & 0x80000000)
+       if ((ctrl & 0x80000000) && M1) {
                clk = ref * N1 / M1;
-
-       if (!(ctrl & 0x00000100)) {
-               if (ctrl & 0x40000000)
-                       clk = clk * N2 / M2;
+               if ((ctrl & 0x40000100) == 0x40000000) {
+                       if (M2)
+                               clk = clk * N2 / M2;
+                       else
+                               clk = 0;
+               }
        }
 
        return clk >> P;
@@ -177,6 +179,11 @@ nv40_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl)
        }
 
        /* memory clock */
+       if (!perflvl->memory) {
+               info->mpll_ctrl = 0x00000000;
+               goto out;
+       }
+
        ret = nv40_calc_pll(dev, 0x004020, &pll, perflvl->memory,
                            &N1, &M1, &N2, &M2, &log2P);
        if (ret < 0)
@@ -264,6 +271,9 @@ nv40_pm_clocks_set(struct drm_device *dev, void *pre_state)
        mdelay(5);
        nv_mask(dev, 0x00c040, 0x00000333, info->ctrl);
 
+       if (!info->mpll_ctrl)
+               goto resume;
+
        /* wait for vblank start on active crtcs, disable memory access */
        for (i = 0; i < 2; i++) {
                if (!(crtc_mask & (1 << i)))
index 8c979b3..ac601f7 100644 (file)
@@ -131,8 +131,8 @@ nv50_graph_init(struct drm_device *dev, int engine)
        NV_DEBUG(dev, "\n");
 
        /* master reset */
-       nv_mask(dev, 0x000200, 0x00200100, 0x00000000);
-       nv_mask(dev, 0x000200, 0x00200100, 0x00200100);
+       nv_mask(dev, 0x000200, 0x00201000, 0x00000000);
+       nv_mask(dev, 0x000200, 0x00201000, 0x00201000);
        nv_wr32(dev, 0x40008c, 0x00000004); /* HW_CTX_SWITCH_ENABLED */
 
        /* reset/enable traps and interrupts */
index d05c2c3..4b46d69 100644 (file)
@@ -601,7 +601,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
                                        gr_def(ctx, offset + 0x1c, 0x00880000);
                                        break;
                                case 0x86:
-                                       gr_def(ctx, offset + 0x1c, 0x008c0000);
+                                       gr_def(ctx, offset + 0x1c, 0x018c0000);
                                        break;
                                case 0x92:
                                case 0x96:
index 9da2383..2e45e57 100644 (file)
@@ -160,7 +160,7 @@ nv50_vram_rblock(struct drm_device *dev)
        colbits  =  (r4 & 0x0000f000) >> 12;
        rowbitsa = ((r4 & 0x000f0000) >> 16) + 8;
        rowbitsb = ((r4 & 0x00f00000) >> 20) + 8;
-       banks    = ((r4 & 0x01000000) ? 8 : 4);
+       banks    = 1 << (((r4 & 0x03000000) >> 24) + 2);
 
        rowsize = parts * banks * (1 << colbits) * 8;
        predicted = rowsize << rowbitsa;
index bbdbc51..a74e501 100644 (file)
@@ -157,8 +157,8 @@ nvc0_graph_create_context_mmio_list(struct nouveau_channel *chan)
        struct nvc0_graph_priv *priv = nv_engine(chan->dev, NVOBJ_ENGINE_GR);
        struct nvc0_graph_chan *grch = chan->engctx[NVOBJ_ENGINE_GR];
        struct drm_device *dev = chan->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
        int i = 0, gpc, tp, ret;
-       u32 magic;
 
        ret = nouveau_gpuobj_new(dev, chan, 0x2000, 256, NVOBJ_FLAG_VM,
                                 &grch->unk408004);
@@ -207,14 +207,37 @@ nvc0_graph_create_context_mmio_list(struct nouveau_channel *chan)
        nv_wo32(grch->mmio, i++ * 4, 0x0041880c);
        nv_wo32(grch->mmio, i++ * 4, 0x80000018);
 
-       magic = 0x02180000;
-       nv_wo32(grch->mmio, i++ * 4, 0x00405830);
-       nv_wo32(grch->mmio, i++ * 4, magic);
-       for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-               for (tp = 0; tp < priv->tp_nr[gpc]; tp++, magic += 0x0324) {
-                       u32 reg = 0x504520 + (gpc * 0x8000) + (tp * 0x0800);
-                       nv_wo32(grch->mmio, i++ * 4, reg);
-                       nv_wo32(grch->mmio, i++ * 4, magic);
+       if (dev_priv->chipset != 0xc1) {
+               u32 magic = 0x02180000;
+               nv_wo32(grch->mmio, i++ * 4, 0x00405830);
+               nv_wo32(grch->mmio, i++ * 4, magic);
+               for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+                       for (tp = 0; tp < priv->tp_nr[gpc]; tp++) {
+                               u32 reg = TP_UNIT(gpc, tp, 0x520);
+                               nv_wo32(grch->mmio, i++ * 4, reg);
+                               nv_wo32(grch->mmio, i++ * 4, magic);
+                               magic += 0x0324;
+                       }
+               }
+       } else {
+               u32 magic = 0x02180000;
+               nv_wo32(grch->mmio, i++ * 4, 0x00405830);
+               nv_wo32(grch->mmio, i++ * 4, magic | 0x0000218);
+               nv_wo32(grch->mmio, i++ * 4, 0x004064c4);
+               nv_wo32(grch->mmio, i++ * 4, 0x0086ffff);
+               for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+                       for (tp = 0; tp < priv->tp_nr[gpc]; tp++) {
+                               u32 reg = TP_UNIT(gpc, tp, 0x520);
+                               nv_wo32(grch->mmio, i++ * 4, reg);
+                               nv_wo32(grch->mmio, i++ * 4, (1 << 28) | magic);
+                               magic += 0x0324;
+                       }
+                       for (tp = 0; tp < priv->tp_nr[gpc]; tp++) {
+                               u32 reg = TP_UNIT(gpc, tp, 0x544);
+                               nv_wo32(grch->mmio, i++ * 4, reg);
+                               nv_wo32(grch->mmio, i++ * 4, magic);
+                               magic += 0x0324;
+                       }
                }
        }
 
index dd0e6a7..96b0b93 100644 (file)
@@ -1812,6 +1812,7 @@ nvc0_grctx_generate(struct nouveau_channel *chan)
                /* calculate first set of magics */
                memcpy(tpnr, priv->tp_nr, sizeof(priv->tp_nr));
 
+               gpc = -1;
                for (tp = 0; tp < priv->tp_total; tp++) {
                        do {
                                gpc = (gpc + 1) % priv->gpc_nr;
@@ -1861,30 +1862,26 @@ nvc0_grctx_generate(struct nouveau_channel *chan)
 
        if (1) {
                u32 tp_mask = 0, tp_set = 0;
-               u8  tpnr[GPC_MAX];
+               u8  tpnr[GPC_MAX], a, b;
 
                memcpy(tpnr, priv->tp_nr, sizeof(priv->tp_nr));
                for (gpc = 0; gpc < priv->gpc_nr; gpc++)
                        tp_mask |= ((1 << priv->tp_nr[gpc]) - 1) << (gpc * 8);
 
-               gpc = -1;
-               for (i = 0, gpc = -1; i < 32; i++) {
-                       int ltp = i * (priv->tp_total - 1) / 32;
-
-                       do {
-                               gpc = (gpc + 1) % priv->gpc_nr;
-                       } while (!tpnr[gpc]);
-                       tp = priv->tp_nr[gpc] - tpnr[gpc]--;
+               for (i = 0, gpc = -1, b = -1; i < 32; i++) {
+                       a = (i * (priv->tp_total - 1)) / 32;
+                       if (a != b) {
+                               b = a;
+                               do {
+                                       gpc = (gpc + 1) % priv->gpc_nr;
+                               } while (!tpnr[gpc]);
+                               tp = priv->tp_nr[gpc] - tpnr[gpc]--;
 
-                       tp_set |= 1 << ((gpc * 8) + tp);
+                               tp_set |= 1 << ((gpc * 8) + tp);
+                       }
 
-                       do {
-                               nv_wr32(dev, 0x406800 + (i * 0x20), tp_set);
-                               tp_set ^= tp_mask;
-                               nv_wr32(dev, 0x406c00 + (i * 0x20), tp_set);
-                               tp_set ^= tp_mask;
-                       } while (ltp == (++i * (priv->tp_total - 1) / 32));
-                       i--;
+                       nv_wr32(dev, 0x406800 + (i * 0x20), tp_set);
+                       nv_wr32(dev, 0x406c00 + (i * 0x20), tp_set ^ tp_mask);
                }
        }
 
index edbfe93..ce984d5 100644 (file)
@@ -43,7 +43,7 @@ static const u8 types[256] = {
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 3, 3, 3, 3, 1, 1, 1, 1, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,
-       3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3,
+       3, 3, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3,
        3, 3, 0, 0, 0, 0, 0, 0, 3, 0, 0, 3, 0, 3, 0, 3,
        3, 0, 3, 3, 3, 3, 3, 0, 0, 3, 0, 3, 0, 3, 3, 0,
        3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 1, 1, 0
@@ -110,22 +110,26 @@ nvc0_vram_init(struct drm_device *dev)
        u32 bsize = nv_rd32(dev, 0x10f20c);
        u32 offset, length;
        bool uniform = true;
-       int ret, i;
+       int ret, part;
 
        NV_DEBUG(dev, "0x100800: 0x%08x\n", nv_rd32(dev, 0x100800));
        NV_DEBUG(dev, "parts 0x%08x bcast_mem_amount 0x%08x\n", parts, bsize);
 
        /* read amount of vram attached to each memory controller */
-       for (i = 0; i < parts; i++) {
-               u32 psize = nv_rd32(dev, 0x11020c + (i * 0x1000));
+       part = 0;
+       while (parts) {
+               u32 psize = nv_rd32(dev, 0x11020c + (part++ * 0x1000));
+               if (psize == 0)
+                       continue;
+               parts--;
+
                if (psize != bsize) {
                        if (psize < bsize)
                                bsize = psize;
                        uniform = false;
                }
 
-               NV_DEBUG(dev, "%d: mem_amount 0x%08x\n", i, psize);
-
+               NV_DEBUG(dev, "%d: mem_amount 0x%08x\n", part, psize);
                dev_priv->vram_size += (u64)psize << 20;
        }
 
index 87921c8..87631fe 100644 (file)
@@ -1522,12 +1522,6 @@ static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc,
                                     struct drm_display_mode *mode,
                                     struct drm_display_mode *adjusted_mode)
 {
-       struct drm_device *dev = crtc->dev;
-       struct radeon_device *rdev = dev->dev_private;
-
-       /* adjust pm to upcoming mode change */
-       radeon_pm_compute_clocks(rdev);
-
        if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode))
                return false;
        return true;
index a0de485..6fb335a 100644 (file)
@@ -283,7 +283,7 @@ int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
                }
        }
 
-       DRM_ERROR("aux i2c too many retries, giving up\n");
+       DRM_DEBUG_KMS("aux i2c too many retries, giving up\n");
        return -EREMOTEIO;
 }
 
index e4c384b..1d603a3 100644 (file)
@@ -157,6 +157,57 @@ int sumo_get_temp(struct radeon_device *rdev)
        return actual_temp * 1000;
 }
 
+void sumo_pm_init_profile(struct radeon_device *rdev)
+{
+       int idx;
+
+       /* default */
+       rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index;
+       rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index;
+       rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0;
+       rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 0;
+
+       /* low,mid sh/mh */
+       if (rdev->flags & RADEON_IS_MOBILITY)
+               idx = radeon_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0);
+       else
+               idx = radeon_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0);
+
+       rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = idx;
+       rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = idx;
+       rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0;
+       rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0;
+
+       rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = idx;
+       rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = idx;
+       rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0;
+       rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0;
+
+       rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_ps_idx = idx;
+       rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx = idx;
+       rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_cm_idx = 0;
+       rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_cm_idx = 0;
+
+       rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_ps_idx = idx;
+       rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx = idx;
+       rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_cm_idx = 0;
+       rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_cm_idx = 0;
+
+       /* high sh/mh */
+       idx = radeon_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0);
+       rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = idx;
+       rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = idx;
+       rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0;
+       rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx =
+               rdev->pm.power_state[idx].num_clock_modes - 1;
+
+       rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = idx;
+       rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = idx;
+       rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0;
+       rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx =
+               rdev->pm.power_state[idx].num_clock_modes - 1;
+}
+
 void evergreen_pm_misc(struct radeon_device *rdev)
 {
        int req_ps_idx = rdev->pm.requested_power_state_index;
@@ -1219,7 +1270,7 @@ void evergreen_mc_program(struct radeon_device *rdev)
                WREG32(MC_VM_SYSTEM_APERTURE_HIGH_ADDR,
                        rdev->mc.vram_end >> 12);
        }
-       WREG32(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, 0);
+       WREG32(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, rdev->vram_scratch.gpu_addr >> 12);
        if (rdev->flags & RADEON_IS_IGP) {
                tmp = RREG32(MC_FUS_VM_FB_OFFSET) & 0x000FFFFF;
                tmp |= ((rdev->mc.vram_end >> 20) & 0xF) << 24;
index 19afc43..9cdda0b 100644 (file)
@@ -288,24 +288,6 @@ void r600_pm_get_dynpm_state(struct radeon_device *rdev)
                  pcie_lanes);
 }
 
-static int r600_pm_get_type_index(struct radeon_device *rdev,
-                                 enum radeon_pm_state_type ps_type,
-                                 int instance)
-{
-       int i;
-       int found_instance = -1;
-
-       for (i = 0; i < rdev->pm.num_power_states; i++) {
-               if (rdev->pm.power_state[i].type == ps_type) {
-                       found_instance++;
-                       if (found_instance == instance)
-                               return i;
-               }
-       }
-       /* return default if no match */
-       return rdev->pm.default_power_state_index;
-}
-
 void rs780_pm_init_profile(struct radeon_device *rdev)
 {
        if (rdev->pm.num_power_states == 2) {
@@ -421,6 +403,8 @@ void rs780_pm_init_profile(struct radeon_device *rdev)
 
 void r600_pm_init_profile(struct radeon_device *rdev)
 {
+       int idx;
+
        if (rdev->family == CHIP_R600) {
                /* XXX */
                /* default */
@@ -502,81 +486,43 @@ void r600_pm_init_profile(struct radeon_device *rdev)
                        rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0;
                        rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 2;
                        /* low sh */
-                       if (rdev->flags & RADEON_IS_MOBILITY) {
-                               rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx =
-                                       r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0);
-                               rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx =
-                                       r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0);
-                               rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0;
-                               rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0;
-                       } else {
-                               rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx =
-                                       r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0);
-                               rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx =
-                                       r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0);
-                               rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0;
-                               rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0;
-                       }
+                       if (rdev->flags & RADEON_IS_MOBILITY)
+                               idx = radeon_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0);
+                       else
+                               idx = radeon_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0);
+                       rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = idx;
+                       rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = idx;
+                       rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0;
+                       rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0;
                        /* mid sh */
-                       if (rdev->flags & RADEON_IS_MOBILITY) {
-                               rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_ps_idx =
-                                       r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0);
-                               rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx =
-                                       r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0);
-                               rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_cm_idx = 0;
-                               rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_cm_idx = 1;
-                       } else {
-                               rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_ps_idx =
-                                       r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0);
-                               rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx =
-                                       r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0);
-                               rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_cm_idx = 0;
-                               rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_cm_idx = 1;
-                       }
+                       rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_ps_idx = idx;
+                       rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx = idx;
+                       rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_cm_idx = 0;
+                       rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_cm_idx = 1;
                        /* high sh */
-                       rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx =
-                               r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0);
-                       rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx =
-                               r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0);
+                       idx = radeon_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0);
+                       rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = idx;
+                       rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = idx;
                        rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0;
                        rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 2;
                        /* low mh */
-                       if (rdev->flags & RADEON_IS_MOBILITY) {
-                               rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx =
-                                       r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 1);
-                               rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx =
-                                       r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 1);
-                               rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0;
-                               rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0;
-                       } else {
-                               rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx =
-                                       r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1);
-                               rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx =
-                                       r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1);
-                               rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0;
-                               rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0;
-                       }
+                       if (rdev->flags & RADEON_IS_MOBILITY)
+                               idx = radeon_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 1);
+                       else
+                               idx = radeon_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1);
+                       rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = idx;
+                       rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = idx;
+                       rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0;
+                       rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0;
                        /* mid mh */
-                       if (rdev->flags & RADEON_IS_MOBILITY) {
-                               rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_ps_idx =
-                                       r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 1);
-                               rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx =
-                                       r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 1);
-                               rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_cm_idx = 0;
-                               rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_cm_idx = 1;
-                       } else {
-                               rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_ps_idx =
-                                       r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1);
-                               rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx =
-                                       r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1);
-                               rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_cm_idx = 0;
-                               rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_cm_idx = 1;
-                       }
+                       rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_ps_idx = idx;
+                       rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx = idx;
+                       rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_cm_idx = 0;
+                       rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_cm_idx = 1;
                        /* high mh */
-                       rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx =
-                               r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1);
-                       rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx =
-                               r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1);
+                       idx = radeon_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1);
+                       rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = idx;
+                       rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = idx;
                        rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0;
                        rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 2;
                }
index b316b30..fc5a1d6 100644 (file)
@@ -784,8 +784,7 @@ struct radeon_pm_clock_info {
 
 struct radeon_power_state {
        enum radeon_pm_state_type type;
-       /* XXX: use a define for num clock modes */
-       struct radeon_pm_clock_info clock_info[8];
+       struct radeon_pm_clock_info *clock_info;
        /* number of valid clock modes in this power state */
        int num_clock_modes;
        struct radeon_pm_clock_info *default_clock_mode;
@@ -855,6 +854,9 @@ struct radeon_pm {
        struct device           *int_hwmon_dev;
 };
 
+int radeon_pm_get_type_index(struct radeon_device *rdev,
+                            enum radeon_pm_state_type ps_type,
+                            int instance);
 
 /*
  * Benchmarking
@@ -1142,6 +1144,48 @@ struct r600_vram_scratch {
        u64                             gpu_addr;
 };
 
+
+/*
+ * Mutex which allows recursive locking from the same process.
+ */
+struct radeon_mutex {
+       struct mutex            mutex;
+       struct task_struct      *owner;
+       int                     level;
+};
+
+static inline void radeon_mutex_init(struct radeon_mutex *mutex)
+{
+       mutex_init(&mutex->mutex);
+       mutex->owner = NULL;
+       mutex->level = 0;
+}
+
+static inline void radeon_mutex_lock(struct radeon_mutex *mutex)
+{
+       if (mutex_trylock(&mutex->mutex)) {
+               /* The mutex was unlocked before, so it's ours now */
+               mutex->owner = current;
+       } else if (mutex->owner != current) {
+               /* Another process locked the mutex, take it */
+               mutex_lock(&mutex->mutex);
+               mutex->owner = current;
+       }
+       /* Otherwise the mutex was already locked by this process */
+
+       mutex->level++;
+}
+
+static inline void radeon_mutex_unlock(struct radeon_mutex *mutex)
+{
+       if (--mutex->level > 0)
+               return;
+
+       mutex->owner = NULL;
+       mutex_unlock(&mutex->mutex);
+}
+
+
 /*
  * Core structure, functions and helpers.
  */
@@ -1197,7 +1241,7 @@ struct radeon_device {
        struct radeon_gem               gem;
        struct radeon_pm                pm;
        uint32_t                        bios_scratch[RADEON_BIOS_NUM_SCRATCH];
-       struct mutex                    cs_mutex;
+       struct radeon_mutex             cs_mutex;
        struct radeon_wb                wb;
        struct radeon_dummy_page        dummy_page;
        bool                            gpu_lockup;
index e294456..a2e1eae 100644 (file)
@@ -834,7 +834,7 @@ static struct radeon_asic sumo_asic = {
        .pm_misc = &evergreen_pm_misc,
        .pm_prepare = &evergreen_pm_prepare,
        .pm_finish = &evergreen_pm_finish,
-       .pm_init_profile = &rs780_pm_init_profile,
+       .pm_init_profile = &sumo_pm_init_profile,
        .pm_get_dynpm_state = &r600_pm_get_dynpm_state,
        .pre_page_flip = &evergreen_pre_page_flip,
        .page_flip = &evergreen_page_flip,
index 85f14f0..5991484 100644 (file)
@@ -413,6 +413,7 @@ extern int evergreen_cs_parse(struct radeon_cs_parser *p);
 extern void evergreen_pm_misc(struct radeon_device *rdev);
 extern void evergreen_pm_prepare(struct radeon_device *rdev);
 extern void evergreen_pm_finish(struct radeon_device *rdev);
+extern void sumo_pm_init_profile(struct radeon_device *rdev);
 extern void evergreen_pre_page_flip(struct radeon_device *rdev, int crtc);
 extern u32 evergreen_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base);
 extern void evergreen_post_page_flip(struct radeon_device *rdev, int crtc);
index 08d0b94..fecd705 100644 (file)
@@ -85,6 +85,18 @@ static struct radeon_i2c_bus_rec radeon_lookup_i2c_gpio(struct radeon_device *rd
                for (i = 0; i < num_indices; i++) {
                        gpio = &i2c_info->asGPIO_Info[i];
 
+                       /* r4xx mask is technically not used by the hw, so patch in the legacy mask bits */
+                       if ((rdev->family == CHIP_R420) ||
+                           (rdev->family == CHIP_R423) ||
+                           (rdev->family == CHIP_RV410)) {
+                               if ((le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x0018) ||
+                                   (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x0019) ||
+                                   (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x001a)) {
+                                       gpio->ucClkMaskShift = 0x19;
+                                       gpio->ucDataMaskShift = 0x18;
+                               }
+                       }
+
                        /* some evergreen boards have bad data for this entry */
                        if (ASIC_IS_DCE4(rdev)) {
                                if ((i == 7) &&
@@ -1996,10 +2008,14 @@ static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev)
                return state_index;
        /* last mode is usually default, array is low to high */
        for (i = 0; i < num_modes; i++) {
+               rdev->pm.power_state[state_index].clock_info =
+                       kzalloc(sizeof(struct radeon_pm_clock_info) * 1, GFP_KERNEL);
+               if (!rdev->pm.power_state[state_index].clock_info)
+                       return state_index;
+               rdev->pm.power_state[state_index].num_clock_modes = 1;
                rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE;
                switch (frev) {
                case 1:
-                       rdev->pm.power_state[state_index].num_clock_modes = 1;
                        rdev->pm.power_state[state_index].clock_info[0].mclk =
                                le16_to_cpu(power_info->info.asPowerPlayInfo[i].usMemoryClock);
                        rdev->pm.power_state[state_index].clock_info[0].sclk =
@@ -2035,7 +2051,6 @@ static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev)
                        state_index++;
                        break;
                case 2:
-                       rdev->pm.power_state[state_index].num_clock_modes = 1;
                        rdev->pm.power_state[state_index].clock_info[0].mclk =
                                le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMemoryClock);
                        rdev->pm.power_state[state_index].clock_info[0].sclk =
@@ -2072,7 +2087,6 @@ static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev)
                        state_index++;
                        break;
                case 3:
-                       rdev->pm.power_state[state_index].num_clock_modes = 1;
                        rdev->pm.power_state[state_index].clock_info[0].mclk =
                                le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMemoryClock);
                        rdev->pm.power_state[state_index].clock_info[0].sclk =
@@ -2257,7 +2271,7 @@ static void radeon_atombios_parse_pplib_non_clock_info(struct radeon_device *rde
                rdev->pm.default_power_state_index = state_index;
                rdev->pm.power_state[state_index].default_clock_mode =
                        &rdev->pm.power_state[state_index].clock_info[mode_index - 1];
-               if (ASIC_IS_DCE5(rdev)) {
+               if (ASIC_IS_DCE5(rdev) && !(rdev->flags & RADEON_IS_IGP)) {
                        /* NI chips post without MC ucode, so default clocks are strobe mode only */
                        rdev->pm.default_sclk = rdev->pm.power_state[state_index].clock_info[0].sclk;
                        rdev->pm.default_mclk = rdev->pm.power_state[state_index].clock_info[0].mclk;
@@ -2377,17 +2391,31 @@ static int radeon_atombios_parse_power_table_4_5(struct radeon_device *rdev)
                         le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) +
                         (power_state->v1.ucNonClockStateIndex *
                          power_info->pplib.ucNonClockSize));
-               for (j = 0; j < (power_info->pplib.ucStateEntrySize - 1); j++) {
-                       clock_info = (union pplib_clock_info *)
-                               (mode_info->atom_context->bios + data_offset +
-                                le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) +
-                                (power_state->v1.ucClockStateIndices[j] *
-                                 power_info->pplib.ucClockInfoSize));
-                       valid = radeon_atombios_parse_pplib_clock_info(rdev,
-                                                                      state_index, mode_index,
-                                                                      clock_info);
-                       if (valid)
-                               mode_index++;
+               rdev->pm.power_state[i].clock_info = kzalloc(sizeof(struct radeon_pm_clock_info) *
+                                                            ((power_info->pplib.ucStateEntrySize - 1) ?
+                                                             (power_info->pplib.ucStateEntrySize - 1) : 1),
+                                                            GFP_KERNEL);
+               if (!rdev->pm.power_state[i].clock_info)
+                       return state_index;
+               if (power_info->pplib.ucStateEntrySize - 1) {
+                       for (j = 0; j < (power_info->pplib.ucStateEntrySize - 1); j++) {
+                               clock_info = (union pplib_clock_info *)
+                                       (mode_info->atom_context->bios + data_offset +
+                                        le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) +
+                                        (power_state->v1.ucClockStateIndices[j] *
+                                         power_info->pplib.ucClockInfoSize));
+                               valid = radeon_atombios_parse_pplib_clock_info(rdev,
+                                                                              state_index, mode_index,
+                                                                              clock_info);
+                               if (valid)
+                                       mode_index++;
+                       }
+               } else {
+                       rdev->pm.power_state[state_index].clock_info[0].mclk =
+                               rdev->clock.default_mclk;
+                       rdev->pm.power_state[state_index].clock_info[0].sclk =
+                               rdev->clock.default_sclk;
+                       mode_index++;
                }
                rdev->pm.power_state[state_index].num_clock_modes = mode_index;
                if (mode_index) {
@@ -2456,18 +2484,32 @@ static int radeon_atombios_parse_power_table_6(struct radeon_device *rdev)
                non_clock_array_index = i; /* power_state->v2.nonClockInfoIndex */
                non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
                        &non_clock_info_array->nonClockInfo[non_clock_array_index];
-               for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) {
-                       clock_array_index = power_state->v2.clockInfoIndex[j];
-                       /* XXX this might be an inagua bug... */
-                       if (clock_array_index >= clock_info_array->ucNumEntries)
-                               continue;
-                       clock_info = (union pplib_clock_info *)
-                               &clock_info_array->clockInfo[clock_array_index];
-                       valid = radeon_atombios_parse_pplib_clock_info(rdev,
-                                                                      state_index, mode_index,
-                                                                      clock_info);
-                       if (valid)
-                               mode_index++;
+               rdev->pm.power_state[i].clock_info = kzalloc(sizeof(struct radeon_pm_clock_info) *
+                                                            (power_state->v2.ucNumDPMLevels ?
+                                                             power_state->v2.ucNumDPMLevels : 1),
+                                                            GFP_KERNEL);
+               if (!rdev->pm.power_state[i].clock_info)
+                       return state_index;
+               if (power_state->v2.ucNumDPMLevels) {
+                       for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) {
+                               clock_array_index = power_state->v2.clockInfoIndex[j];
+                               /* XXX this might be an inagua bug... */
+                               if (clock_array_index >= clock_info_array->ucNumEntries)
+                                       continue;
+                               clock_info = (union pplib_clock_info *)
+                                       &clock_info_array->clockInfo[clock_array_index];
+                               valid = radeon_atombios_parse_pplib_clock_info(rdev,
+                                                                              state_index, mode_index,
+                                                                              clock_info);
+                               if (valid)
+                                       mode_index++;
+                       }
+               } else {
+                       rdev->pm.power_state[state_index].clock_info[0].mclk =
+                               rdev->clock.default_mclk;
+                       rdev->pm.power_state[state_index].clock_info[0].sclk =
+                               rdev->clock.default_sclk;
+                       mode_index++;
                }
                rdev->pm.power_state[state_index].num_clock_modes = mode_index;
                if (mode_index) {
@@ -2524,19 +2566,23 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
        } else {
                rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state), GFP_KERNEL);
                if (rdev->pm.power_state) {
-                       /* add the default mode */
-                       rdev->pm.power_state[state_index].type =
-                               POWER_STATE_TYPE_DEFAULT;
-                       rdev->pm.power_state[state_index].num_clock_modes = 1;
-                       rdev->pm.power_state[state_index].clock_info[0].mclk = rdev->clock.default_mclk;
-                       rdev->pm.power_state[state_index].clock_info[0].sclk = rdev->clock.default_sclk;
-                       rdev->pm.power_state[state_index].default_clock_mode =
-                               &rdev->pm.power_state[state_index].clock_info[0];
-                       rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE;
-                       rdev->pm.power_state[state_index].pcie_lanes = 16;
-                       rdev->pm.default_power_state_index = state_index;
-                       rdev->pm.power_state[state_index].flags = 0;
-                       state_index++;
+                       rdev->pm.power_state[0].clock_info =
+                               kzalloc(sizeof(struct radeon_pm_clock_info) * 1, GFP_KERNEL);
+                       if (rdev->pm.power_state[0].clock_info) {
+                               /* add the default mode */
+                               rdev->pm.power_state[state_index].type =
+                                       POWER_STATE_TYPE_DEFAULT;
+                               rdev->pm.power_state[state_index].num_clock_modes = 1;
+                               rdev->pm.power_state[state_index].clock_info[0].mclk = rdev->clock.default_mclk;
+                               rdev->pm.power_state[state_index].clock_info[0].sclk = rdev->clock.default_sclk;
+                               rdev->pm.power_state[state_index].default_clock_mode =
+                                       &rdev->pm.power_state[state_index].clock_info[0];
+                               rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE;
+                               rdev->pm.power_state[state_index].pcie_lanes = 16;
+                               rdev->pm.default_power_state_index = state_index;
+                               rdev->pm.power_state[state_index].flags = 0;
+                               state_index++;
+                       }
                }
        }
 
index 5cafc90..17e1a9b 100644 (file)
@@ -98,7 +98,7 @@ static void radeon_benchmark_move(struct radeon_device *rdev, unsigned size,
        struct radeon_bo *sobj = NULL;
        uint64_t saddr, daddr;
        int r, n;
-       unsigned int time;
+       int time;
 
        n = RADEON_BENCHMARK_ITERATIONS;
        r = radeon_bo_create(rdev, size, PAGE_SIZE, true, sdomain, &sobj);
index 8bf83c4..81fc100 100644 (file)
@@ -2563,14 +2563,17 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev)
 
        /* allocate 2 power states */
        rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) * 2, GFP_KERNEL);
-       if (!rdev->pm.power_state) {
-               rdev->pm.default_power_state_index = state_index;
-               rdev->pm.num_power_states = 0;
-
-               rdev->pm.current_power_state_index = rdev->pm.default_power_state_index;
-               rdev->pm.current_clock_mode_index = 0;
-               return;
-       }
+       if (rdev->pm.power_state) {
+               /* allocate 1 clock mode per state */
+               rdev->pm.power_state[0].clock_info =
+                       kzalloc(sizeof(struct radeon_pm_clock_info) * 1, GFP_KERNEL);
+               rdev->pm.power_state[1].clock_info =
+                       kzalloc(sizeof(struct radeon_pm_clock_info) * 1, GFP_KERNEL);
+               if (!rdev->pm.power_state[0].clock_info ||
+                   !rdev->pm.power_state[1].clock_info)
+                       goto pm_failed;
+       } else
+               goto pm_failed;
 
        /* check for a thermal chip */
        offset = combios_get_table_offset(dev, COMBIOS_OVERDRIVE_INFO_TABLE);
@@ -2735,6 +2738,14 @@ default_mode:
 
        rdev->pm.current_power_state_index = rdev->pm.default_power_state_index;
        rdev->pm.current_clock_mode_index = 0;
+       return;
+
+pm_failed:
+       rdev->pm.default_power_state_index = state_index;
+       rdev->pm.num_power_states = 0;
+
+       rdev->pm.current_power_state_index = rdev->pm.default_power_state_index;
+       rdev->pm.current_clock_mode_index = 0;
 }
 
 void radeon_external_tmds_setup(struct drm_encoder *encoder)
index fae00c0..ccaa243 100644 (file)
@@ -222,7 +222,7 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
        struct radeon_cs_chunk *ib_chunk;
        int r;
 
-       mutex_lock(&rdev->cs_mutex);
+       radeon_mutex_lock(&rdev->cs_mutex);
        /* initialize parser */
        memset(&parser, 0, sizeof(struct radeon_cs_parser));
        parser.filp = filp;
@@ -233,14 +233,14 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
        if (r) {
                DRM_ERROR("Failed to initialize parser !\n");
                radeon_cs_parser_fini(&parser, r);
-               mutex_unlock(&rdev->cs_mutex);
+               radeon_mutex_unlock(&rdev->cs_mutex);
                return r;
        }
        r =  radeon_ib_get(rdev, &parser.ib);
        if (r) {
                DRM_ERROR("Failed to get ib !\n");
                radeon_cs_parser_fini(&parser, r);
-               mutex_unlock(&rdev->cs_mutex);
+               radeon_mutex_unlock(&rdev->cs_mutex);
                return r;
        }
        r = radeon_cs_parser_relocs(&parser);
@@ -248,7 +248,7 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
                if (r != -ERESTARTSYS)
                        DRM_ERROR("Failed to parse relocation %d!\n", r);
                radeon_cs_parser_fini(&parser, r);
-               mutex_unlock(&rdev->cs_mutex);
+               radeon_mutex_unlock(&rdev->cs_mutex);
                return r;
        }
        /* Copy the packet into the IB, the parser will read from the
@@ -260,14 +260,14 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
        if (r || parser.parser_error) {
                DRM_ERROR("Invalid command stream !\n");
                radeon_cs_parser_fini(&parser, r);
-               mutex_unlock(&rdev->cs_mutex);
+               radeon_mutex_unlock(&rdev->cs_mutex);
                return r;
        }
        r = radeon_cs_finish_pages(&parser);
        if (r) {
                DRM_ERROR("Invalid command stream !\n");
                radeon_cs_parser_fini(&parser, r);
-               mutex_unlock(&rdev->cs_mutex);
+               radeon_mutex_unlock(&rdev->cs_mutex);
                return r;
        }
        r = radeon_ib_schedule(rdev, parser.ib);
@@ -275,7 +275,7 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
                DRM_ERROR("Failed to schedule IB !\n");
        }
        radeon_cs_parser_fini(&parser, r);
-       mutex_unlock(&rdev->cs_mutex);
+       radeon_mutex_unlock(&rdev->cs_mutex);
        return r;
 }
 
index c33bc91..c4d00a1 100644 (file)
@@ -716,7 +716,7 @@ int radeon_device_init(struct radeon_device *rdev,
 
        /* mutex initialization are all done here so we
         * can recall function without having locking issues */
-       mutex_init(&rdev->cs_mutex);
+       radeon_mutex_init(&rdev->cs_mutex);
        mutex_init(&rdev->ib_pool.mutex);
        mutex_init(&rdev->cp.mutex);
        mutex_init(&rdev->dc_hw_i2c_mutex);
@@ -955,6 +955,9 @@ int radeon_gpu_reset(struct radeon_device *rdev)
        int r;
        int resched;
 
+       /* Prevent CS ioctl from interfering */
+       radeon_mutex_lock(&rdev->cs_mutex);
+
        radeon_save_bios_scratch_regs(rdev);
        /* block TTM */
        resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev);
@@ -967,10 +970,15 @@ int radeon_gpu_reset(struct radeon_device *rdev)
                radeon_restore_bios_scratch_regs(rdev);
                drm_helper_resume_force_mode(rdev->ddev);
                ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched);
-               return 0;
        }
-       /* bad news, how to tell it to userspace ? */
-       dev_info(rdev->dev, "GPU reset failed\n");
+
+       radeon_mutex_unlock(&rdev->cs_mutex);
+
+       if (r) {
+               /* bad news, how to tell it to userspace ? */
+               dev_info(rdev->dev, "GPU reset failed\n");
+       }
+
        return r;
 }
 
index 41a5d48..daadf21 100644 (file)
@@ -991,12 +991,6 @@ static bool radeon_crtc_mode_fixup(struct drm_crtc *crtc,
                                   struct drm_display_mode *mode,
                                   struct drm_display_mode *adjusted_mode)
 {
-       struct drm_device *dev = crtc->dev;
-       struct radeon_device *rdev = dev->dev_private;
-
-       /* adjust pm to upcoming mode change */
-       radeon_pm_compute_clocks(rdev);
-
        if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode))
                return false;
        return true;
index 6fabe89..78a665b 100644 (file)
@@ -53,6 +53,24 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev);
 
 #define ACPI_AC_CLASS           "ac_adapter"
 
+int radeon_pm_get_type_index(struct radeon_device *rdev,
+                            enum radeon_pm_state_type ps_type,
+                            int instance)
+{
+       int i;
+       int found_instance = -1;
+
+       for (i = 0; i < rdev->pm.num_power_states; i++) {
+               if (rdev->pm.power_state[i].type == ps_type) {
+                       found_instance++;
+                       if (found_instance == instance)
+                               return i;
+               }
+       }
+       /* return default if no match */
+       return rdev->pm.default_power_state_index;
+}
+
 #ifdef CONFIG_ACPI
 static int radeon_acpi_event(struct notifier_block *nb,
                             unsigned long val,
index 03daefa..880e285 100644 (file)
@@ -105,6 +105,10 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
        struct vmw_dma_buffer *dmabuf = NULL;
        int ret;
 
+       /* A lot of the code assumes this */
+       if (handle && (width != 64 || height != 64))
+               return -EINVAL;
+
        if (handle) {
                ret = vmw_user_surface_lookup_handle(dev_priv, tfile,
                                                     handle, &surface);
@@ -410,8 +414,9 @@ static int do_surface_dirty_sou(struct vmw_private *dev_priv,
        top = clips->y1;
        bottom = clips->y2;
 
-       clips_ptr = clips;
-       for (i = 1; i < num_clips; i++, clips_ptr += inc) {
+       /* skip the first clip rect */
+       for (i = 1, clips_ptr = clips + inc;
+            i < num_clips; i++, clips_ptr += inc) {
                left = min_t(int, left, (int)clips_ptr->x1);
                right = max_t(int, right, (int)clips_ptr->x2);
                top = min_t(int, top, (int)clips_ptr->y1);
@@ -1323,7 +1328,10 @@ int vmw_kms_close(struct vmw_private *dev_priv)
         * drm_encoder_cleanup which takes the lock we deadlock.
         */
        drm_mode_config_cleanup(dev_priv->dev);
-       vmw_kms_close_legacy_display_system(dev_priv);
+       if (dev_priv->sou_priv)
+               vmw_kms_close_screen_object_display(dev_priv);
+       else
+               vmw_kms_close_legacy_display_system(dev_priv);
        return 0;
 }
 
index c72f1c0..bdde899 100644 (file)
@@ -465,31 +465,29 @@ static void vga_arbiter_check_bridge_sharing(struct vga_device *vgadev)
        while (new_bus) {
                new_bridge = new_bus->self;
 
-               if (new_bridge) {
-                       /* go through list of devices already registered */
-                       list_for_each_entry(same_bridge_vgadev, &vga_list, list) {
-                               bus = same_bridge_vgadev->pdev->bus;
-                               bridge = bus->self;
-
-                               /* see if the share a bridge with this device */
-                               if (new_bridge == bridge) {
-                                       /* if their direct parent bridge is the same
-                                          as any bridge of this device then it can't be used
-                                          for that device */
-                                       same_bridge_vgadev->bridge_has_one_vga = false;
-                               }
+               /* go through list of devices already registered */
+               list_for_each_entry(same_bridge_vgadev, &vga_list, list) {
+                       bus = same_bridge_vgadev->pdev->bus;
+                       bridge = bus->self;
+
+                       /* see if the share a bridge with this device */
+                       if (new_bridge == bridge) {
+                               /* if their direct parent bridge is the same
+                                  as any bridge of this device then it can't be used
+                                  for that device */
+                               same_bridge_vgadev->bridge_has_one_vga = false;
+                       }
 
-                               /* now iterate the previous devices bridge hierarchy */
-                               /* if the new devices parent bridge is in the other devices
-                                  hierarchy then we can't use it to control this device */
-                               while (bus) {
-                                       bridge = bus->self;
-                                       if (bridge) {
-                                               if (bridge == vgadev->pdev->bus->self)
-                                                       vgadev->bridge_has_one_vga = false;
-                                       }
-                                       bus = bus->parent;
+                       /* now iterate the previous devices bridge hierarchy */
+                       /* if the new devices parent bridge is in the other devices
+                          hierarchy then we can't use it to control this device */
+                       while (bus) {
+                               bridge = bus->self;
+                               if (bridge) {
+                                       if (bridge == vgadev->pdev->bus->self)
+                                               vgadev->bridge_has_one_vga = false;
                                }
+                               bus = bus->parent;
                        }
                }
                new_bus = new_bus->parent;
index 9ec854a..91be41f 100644 (file)
@@ -315,7 +315,7 @@ config SENSORS_DS1621
 
 config SENSORS_EXYNOS4_TMU
        tristate "Temperature sensor on Samsung EXYNOS4"
-       depends on EXYNOS4_DEV_TMU
+       depends on ARCH_EXYNOS4
        help
          If you say yes here you get support for TMU (Thermal Managment
          Unit) on SAMSUNG EXYNOS4 series of SoC.
index 143461a..86980fe 100644 (file)
@@ -21,6 +21,7 @@
  * General Public License for more details.
  */
 
+#include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/pm_runtime.h>
@@ -108,10 +109,8 @@ static int __devinit u8500_hsem_probe(struct platform_device *pdev)
                return -ENODEV;
 
        io_base = ioremap(res->start, resource_size(res));
-       if (!io_base) {
-               ret = -ENOMEM;
-               goto free_state;
-       }
+       if (!io_base)
+               return -ENOMEM;
 
        /* make sure protocol 1 is selected */
        val = readl(io_base + HSEM_CTRL_REG);
index 67cbcfa..847553f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Copyright (C) 1998-2000 Andreas S. Krebs (akrebs@altavista.net), Maintainer
  *  Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>, Integrator
- *  Copyright (C) 2007-2010 Bartlomiej Zolnierkiewicz
+ *  Copyright (C) 2007-2011 Bartlomiej Zolnierkiewicz
  *
  * CYPRESS CY82C693 chipset IDE controller
  *
@@ -90,7 +90,7 @@ static void cy82c693_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
        u8 time_16, time_8;
 
        /* select primary or secondary channel */
-       if (hwif->index > 0) {  /* drive is on the secondary channel */
+       if (drive->dn > 1) {  /* drive is on the secondary channel */
                dev = pci_get_slot(dev->bus, dev->devfn+1);
                if (!dev) {
                        printk(KERN_ERR "%s: tune_drive: "
@@ -141,7 +141,7 @@ static void cy82c693_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
                pci_write_config_byte(dev, CY82_IDE_SLAVE_IOW, time_16);
                pci_write_config_byte(dev, CY82_IDE_SLAVE_8BIT, time_8);
        }
-       if (hwif->index > 0)
+       if (drive->dn > 1)
                pci_dev_put(dev);
 }
 
index 4a697a2..8716066 100644 (file)
@@ -521,8 +521,8 @@ icside_register_v6(struct icside_state *state, struct expansion_card *ec)
        if (ec->dma != NO_DMA && !request_dma(ec->dma, DRV_NAME)) {
                d.init_dma = icside_dma_init;
                d.port_ops = &icside_v6_port_ops;
+       } else
                d.dma_ops = NULL;
-       }
 
        ret = ide_host_register(host, &d, hws);
        if (ret)
index 04b0956..8126824 100644 (file)
@@ -43,7 +43,6 @@
 /* For SCSI -> ATAPI command conversion */
 #include <scsi/scsi.h>
 
-#include <linux/irq.h>
 #include <linux/io.h>
 #include <asm/byteorder.h>
 #include <linux/uaccess.h>
index 61fdf54..3d42043 100644 (file)
@@ -35,7 +35,6 @@
 #include <scsi/scsi_ioctl.h>
 
 #include <asm/byteorder.h>
-#include <linux/irq.h>
 #include <linux/uaccess.h>
 #include <linux/io.h>
 #include <asm/unaligned.h>
index 7ecb1ad..ce8237d 100644 (file)
@@ -41,7 +41,6 @@
 #include <scsi/scsi.h>
 
 #include <asm/byteorder.h>
-#include <linux/irq.h>
 #include <linux/uaccess.h>
 #include <linux/io.h>
 #include <asm/unaligned.h>
index b59d04c..1892e81 100644 (file)
@@ -331,7 +331,7 @@ static const struct ide_port_ops ich_port_ops = {
                .udma_mask      = udma,                 \
        }
 
-#define DECLARE_ICH_DEV(udma) \
+#define DECLARE_ICH_DEV(mwdma, udma) \
        { \
                .name           = DRV_NAME, \
                .init_chipset   = init_chipset_ich, \
@@ -340,7 +340,7 @@ static const struct ide_port_ops ich_port_ops = {
                .port_ops       = &ich_port_ops, \
                .pio_mask       = ATA_PIO4, \
                .swdma_mask     = ATA_SWDMA2_ONLY, \
-               .mwdma_mask     = ATA_MWDMA12_ONLY, \
+               .mwdma_mask     = mwdma, \
                .udma_mask      = udma, \
        }
 
@@ -362,13 +362,15 @@ static const struct ide_port_info piix_pci_info[] __devinitdata = {
        /* 2: PIIX4 */
        DECLARE_PIIX_DEV(ATA_UDMA2),
        /* 3: ICH0 */
-       DECLARE_ICH_DEV(ATA_UDMA2),
+       DECLARE_ICH_DEV(ATA_MWDMA12_ONLY, ATA_UDMA2),
        /* 4: ICH */
-       DECLARE_ICH_DEV(ATA_UDMA4),
+       DECLARE_ICH_DEV(ATA_MWDMA12_ONLY, ATA_UDMA4),
        /* 5: PIIX4 */
        DECLARE_PIIX_DEV(ATA_UDMA4),
-       /* 6: ICH[2-7]/ICH[2-3]M/C-ICH/ICH5-SATA/ESB2/ICH8M */
-       DECLARE_ICH_DEV(ATA_UDMA5),
+       /* 6: ICH[2-6]/ICH[2-3]M/C-ICH/ICH5-SATA/ESB2/ICH8M */
+       DECLARE_ICH_DEV(ATA_MWDMA12_ONLY, ATA_UDMA5),
+       /* 7: ICH7/7-R, no MWDMA1 */
+       DECLARE_ICH_DEV(ATA_MWDMA2_ONLY, ATA_UDMA5),
 };
 
 /**
@@ -438,9 +440,9 @@ static const struct pci_device_id piix_pci_tbl[] = {
 #endif
        { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ESB_2),      6 },
        { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH6_19),    6 },
-       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH7_21),    6 },
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH7_21),    7 },
        { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801DB_1),  6 },
-       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ESB2_18),    6 },
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ESB2_18),    7 },
        { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH8_6),     6 },
        { 0, },
 };
index e53a1b7..281c914 100644 (file)
@@ -113,12 +113,26 @@ static const struct pci_device_id triflex_pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci, triflex_pci_tbl);
 
+#ifdef CONFIG_PM
+static int triflex_ide_pci_suspend(struct pci_dev *dev, pm_message_t state)
+{
+       /*
+        * We must not disable or powerdown the device.
+        * APM bios refuses to suspend if IDE is not accessible.
+        */
+       pci_save_state(dev);
+       return 0;
+}
+#else
+#define triflex_ide_pci_suspend NULL
+#endif
+
 static struct pci_driver triflex_pci_driver = {
        .name           = "TRIFLEX_IDE",
        .id_table       = triflex_pci_tbl,
        .probe          = triflex_init_one,
        .remove         = ide_pci_remove,
-       .suspend        = ide_pci_suspend,
+       .suspend        = triflex_ide_pci_suspend,
        .resume         = ide_pci_resume,
 };
 
index eb0e2cc..73d4531 100644 (file)
@@ -343,7 +343,7 @@ static void ieee802154_fake_setup(struct net_device *dev)
 {
        dev->addr_len           = IEEE802154_ADDR_LEN;
        memset(dev->broadcast, 0xff, IEEE802154_ADDR_LEN);
-       dev->features           = NETIF_F_NO_CSUM;
+       dev->features           = NETIF_F_HW_CSUM;
        dev->needed_tailroom    = 2; /* FCS */
        dev->mtu                = 127;
        dev->tx_queue_len       = 10;
index 691276b..adf0757 100644 (file)
@@ -243,8 +243,8 @@ static int addr6_resolve(struct sockaddr_in6 *src_in,
        int ret;
 
        memset(&fl6, 0, sizeof fl6);
-       ipv6_addr_copy(&fl6.daddr, &dst_in->sin6_addr);
-       ipv6_addr_copy(&fl6.saddr, &src_in->sin6_addr);
+       fl6.daddr = dst_in->sin6_addr;
+       fl6.saddr = src_in->sin6_addr;
        fl6.flowi6_oif = addr->bound_dev_if;
 
        dst = ip6_route_output(&init_net, NULL, &fl6);
@@ -258,7 +258,7 @@ static int addr6_resolve(struct sockaddr_in6 *src_in,
                        goto put;
 
                src_in->sin6_family = AF_INET6;
-               ipv6_addr_copy(&src_in->sin6_addr, &fl6.saddr);
+               src_in->sin6_addr = fl6.saddr;
        }
 
        if (dst->dev->flags & IFF_LOOPBACK) {
index 75ff821..09e66cc 100644 (file)
@@ -2005,11 +2005,11 @@ static int cma_resolve_loopback(struct rdma_id_private *id_priv)
        if (cma_zero_addr(src)) {
                dst = (struct sockaddr *) &id_priv->id.route.addr.dst_addr;
                if ((src->sa_family = dst->sa_family) == AF_INET) {
-                       ((struct sockaddr_in *) src)->sin_addr.s_addr =
-                               ((struct sockaddr_in *) dst)->sin_addr.s_addr;
+                       ((struct sockaddr_in *)src)->sin_addr =
+                               ((struct sockaddr_in *)dst)->sin_addr;
                } else {
-                       ipv6_addr_copy(&((struct sockaddr_in6 *) src)->sin6_addr,
-                                      &((struct sockaddr_in6 *) dst)->sin6_addr);
+                       ((struct sockaddr_in6 *)src)->sin6_addr =
+                               ((struct sockaddr_in6 *)dst)->sin6_addr;
                }
        }
 
index c00d2f3..4b3fa71 100644 (file)
@@ -1589,7 +1589,7 @@ static const struct ethtool_ops nes_ethtool_ops = {
        .set_pauseparam = nes_netdev_set_pauseparam,
 };
 
-static void nes_vlan_mode(struct net_device *netdev, struct nes_device *nesdev, u32 features)
+static void nes_vlan_mode(struct net_device *netdev, struct nes_device *nesdev, netdev_features_t features)
 {
        struct nes_adapter *nesadapter = nesdev->nesadapter;
        u32 u32temp;
@@ -1610,7 +1610,7 @@ static void nes_vlan_mode(struct net_device *netdev, struct nes_device *nesdev,
        spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
 }
 
-static u32 nes_fix_features(struct net_device *netdev, u32 features)
+static netdev_features_t nes_fix_features(struct net_device *netdev, netdev_features_t features)
 {
        /*
         * Since there is no support for separate rx/tx vlan accel
@@ -1624,7 +1624,7 @@ static u32 nes_fix_features(struct net_device *netdev, u32 features)
        return features;
 }
 
-static int nes_set_features(struct net_device *netdev, u32 features)
+static int nes_set_features(struct net_device *netdev, netdev_features_t features)
 {
        struct nes_vnic *nesvnic = netdev_priv(netdev);
        struct nes_device *nesdev = nesvnic->nesdev;
index 7567b60..efd7a96 100644 (file)
@@ -171,7 +171,7 @@ static int ipoib_stop(struct net_device *dev)
        return 0;
 }
 
-static u32 ipoib_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t ipoib_fix_features(struct net_device *dev, netdev_features_t features)
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
 
index 9c192e7..288da5c 100644 (file)
@@ -10,6 +10,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/module.h>
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/io.h>
index e8fdb88..46be456 100644 (file)
@@ -10,6 +10,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/module.h>
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
index 661b692..6d5628b 100644 (file)
@@ -270,11 +270,8 @@ void led_blink_set(struct led_classdev *led_cdev,
        del_timer_sync(&led_cdev->blink_timer);
 
        if (led_cdev->blink_set &&
-           !led_cdev->blink_set(led_cdev, delay_on, delay_off)) {
-               led_cdev->blink_delay_on = *delay_on;
-               led_cdev->blink_delay_off = *delay_off;
+           !led_cdev->blink_set(led_cdev, delay_on, delay_off))
                return;
-       }
 
        /* blink with 1 Hz as default if nothing specified */
        if (!*delay_on && !*delay_off)
index 0dc30ff..595d731 100644 (file)
@@ -381,6 +381,11 @@ error:
        return PTR_ERR(vqs[i]);
 }
 
+static const char *lg_bus_name(struct virtio_device *vdev)
+{
+       return "";
+}
+
 /* The ops structure which hooks everything together. */
 static struct virtio_config_ops lguest_config_ops = {
        .get_features = lg_get_features,
@@ -392,6 +397,7 @@ static struct virtio_config_ops lguest_config_ops = {
        .reset = lg_reset,
        .find_vqs = lg_find_vqs,
        .del_vqs = lg_del_vqs,
+       .bus_name = lg_bus_name,
 };
 
 /*
index 817f37a..c9570fc 100644 (file)
@@ -159,7 +159,7 @@ int macii_init(void)
        err = macii_init_via();
        if (err) goto out;
 
-       err = request_irq(IRQ_MAC_ADB, macii_interrupt, IRQ_FLG_LOCK, "ADB",
+       err = request_irq(IRQ_MAC_ADB, macii_interrupt, 0, "ADB",
                          macii_interrupt);
        if (err) goto out;
 
index 9ab5b0c..34d02a9 100644 (file)
@@ -122,8 +122,8 @@ maciisi_init(void)
                return err;
        }
 
-       if (request_irq(IRQ_MAC_ADB, maciisi_interrupt, IRQ_FLG_LOCK | IRQ_FLG_FAST, 
-                       "ADB", maciisi_interrupt)) {
+       if (request_irq(IRQ_MAC_ADB, maciisi_interrupt, 0, "ADB",
+                       maciisi_interrupt)) {
                printk(KERN_ERR "maciisi_init: can't get irq %d\n", IRQ_MAC_ADB);
                return -EAGAIN;
        }
index 472aedf..297e260 100644 (file)
@@ -3110,7 +3110,7 @@ static void handle_stripe(struct stripe_head *sh)
        struct r5dev *pdev, *qdev;
 
        clear_bit(STRIPE_HANDLE, &sh->state);
-       if (test_and_set_bit(STRIPE_ACTIVE, &sh->state)) {
+       if (test_and_set_bit_lock(STRIPE_ACTIVE, &sh->state)) {
                /* already being handled, ensure it gets handled
                 * again when current action finishes */
                set_bit(STRIPE_HANDLE, &sh->state);
@@ -3159,10 +3159,14 @@ static void handle_stripe(struct stripe_head *sh)
        /* check if the array has lost more than max_degraded devices and,
         * if so, some requests might need to be failed.
         */
-       if (s.failed > conf->max_degraded && s.to_read+s.to_write+s.written)
-               handle_failed_stripe(conf, sh, &s, disks, &s.return_bi);
-       if (s.failed > conf->max_degraded && s.syncing)
-               handle_failed_sync(conf, sh, &s);
+       if (s.failed > conf->max_degraded) {
+               sh->check_state = 0;
+               sh->reconstruct_state = 0;
+               if (s.to_read+s.to_write+s.written)
+                       handle_failed_stripe(conf, sh, &s, disks, &s.return_bi);
+               if (s.syncing)
+                       handle_failed_sync(conf, sh, &s);
+       }
 
        /*
         * might be able to return some write requests if the parity blocks
@@ -3371,7 +3375,7 @@ finish:
 
        return_io(s.return_bi);
 
-       clear_bit(STRIPE_ACTIVE, &sh->state);
+       clear_bit_unlock(STRIPE_ACTIVE, &sh->state);
 }
 
 static void raid5_activate_delayed(struct r5conf *conf)
index 2e8c288..3443455 100644 (file)
@@ -398,7 +398,6 @@ static int mxl111sf_i2c_readagain(struct mxl111sf_state *state,
        u8 i2c_r_data[24];
        u8 i = 0;
        u8 fifo_status = 0;
-       int ret;
        int status = 0;
 
        mxl_i2c("read %d bytes", count);
@@ -418,7 +417,7 @@ static int mxl111sf_i2c_readagain(struct mxl111sf_state *state,
                i2c_w_data[4+(i*3)] = 0x00;
        }
 
-       ret = mxl111sf_i2c_get_data(state, 0, i2c_w_data, i2c_r_data);
+       mxl111sf_i2c_get_data(state, 0, i2c_w_data, i2c_r_data);
 
        /* Check for I2C NACK status */
        if (mxl111sf_i2c_check_status(state) == 1) {
index 91dc1fc..b741b3a 100644 (file)
@@ -296,8 +296,7 @@ int mxl111sf_config_spi(struct mxl111sf_state *state, int onoff)
                goto fail;
 
        ret = mxl111sf_write_reg(state, 0x00, 0x00);
-       if (mxl_fail(ret))
-               goto fail;
+       mxl_fail(ret);
 fail:
        return ret;
 }
@@ -328,11 +327,13 @@ int mxl111sf_idac_config(struct mxl111sf_state *state,
                /* set hysteresis value  reg: 0x0B<5:0> */
                ret = mxl111sf_write_reg(state, V6_IDAC_HYSTERESIS_REG,
                                         (hysteresis_value & 0x3F));
+               mxl_fail(ret);
        }
 
        ret = mxl111sf_write_reg(state, V6_IDAC_SETTINGS_REG, val);
+       mxl_fail(ret);
 
-       return val;
+       return ret;
 }
 
 /*
index 2446736..0df7f2a 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/gpio.h>
 #include <linux/i2c.h>
 #include <linux/media.h>
+#include <linux/module.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 
index 725634d..844a4d7 100644 (file)
@@ -220,8 +220,8 @@ static int vidioc_querycap(struct file *file, void *priv,
        strncpy(cap->card, dev->plat_dev->name, sizeof(cap->card) - 1);
        cap->bus_info[0] = 0;
        cap->version = KERNEL_VERSION(1, 0, 0);
-       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT
-                                                   | V4L2_CAP_STREAMING;
+       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE_MPLANE |
+                       V4L2_CAP_VIDEO_OUTPUT_MPLANE | V4L2_CAP_STREAMING;
        return 0;
 }
 
index ecef127..1e8cdb7 100644 (file)
@@ -785,8 +785,8 @@ static int vidioc_querycap(struct file *file, void *priv,
        strncpy(cap->card, dev->plat_dev->name, sizeof(cap->card) - 1);
        cap->bus_info[0] = 0;
        cap->version = KERNEL_VERSION(1, 0, 0);
-       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
-                         | V4L2_CAP_VIDEO_OUTPUT
+       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE_MPLANE
+                         | V4L2_CAP_VIDEO_OUTPUT_MPLANE
                          | V4L2_CAP_STREAMING;
        return 0;
 }
index 10c2364..254d326 100644 (file)
@@ -1016,7 +1016,8 @@ int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
 
        menu_info = &mapping->menu_info[query_menu->index];
 
-       if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) {
+       if (mapping->data_type == UVC_CTRL_DATA_TYPE_BITMASK &&
+           (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES)) {
                s32 bitmap;
 
                if (!ctrl->cached) {
@@ -1225,7 +1226,8 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
                /* Valid menu indices are reported by the GET_RES request for
                 * UVC controls that support it.
                 */
-               if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) {
+               if (mapping->data_type == UVC_CTRL_DATA_TYPE_BITMASK &&
+                   (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES)) {
                        if (!ctrl->cached) {
                                ret = uvc_ctrl_populate_cache(chain, ctrl);
                                if (ret < 0)
index f17f92b..0f415da 100644 (file)
@@ -821,8 +821,8 @@ static void send_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 changes)
        fill_event(&ev, ctrl, changes);
 
        list_for_each_entry(sev, &ctrl->ev_subs, node)
-               if (sev->fh && (sev->fh != fh ||
-                               (sev->flags & V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK)))
+               if (sev->fh != fh ||
+                   (sev->flags & V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK))
                        v4l2_event_queue_fh(sev->fh, &ev);
 }
 
@@ -947,6 +947,7 @@ static void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
                        if (ctrl->cluster[0]->has_volatiles)
                                ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
                }
+               fh = NULL;
        }
        if (changed || update_inactive) {
                /* If a control was changed that was not one of the controls
index 46037f2..c26ad96 100644 (file)
@@ -216,6 +216,9 @@ int v4l2_event_subscribe(struct v4l2_fh *fh,
        unsigned long flags;
        unsigned i;
 
+       if (sub->type == V4L2_EVENT_ALL)
+               return -EINVAL;
+
        if (elems < 1)
                elems = 1;
        if (sub->type == V4L2_EVENT_CTRL) {
@@ -283,6 +286,7 @@ int v4l2_event_unsubscribe(struct v4l2_fh *fh,
 {
        struct v4l2_subscribed_event *sev;
        unsigned long flags;
+       int i;
 
        if (sub->type == V4L2_EVENT_ALL) {
                v4l2_event_unsubscribe_all(fh);
@@ -293,8 +297,12 @@ int v4l2_event_unsubscribe(struct v4l2_fh *fh,
 
        sev = v4l2_event_subscribed(fh, sub->type, sub->id);
        if (sev != NULL) {
+               /* Remove any pending events for this subscription */
+               for (i = 0; i < sev->in_use; i++) {
+                       list_del(&sev->events[sev_pos(sev, i)].list);
+                       fh->navailable--;
+               }
                list_del(&sev->list);
-               sev->fh = NULL;
        }
 
        spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
index 979e544..95a3f5e 100644 (file)
@@ -131,6 +131,7 @@ static void __setup_offsets(struct vb2_queue *q, unsigned int n)
                        continue;
 
                for (plane = 0; plane < vb->num_planes; ++plane) {
+                       vb->v4l2_planes[plane].length = q->plane_sizes[plane];
                        vb->v4l2_planes[plane].m.mem_offset = off;
 
                        dprintk(3, "Buffer %d, plane %d offset 0x%08lx\n",
@@ -264,6 +265,7 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
        q->num_buffers -= buffers;
        if (!q->num_buffers)
                q->memory = 0;
+       INIT_LIST_HEAD(&q->queued_list);
 }
 
 /**
@@ -296,14 +298,14 @@ static bool __buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb)
 {
        unsigned int plane;
        for (plane = 0; plane < vb->num_planes; ++plane) {
+               void *mem_priv = vb->planes[plane].mem_priv;
                /*
                 * If num_users() has not been provided, call_memop
                 * will return 0, apparently nobody cares about this
                 * case anyway. If num_users() returns more than 1,
                 * we are not the only user of the plane's memory.
                 */
-               if (call_memop(q, plane, num_users,
-                               vb->planes[plane].mem_priv) > 1)
+               if (mem_priv && call_memop(q, plane, num_users, mem_priv) > 1)
                        return true;
        }
        return false;
index 4175544..ec10629 100644 (file)
@@ -13,6 +13,7 @@
  * TODO: Event handling with irq_chip. Waiting for PRCMU fw support.
  */
 
+#include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/err.h>
 #include <linux/platform_device.h>
index 6be1fe6..43c0ebb 100644 (file)
@@ -4,6 +4,7 @@
  * Debugfs support for the AB5500 MFD driver
  */
 
+#include <linux/export.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 #include <linux/mfd/ab5500/ab5500.h>
index 7ce6065..eb5cd28 100644 (file)
@@ -945,8 +945,7 @@ static int fpga_of_remove(struct platform_device *op)
 /* CTL-CPLD Version Register */
 #define CTL_CPLD_VERSION       0x2000
 
-static int fpga_of_probe(struct platform_device *op,
-                        const struct of_device_id *match)
+static int fpga_of_probe(struct platform_device *op)
 {
        struct device_node *of_node = op->dev.of_node;
        struct device *this_device;
@@ -1107,7 +1106,7 @@ static struct of_device_id fpga_of_match[] = {
        {},
 };
 
-static struct of_platform_driver fpga_of_driver = {
+static struct platform_driver fpga_of_driver = {
        .probe          = fpga_of_probe,
        .remove         = fpga_of_remove,
        .driver         = {
@@ -1124,12 +1123,12 @@ static struct of_platform_driver fpga_of_driver = {
 static int __init fpga_init(void)
 {
        led_trigger_register_simple("fpga", &ledtrig_fpga);
-       return of_register_platform_driver(&fpga_of_driver);
+       return platform_driver_register(&fpga_of_driver);
 }
 
 static void __exit fpga_exit(void)
 {
-       of_unregister_platform_driver(&fpga_of_driver);
+       platform_driver_unregister(&fpga_of_driver);
        led_trigger_unregister_simple(ledtrig_fpga);
 }
 
index 3965821..14e974b 100644 (file)
@@ -1249,8 +1249,7 @@ static bool dma_filter(struct dma_chan *chan, void *data)
        return true;
 }
 
-static int data_of_probe(struct platform_device *op,
-                        const struct of_device_id *match)
+static int data_of_probe(struct platform_device *op)
 {
        struct device_node *of_node = op->dev.of_node;
        struct device *this_device;
@@ -1401,7 +1400,7 @@ static struct of_device_id data_of_match[] = {
        {},
 };
 
-static struct of_platform_driver data_of_driver = {
+static struct platform_driver data_of_driver = {
        .probe          = data_of_probe,
        .remove         = data_of_remove,
        .driver         = {
@@ -1417,12 +1416,12 @@ static struct of_platform_driver data_of_driver = {
 
 static int __init data_init(void)
 {
-       return of_register_platform_driver(&data_of_driver);
+       return platform_driver_register(&data_of_driver);
 }
 
 static void __exit data_exit(void)
 {
-       of_unregister_platform_driver(&data_of_driver);
+       platform_driver_unregister(&data_of_driver);
 }
 
 MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>");
index 26cf12c..701edf6 100644 (file)
@@ -85,7 +85,7 @@ config EEPROM_93XX46
 
 config EEPROM_DIGSY_MTC_CFG
        bool "DigsyMTC display configuration EEPROMs device"
-       depends on PPC_MPC5200_GPIO && GPIOLIB && SPI_GPIO
+       depends on GPIO_MPC5200 && SPI_GPIO
        help
          This option enables access to display configuration EEPROMs
          on digsy_mtc board. You have to additionally select Microwire
index 42f0673..3fac67a 100644 (file)
@@ -576,7 +576,7 @@ xpnet_init(void)
         * report an error if the data is not retrievable and the
         * packet will be dropped.
         */
-       xpnet_device->features = NETIF_F_NO_CSUM;
+       xpnet_device->features = NETIF_F_HW_CSUM;
 
        result = register_netdev(xpnet_device);
        if (result != 0) {
index ae57769..4b976f0 100644 (file)
@@ -32,6 +32,7 @@
 /* VENDOR SPEC register */
 #define SDHCI_VENDOR_SPEC              0xC0
 #define  SDHCI_VENDOR_SPEC_SDIO_QUIRK  0x00000002
+#define SDHCI_WTMK_LVL                 0x44
 #define SDHCI_MIX_CTRL                 0x48
 
 /*
@@ -476,6 +477,13 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
        if (is_imx53_esdhc(imx_data))
                imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT;
 
+       /*
+        * The imx6q ROM code will change the default watermark level setting
+        * to something insane.  Change it back here.
+        */
+       if (is_imx6q_usdhc(imx_data))
+               writel(0x08100810, host->ioaddr + SDHCI_WTMK_LVL);
+
        boarddata = &imx_data->boarddata;
        if (sdhci_esdhc_imx_probe_dt(pdev, boarddata) < 0) {
                if (!host->mmc->parent->platform_data) {
index 608967f..736ca10 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
+#include <linux/module.h>
 #include <linux/mtd/map.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
index 583f66c..debdf1c 100644 (file)
@@ -125,6 +125,8 @@ config IFB
          'ifb1' etc.
          Look at the iproute2 documentation directory for usage etc
 
+source "drivers/net/team/Kconfig"
+
 config MACVLAN
        tristate "MAC-VLAN support (EXPERIMENTAL)"
        depends on EXPERIMENTAL
@@ -245,6 +247,8 @@ source "drivers/net/ethernet/Kconfig"
 
 source "drivers/net/fddi/Kconfig"
 
+source "drivers/net/hippi/Kconfig"
+
 config NET_SB1000
        tristate "General Instruments Surfboard 1000"
        depends on PNP
index fa877cd..4e4ebfe 100644 (file)
@@ -17,6 +17,7 @@ obj-$(CONFIG_NET) += Space.o loopback.o
 obj-$(CONFIG_NETCONSOLE) += netconsole.o
 obj-$(CONFIG_PHYLIB) += phy/
 obj-$(CONFIG_RIONET) += rionet.o
+obj-$(CONFIG_NET_TEAM) += team/
 obj-$(CONFIG_TUN) += tun.o
 obj-$(CONFIG_VETH) += veth.o
 obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
index 027a0ee..7e66322 100644 (file)
@@ -50,7 +50,7 @@ static void bond_glean_dev_ipv6(struct net_device *dev, struct in6_addr *addr)
                struct inet6_ifaddr *ifa
                        = list_first_entry(&idev->addr_list,
                                           struct inet6_ifaddr, if_list);
-               ipv6_addr_copy(addr, &ifa->addr);
+               *addr = ifa->addr;
        } else
                ipv6_addr_set(addr, 0, 0, 0, 0);
 
@@ -168,8 +168,7 @@ static int bond_inet6addr_event(struct notifier_block *this,
                        switch (event) {
                        case NETDEV_UP:
                                if (ipv6_addr_any(&bond->master_ipv6))
-                                       ipv6_addr_copy(&bond->master_ipv6,
-                                                      &ifa->addr);
+                                       bond->master_ipv6 = ifa->addr;
                                return NOTIFY_OK;
                        case NETDEV_DOWN:
                                if (ipv6_addr_equal(&bond->master_ipv6,
@@ -191,8 +190,7 @@ static int bond_inet6addr_event(struct notifier_block *this,
                                switch (event) {
                                case NETDEV_UP:
                                        if (ipv6_addr_any(&vlan->vlan_ipv6))
-                                               ipv6_addr_copy(&vlan->vlan_ipv6,
-                                                              &ifa->addr);
+                                               vlan->vlan_ipv6 = ifa->addr;
                                        return NOTIFY_OK;
                                case NETDEV_DOWN:
                                        if (ipv6_addr_equal(&vlan->vlan_ipv6,
index b0c5772..25a44d9 100644 (file)
@@ -1325,11 +1325,12 @@ static int bond_sethwaddr(struct net_device *bond_dev,
        return 0;
 }
 
-static u32 bond_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t bond_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        struct slave *slave;
        struct bonding *bond = netdev_priv(dev);
-       u32 mask;
+       netdev_features_t mask;
        int i;
 
        read_lock(&bond->lock);
@@ -1363,7 +1364,7 @@ static void bond_compute_features(struct bonding *bond)
 {
        struct slave *slave;
        struct net_device *bond_dev = bond->dev;
-       u32 vlan_features = BOND_VLAN_FEATURES;
+       netdev_features_t vlan_features = BOND_VLAN_FEATURES;
        unsigned short max_hard_header_len = ETH_HLEN;
        int i;
 
@@ -1897,7 +1898,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
        struct bonding *bond = netdev_priv(bond_dev);
        struct slave *slave, *oldcurrent;
        struct sockaddr addr;
-       u32 old_features = bond_dev->features;
+       netdev_features_t old_features = bond_dev->features;
 
        /* slave is not a slave or master is not master of this slave */
        if (!(slave_dev->flags & IFF_SLAVE) ||
@@ -4360,7 +4361,7 @@ static void bond_setup(struct net_device *bond_dev)
                                NETIF_F_HW_VLAN_RX |
                                NETIF_F_HW_VLAN_FILTER;
 
-       bond_dev->hw_features &= ~(NETIF_F_ALL_CSUM & ~NETIF_F_NO_CSUM);
+       bond_dev->hw_features &= ~(NETIF_F_ALL_CSUM & ~NETIF_F_HW_CSUM);
        bond_dev->features |= bond_dev->hw_features;
 }
 
index 5a20804..4ef7e2f 100644 (file)
@@ -319,6 +319,13 @@ static ssize_t bonding_store_mode(struct device *d,
                goto out;
        }
 
+       if (bond->slave_cnt > 0) {
+               pr_err("unable to update mode of %s because it has slaves.\n",
+                       bond->dev->name);
+               ret = -EPERM;
+               goto out;
+       }
+
        new_value = bond_parse_parm(buf, bond_mode_tbl);
        if (new_value < 0)  {
                pr_err("%s: Ignoring invalid mode value %.*s.\n",
index 25695bd..120f1ab 100644 (file)
@@ -454,7 +454,7 @@ static void can_setup(struct net_device *dev)
 
        /* New-style flags. */
        dev->flags = IFF_NOARP;
-       dev->features = NETIF_F_NO_CSUM;
+       dev->features = NETIF_F_HW_CSUM;
 }
 
 struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
index ec4a311..1c82dd8 100644 (file)
@@ -581,7 +581,10 @@ static int mscan_open(struct net_device *dev)
 
        priv->open_time = jiffies;
 
-       clrbits8(&regs->canctl1, MSCAN_LISTEN);
+       if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
+               setbits8(&regs->canctl1, MSCAN_LISTEN);
+       else
+               clrbits8(&regs->canctl1, MSCAN_LISTEN);
 
        ret = mscan_start(dev);
        if (ret)
@@ -690,7 +693,8 @@ struct net_device *alloc_mscandev(void)
        priv->can.bittiming_const = &mscan_bittiming_const;
        priv->can.do_set_bittiming = mscan_do_set_bittiming;
        priv->can.do_set_mode = mscan_do_set_mode;
-       priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
+       priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
+               CAN_CTRLMODE_LISTENONLY;
 
        for (i = 0; i < TX_QUEUE_SIZE; i++) {
                priv->tx_queue[i].id = i;
index a979b00..3f1ebcc 100644 (file)
@@ -387,7 +387,7 @@ static void slc_setup(struct net_device *dev)
 
        /* New-style flags. */
        dev->flags              = IFF_NOARP;
-       dev->features           = NETIF_F_NO_CSUM;
+       dev->features           = NETIF_F_HW_CSUM;
 }
 
 /******************************************
index a7c5e88..087648e 100644 (file)
@@ -134,7 +134,7 @@ static void dummy_setup(struct net_device *dev)
        dev->flags |= IFF_NOARP;
        dev->flags &= ~IFF_MULTICAST;
        dev->features   |= NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO;
-       dev->features   |= NETIF_F_NO_CSUM | NETIF_F_HIGHDMA | NETIF_F_LLTX;
+       dev->features   |= NETIF_F_HW_CSUM | NETIF_F_HIGHDMA | NETIF_F_LLTX;
        random_ether_addr(dev->dev_addr);
 }
 
index 972f80e..da410f0 100644 (file)
@@ -468,9 +468,10 @@ static void tc589_reset(struct net_device *dev)
 static void netdev_get_drvinfo(struct net_device *dev,
                               struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       sprintf(info->bus_info, "PCMCIA 0x%lx", dev->base_addr);
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       snprintf(info->bus_info, sizeof(info->bus_info),
+               "PCMCIA 0x%lx", dev->base_addr);
 }
 
 static const struct ethtool_ops netdev_ethtool_ops = {
index b42c06b..8153a3e 100644 (file)
@@ -2929,15 +2929,17 @@ static void vortex_get_drvinfo(struct net_device *dev,
 {
        struct vortex_private *vp = netdev_priv(dev);
 
-       strcpy(info->driver, DRV_NAME);
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
        if (VORTEX_PCI(vp)) {
-               strcpy(info->bus_info, pci_name(VORTEX_PCI(vp)));
+               strlcpy(info->bus_info, pci_name(VORTEX_PCI(vp)),
+                       sizeof(info->bus_info));
        } else {
                if (VORTEX_EISA(vp))
-                       strcpy(info->bus_info, dev_name(vp->gendev));
+                       strlcpy(info->bus_info, dev_name(vp->gendev),
+                               sizeof(info->bus_info));
                else
-                       sprintf(info->bus_info, "EISA 0x%lx %d",
-                                       dev->base_addr, dev->irq);
+                       snprintf(info->bus_info, sizeof(info->bus_info),
+                               "EISA 0x%lx %d", dev->base_addr, dev->irq);
        }
 }
 
index 20ea075..6d6bc75 100644 (file)
@@ -988,21 +988,23 @@ typhoon_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 
        smp_rmb();
        if(tp->card_state == Sleeping) {
-               strcpy(info->fw_version, "Sleep image");
+               strlcpy(info->fw_version, "Sleep image",
+                       sizeof(info->fw_version));
        } else {
                INIT_COMMAND_WITH_RESPONSE(&xp_cmd, TYPHOON_CMD_READ_VERSIONS);
                if(typhoon_issue_command(tp, 1, &xp_cmd, 3, xp_resp) < 0) {
-                       strcpy(info->fw_version, "Unknown runtime");
+                       strlcpy(info->fw_version, "Unknown runtime",
+                               sizeof(info->fw_version));
                } else {
                        u32 sleep_ver = le32_to_cpu(xp_resp[0].parm2);
-                       snprintf(info->fw_version, 32, "%02x.%03x.%03x",
-                                sleep_ver >> 24, (sleep_ver >> 12) & 0xfff,
-                                sleep_ver & 0xfff);
+                       snprintf(info->fw_version, sizeof(info->fw_version),
+                               "%02x.%03x.%03x", sleep_ver >> 24,
+                               (sleep_ver >> 12) & 0xfff, sleep_ver & 0xfff);
                }
        }
 
-       strcpy(info->driver, KBUILD_MODNAME);
-       strcpy(info->bus_info, pci_name(pci_dev));
+       strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
+       strlcpy(info->bus_info, pci_name(pci_dev), sizeof(info->bus_info));
 }
 
 static int
index 58a12e4..ef325ff 100644 (file)
@@ -14,8 +14,6 @@
 
 #define TX_PAGES 12    /* Two Tx slots */
 
-#define ETHER_ADDR_LEN 6
-
 /* The 8390 specific per-packet-header format. */
 struct e8390_pkt_hdr {
   unsigned char status; /* status */
index 5477373..3ad5d2f 100644 (file)
@@ -318,7 +318,7 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr)
     i = request_irq(dev->irq, apne_interrupt, IRQF_SHARED, DRV_NAME, dev);
     if (i) return i;
 
-    for(i = 0; i < ETHER_ADDR_LEN; i++)
+    for (i = 0; i < ETH_ALEN; i++)
        dev->dev_addr[i] = SA_prom[i];
 
     printk(" %pM\n", dev->dev_addr);
index e9f8432..2a3b8c2 100644 (file)
@@ -735,15 +735,14 @@ static int ax_init_dev(struct net_device *dev)
        if (ax->plat->flags & AXFLG_MAC_FROMDEV) {
                ei_outb(E8390_NODMA + E8390_PAGE1 + E8390_STOP,
                        ei_local->mem + E8390_CMD); /* 0x61 */
-               for (i = 0; i < ETHER_ADDR_LEN; i++)
+               for (i = 0; i < ETH_ALEN; i++)
                        dev->dev_addr[i] =
                                ei_inb(ioaddr + EN1_PHYS_SHIFT(i));
        }
 
        if ((ax->plat->flags & AXFLG_MAC_FROMPLATFORM) &&
            ax->plat->mac_addr)
-               memcpy(dev->dev_addr, ax->plat->mac_addr,
-                      ETHER_ADDR_LEN);
+               memcpy(dev->dev_addr, ax->plat->mac_addr, ETH_ALEN);
 
        ax_reset_8390(dev);
 
index 7a09575..6428f9e 100644 (file)
@@ -195,7 +195,7 @@ static int __init es_probe1(struct net_device *dev, int ioaddr)
                goto out;
        }
 
-       for (i = 0; i < ETHER_ADDR_LEN ; i++)
+       for (i = 0; i < ETH_ALEN ; i++)
                dev->dev_addr[i] = inb(ioaddr + ES_SA_PROM + i);
 
 /*     Check the Racal vendor ID as well. */
index eeac843..d42938b 100644 (file)
@@ -202,7 +202,7 @@ static int __init hpp_probe1(struct net_device *dev, int ioaddr)
        /* Retrieve and checksum the station address. */
        outw(MAC_Page, ioaddr + HP_PAGING);
 
-       for(i = 0; i < ETHER_ADDR_LEN; i++) {
+       for(i = 0; i < ETH_ALEN; i++) {
                unsigned char inval = inb(ioaddr + 8 + i);
                dev->dev_addr[i] = inval;
                checksum += inval;
index 18564d4..113f1e0 100644 (file)
@@ -156,7 +156,7 @@ static int __init hp_probe1(struct net_device *dev, int ioaddr)
 
        printk("%s: %s (ID %02x) at %#3x,", dev->name, name, board_id, ioaddr);
 
-       for(i = 0; i < ETHER_ADDR_LEN; i++)
+       for(i = 0; i < ETH_ALEN; i++)
                dev->dev_addr[i] = inb(ioaddr + i);
 
        printk(" %pM", dev->dev_addr);
index 3dac937..5370c88 100644 (file)
@@ -129,7 +129,7 @@ static int __devinit hydra_init(struct zorro_dev *z)
     if (!dev)
        return -ENOMEM;
 
-    for(j = 0; j < ETHER_ADDR_LEN; j++)
+    for (j = 0; j < ETH_ALEN; j++)
        dev->dev_addr[j] = *((u8 *)(board + HYDRA_ADDRPROM + 2*j));
 
     /* We must set the 8390 for word mode. */
index f9888d2..69490ae 100644 (file)
@@ -191,14 +191,14 @@ static int __init lne390_probe1(struct net_device *dev, int ioaddr)
                || inb(ioaddr + LNE390_SA_PROM + 1) != LNE390_ADDR1
                || inb(ioaddr + LNE390_SA_PROM + 2) != LNE390_ADDR2 ) {
                printk("lne390.c: card not found");
-               for(i = 0; i < ETHER_ADDR_LEN; i++)
+               for (i = 0; i < ETH_ALEN; i++)
                        printk(" %02x", inb(ioaddr + LNE390_SA_PROM + i));
                printk(" (invalid prefix).\n");
                return -ENODEV;
        }
 #endif
 
-       for(i = 0; i < ETHER_ADDR_LEN; i++)
+       for (i = 0; i < ETH_ALEN; i++)
                dev->dev_addr[i] = inb(ioaddr + LNE390_SA_PROM + i);
        printk("lne390.c: LNE390%X in EISA slot %d, address %pM.\n",
               0xa+revision, ioaddr/0x1000, dev->dev_addr);
index cd36a6a..9b9c77d 100644 (file)
@@ -312,7 +312,7 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr)
 
        dev->base_addr = ioaddr;
 
-       for(i = 0; i < ETHER_ADDR_LEN; i++)
+       for (i = 0; i < ETH_ALEN; i++)
                dev->dev_addr[i] = SA_prom[i];
        printk(" %pM\n", dev->dev_addr);
 
index 1063093..f92ea2a 100644 (file)
@@ -503,12 +503,12 @@ static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr)
 #ifdef CONFIG_PLAT_MAPPI
        outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP,
                ioaddr + E8390_CMD); /* 0x61 */
-       for (i = 0 ; i < ETHER_ADDR_LEN ; i++) {
+       for (i = 0; i < ETH_ALEN; i++) {
                dev->dev_addr[i] = SA_prom[i]
                        = inb_p(ioaddr + EN1_PHYS_SHIFT(i));
        }
 #else
-       for(i = 0; i < ETHER_ADDR_LEN; i++) {
+       for (i = 0; i < ETH_ALEN; i++) {
                dev->dev_addr[i] = SA_prom[i];
        }
 #endif
index 70cdc69..922b320 100644 (file)
@@ -460,7 +460,7 @@ static int __init ne2_probe1(struct net_device *dev, int slot)
 
        dev->base_addr = base_addr;
 
-       for(i = 0; i < ETHER_ADDR_LEN; i++)
+       for (i = 0; i < ETH_ALEN; i++)
                dev->dev_addr[i] = SA_prom[i];
 
        printk(" %pM\n", dev->dev_addr);
index 3992342..3fab04a 100644 (file)
@@ -639,9 +639,9 @@ static void ne2k_pci_get_drvinfo(struct net_device *dev,
        struct ei_device *ei = netdev_priv(dev);
        struct pci_dev *pci_dev = (struct pci_dev *) ei->priv;
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, pci_name(pci_dev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(pci_dev), sizeof(info->bus_info));
 }
 
 static const struct ethtool_ops ne2k_pci_ethtool_ops = {
index 243ed2a..2a3e805 100644 (file)
@@ -125,7 +125,7 @@ static int __init ne3210_eisa_probe (struct device *device)
 #endif
 
        port_index = inb(ioaddr + NE3210_CFG2) >> 6;
-       for(i = 0; i < ETHER_ADDR_LEN; i++)
+       for (i = 0; i < ETH_ALEN; i++)
                dev->dev_addr[i] = inb(ioaddr + NE3210_SA_PROM + i);
        printk("ne3210.c: NE3210 in EISA slot %d, media: %s, addr: %pM.\n",
                edev->slot, ifmap[port_index], dev->dev_addr);
index d85f0a8..3b90375 100644 (file)
@@ -114,7 +114,7 @@ static int __init stnic_probe(void)
 #ifdef CONFIG_SH_STANDARD_BIOS
   sh_bios_get_node_addr (stnic_eadr);
 #endif
-  for (i = 0; i < ETHER_ADDR_LEN; i++)
+  for (i = 0; i < ETH_ALEN; i++)
     dev->dev_addr[i] = stnic_eadr[i];
 
   /* Set the base address to point to the NIC, not the "real" base! */
index 3aa9fe9..bcd2732 100644 (file)
@@ -365,7 +365,7 @@ static int __devinit zorro8390_init(struct net_device *dev,
        if (i)
                return i;
 
-       for (i = 0; i < ETHER_ADDR_LEN; i++)
+       for (i = 0; i < ETH_ALEN; i++)
                dev->dev_addr[i] = SA_prom[i];
 
        pr_debug("Found ethernet address: %pM\n", dev->dev_addr);
index 6d9f691..a446e25 100644 (file)
@@ -1842,9 +1842,9 @@ static int check_if_running(struct net_device *dev)
 static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
        struct netdev_private *np = netdev_priv(dev);
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, pci_name(np->pci_dev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(np->pci_dev), sizeof(info->bus_info));
 }
 
 static int get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
index a9745f4..33e0a8c 100644 (file)
@@ -499,7 +499,7 @@ static int amd8111e_restart(struct net_device *dev)
        writel( VAL0 | APAD_XMT | REX_RTRY, mmio + CMD2 );
 
        /* Setting the MAC address to the device */
-       for(i = 0; i < ETH_ADDR_LEN; i++)
+       for (i = 0; i < ETH_ALEN; i++)
                writeb( dev->dev_addr[i], mmio + PADR + i );
 
        /* Enable interrupt coalesce */
@@ -1412,10 +1412,11 @@ static void amd8111e_get_drvinfo(struct net_device* dev, struct ethtool_drvinfo
 {
        struct amd8111e_priv *lp = netdev_priv(dev);
        struct pci_dev *pci_dev = lp->pci_dev;
-       strcpy (info->driver, MODULE_NAME);
-       strcpy (info->version, MODULE_VERS);
-       sprintf(info->fw_version,"%u",chip_version);
-       strcpy (info->bus_info, pci_name(pci_dev));
+       strlcpy(info->driver, MODULE_NAME, sizeof(info->driver));
+       strlcpy(info->version, MODULE_VERS, sizeof(info->version));
+       snprintf(info->fw_version, sizeof(info->fw_version),
+               "%u", chip_version);
+       strlcpy(info->bus_info, pci_name(pci_dev), sizeof(info->bus_info));
 }
 
 static int amd8111e_get_regs_len(struct net_device *dev)
@@ -1549,7 +1550,7 @@ static int amd8111e_set_mac_address(struct net_device *dev, void *p)
        memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
        spin_lock_irq(&lp->lock);
        /* Setting the MAC address to the device */
-       for(i = 0; i < ETH_ADDR_LEN; i++)
+       for (i = 0; i < ETH_ALEN; i++)
                writeb( dev->dev_addr[i], lp->mmio + PADR + i );
 
        spin_unlock_irq(&lp->lock);
@@ -1885,7 +1886,7 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
        }
 
        /* Initializing MAC address */
-       for(i = 0; i < ETH_ADDR_LEN; i++)
+       for (i = 0; i < ETH_ALEN; i++)
                dev->dev_addr[i] = readb(lp->mmio + PADR + i);
 
        /* Setting user defined parametrs */
index 2ff2e7a..5bbb53a 100644 (file)
@@ -586,7 +586,6 @@ typedef enum {
 
 #define PKT_BUFF_SZ                    1536
 #define MIN_PKT_LEN                    60
-#define ETH_ADDR_LEN                   6
 
 #define  AMD8111E_TX_TIMEOUT           (3 * HZ)/* 3 sec */
 #define SOFT_TIMER_FREQ                0xBEBC  /* 0.5 sec */
index 3accd5d..6be0dd6 100644 (file)
@@ -160,8 +160,6 @@ Include Files
 Defines
 ---------------------------------------------------------------------------- */
 
-#define ETHER_ADDR_LEN                 ETH_ALEN
-                                       /* 6 bytes in an Ethernet Address */
 #define MACE_LADRF_LEN                 8
                                        /* 8 bytes in Logical Address Filter */
 
@@ -600,7 +598,7 @@ static int mace_init(mace_private *lp, unsigned int ioaddr, char *enet_addr)
        }
   }
   /* Set PADR register */
-  for (i = 0; i < ETHER_ADDR_LEN; i++)
+  for (i = 0; i < ETH_ALEN; i++)
     mace_write(lp, ioaddr, MACE_PADR, enet_addr[i]);
 
   /* MAC Configuration Control Register should be written last */
@@ -639,11 +637,11 @@ static int nmclan_config(struct pcmcia_device *link)
 
   /* Read the ethernet address from the CIS. */
   len = pcmcia_get_tuple(link, 0x80, &buf);
-  if (!buf || len < ETHER_ADDR_LEN) {
+  if (!buf || len < ETH_ALEN) {
          kfree(buf);
          goto failed;
   }
-  memcpy(dev->dev_addr, buf, ETHER_ADDR_LEN);
+  memcpy(dev->dev_addr, buf, ETH_ALEN);
   kfree(buf);
 
   /* Verify configuration by reading the MACE ID. */
@@ -822,9 +820,10 @@ static int mace_close(struct net_device *dev)
 static void netdev_get_drvinfo(struct net_device *dev,
                               struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       sprintf(info->bus_info, "PCMCIA 0x%lx", dev->base_addr);
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       snprintf(info->bus_info, sizeof(info->bus_info),
+               "PCMCIA 0x%lx", dev->base_addr);
 }
 
 static const struct ethtool_ops netdev_ethtool_ops = {
@@ -1420,7 +1419,7 @@ Output
 static void set_multicast_list(struct net_device *dev)
 {
   mace_private *lp = netdev_priv(dev);
-  int adr[ETHER_ADDR_LEN] = {0}; /* Ethernet address */
+  int adr[ETH_ALEN] = {0}; /* Ethernet address */
   struct netdev_hw_addr *ha;
 
 #ifdef PCMCIA_DEBUG
@@ -1442,7 +1441,7 @@ static void set_multicast_list(struct net_device *dev)
     /* Calculate multicast logical address filter */
     memset(lp->multicast_ladrf, 0, MACE_LADRF_LEN);
     netdev_for_each_mc_addr(ha, dev) {
-      memcpy(adr, ha->addr, ETHER_ADDR_LEN);
+      memcpy(adr, ha->addr, ETH_ALEN);
       BuildLAF(lp->multicast_ladrf, adr);
     }
   }
index f92bc6e..20e6dab 100644 (file)
@@ -711,12 +711,14 @@ static void pcnet32_get_drvinfo(struct net_device *dev,
 {
        struct pcnet32_private *lp = netdev_priv(dev);
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
        if (lp->pci_dev)
-               strcpy(info->bus_info, pci_name(lp->pci_dev));
+               strlcpy(info->bus_info, pci_name(lp->pci_dev),
+                       sizeof(info->bus_info));
        else
-               sprintf(info->bus_info, "VLB 0x%lx", dev->base_addr);
+               snprintf(info->bus_info, sizeof(info->bus_info),
+                       "VLB 0x%lx", dev->base_addr);
 }
 
 static u32 pcnet32_get_link(struct net_device *dev)
index 7be884d..0a9326a 100644 (file)
@@ -232,7 +232,6 @@ static void atl1c_get_drvinfo(struct net_device *netdev,
        strlcpy(drvinfo->driver,  atl1c_driver_name, sizeof(drvinfo->driver));
        strlcpy(drvinfo->version, atl1c_driver_version,
                sizeof(drvinfo->version));
-       strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
        strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
                sizeof(drvinfo->bus_info));
        drvinfo->n_stats = 0;
index 02c7ed8..b859124 100644 (file)
@@ -411,7 +411,7 @@ static void atl1c_set_multi(struct net_device *netdev)
        }
 }
 
-static void __atl1c_vlan_mode(u32 features, u32 *mac_ctrl_data)
+static void __atl1c_vlan_mode(netdev_features_t features, u32 *mac_ctrl_data)
 {
        if (features & NETIF_F_HW_VLAN_RX) {
                /* enable VLAN tag insert/strip */
@@ -422,7 +422,8 @@ static void __atl1c_vlan_mode(u32 features, u32 *mac_ctrl_data)
        }
 }
 
-static void atl1c_vlan_mode(struct net_device *netdev, u32 features)
+static void atl1c_vlan_mode(struct net_device *netdev,
+       netdev_features_t features)
 {
        struct atl1c_adapter *adapter = netdev_priv(netdev);
        struct pci_dev *pdev = adapter->pdev;
@@ -482,7 +483,8 @@ static void atl1c_set_rxbufsize(struct atl1c_adapter *adapter,
                roundup(mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN, 8) : AT_RX_BUF_SIZE;
 }
 
-static u32 atl1c_fix_features(struct net_device *netdev, u32 features)
+static netdev_features_t atl1c_fix_features(struct net_device *netdev,
+       netdev_features_t features)
 {
        /*
         * Since there is no support for separate rx/tx vlan accel
@@ -499,9 +501,10 @@ static u32 atl1c_fix_features(struct net_device *netdev, u32 features)
        return features;
 }
 
-static int atl1c_set_features(struct net_device *netdev, u32 features)
+static int atl1c_set_features(struct net_device *netdev,
+       netdev_features_t features)
 {
-       u32 changed = netdev->features ^ features;
+       netdev_features_t changed = netdev->features ^ features;
 
        if (changed & NETIF_F_HW_VLAN_RX)
                atl1c_vlan_mode(netdev, features);
index 6269438..6e61f9f 100644 (file)
@@ -310,10 +310,12 @@ static void atl1e_get_drvinfo(struct net_device *netdev,
 {
        struct atl1e_adapter *adapter = netdev_priv(netdev);
 
-       strncpy(drvinfo->driver,  atl1e_driver_name, 32);
-       strncpy(drvinfo->version, atl1e_driver_version, 32);
-       strncpy(drvinfo->fw_version, "L1e", 32);
-       strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
+       strlcpy(drvinfo->driver,  atl1e_driver_name, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, atl1e_driver_version,
+               sizeof(drvinfo->version));
+       strlcpy(drvinfo->fw_version, "L1e", sizeof(drvinfo->fw_version));
+       strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
+               sizeof(drvinfo->bus_info));
        drvinfo->n_stats = 0;
        drvinfo->testinfo_len = 0;
        drvinfo->regdump_len = atl1e_get_regs_len(netdev);
index 95483bc..c915c08 100644 (file)
@@ -313,7 +313,7 @@ static void atl1e_set_multi(struct net_device *netdev)
        }
 }
 
-static void __atl1e_vlan_mode(u32 features, u32 *mac_ctrl_data)
+static void __atl1e_vlan_mode(netdev_features_t features, u32 *mac_ctrl_data)
 {
        if (features & NETIF_F_HW_VLAN_RX) {
                /* enable VLAN tag insert/strip */
@@ -324,7 +324,8 @@ static void __atl1e_vlan_mode(u32 features, u32 *mac_ctrl_data)
        }
 }
 
-static void atl1e_vlan_mode(struct net_device *netdev, u32 features)
+static void atl1e_vlan_mode(struct net_device *netdev,
+       netdev_features_t features)
 {
        struct atl1e_adapter *adapter = netdev_priv(netdev);
        u32 mac_ctrl_data = 0;
@@ -370,7 +371,8 @@ static int atl1e_set_mac_addr(struct net_device *netdev, void *p)
        return 0;
 }
 
-static u32 atl1e_fix_features(struct net_device *netdev, u32 features)
+static netdev_features_t atl1e_fix_features(struct net_device *netdev,
+       netdev_features_t features)
 {
        /*
         * Since there is no support for separate rx/tx vlan accel
@@ -384,9 +386,10 @@ static u32 atl1e_fix_features(struct net_device *netdev, u32 features)
        return features;
 }
 
-static int atl1e_set_features(struct net_device *netdev, u32 features)
+static int atl1e_set_features(struct net_device *netdev,
+       netdev_features_t features)
 {
-       u32 changed = netdev->features ^ features;
+       netdev_features_t changed = netdev->features ^ features;
 
        if (changed & NETIF_F_HW_VLAN_RX)
                atl1e_vlan_mode(netdev, features);
index 33a4e35..9bd2049 100644 (file)
@@ -3365,7 +3365,6 @@ static void atl1_get_drvinfo(struct net_device *netdev,
        strlcpy(drvinfo->driver, ATLX_DRIVER_NAME, sizeof(drvinfo->driver));
        strlcpy(drvinfo->version, ATLX_DRIVER_VERSION,
                sizeof(drvinfo->version));
-       strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
        strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
                sizeof(drvinfo->bus_info));
        drvinfo->eedump_len = ATL1_EEDUMP_LEN;
index 1feae59..071f4c8 100644 (file)
@@ -361,7 +361,7 @@ static inline void atl2_irq_disable(struct atl2_adapter *adapter)
     synchronize_irq(adapter->pdev->irq);
 }
 
-static void __atl2_vlan_mode(u32 features, u32 *ctrl)
+static void __atl2_vlan_mode(netdev_features_t features, u32 *ctrl)
 {
        if (features & NETIF_F_HW_VLAN_RX) {
                /* enable VLAN tag insert/strip */
@@ -372,7 +372,8 @@ static void __atl2_vlan_mode(u32 features, u32 *ctrl)
        }
 }
 
-static void atl2_vlan_mode(struct net_device *netdev, u32 features)
+static void atl2_vlan_mode(struct net_device *netdev,
+       netdev_features_t features)
 {
        struct atl2_adapter *adapter = netdev_priv(netdev);
        u32 ctrl;
@@ -391,7 +392,8 @@ static void atl2_restore_vlan(struct atl2_adapter *adapter)
        atl2_vlan_mode(adapter->netdev, adapter->netdev->features);
 }
 
-static u32 atl2_fix_features(struct net_device *netdev, u32 features)
+static netdev_features_t atl2_fix_features(struct net_device *netdev,
+       netdev_features_t features)
 {
        /*
         * Since there is no support for separate rx/tx vlan accel
@@ -405,9 +407,10 @@ static u32 atl2_fix_features(struct net_device *netdev, u32 features)
        return features;
 }
 
-static int atl2_set_features(struct net_device *netdev, u32 features)
+static int atl2_set_features(struct net_device *netdev,
+       netdev_features_t features)
 {
-       u32 changed = netdev->features ^ features;
+       netdev_features_t changed = netdev->features ^ features;
 
        if (changed & NETIF_F_HW_VLAN_RX)
                atl2_vlan_mode(netdev, features);
@@ -2049,10 +2052,12 @@ static void atl2_get_drvinfo(struct net_device *netdev,
 {
        struct atl2_adapter *adapter = netdev_priv(netdev);
 
-       strncpy(drvinfo->driver,  atl2_driver_name, 32);
-       strncpy(drvinfo->version, atl2_driver_version, 32);
-       strncpy(drvinfo->fw_version, "L2", 32);
-       strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
+       strlcpy(drvinfo->driver,  atl2_driver_name, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, atl2_driver_version,
+               sizeof(drvinfo->version));
+       strlcpy(drvinfo->fw_version, "L2", sizeof(drvinfo->fw_version));
+       strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
+               sizeof(drvinfo->bus_info));
        drvinfo->n_stats = 0;
        drvinfo->testinfo_len = 0;
        drvinfo->regdump_len = atl2_get_regs_len(netdev);
index aabcf4b..8ff7411 100644 (file)
@@ -211,7 +211,7 @@ static void atlx_link_chg_task(struct work_struct *work)
        spin_unlock_irqrestore(&adapter->lock, flags);
 }
 
-static void __atlx_vlan_mode(u32 features, u32 *ctrl)
+static void __atlx_vlan_mode(netdev_features_t features, u32 *ctrl)
 {
        if (features & NETIF_F_HW_VLAN_RX) {
                /* enable VLAN tag insert/strip */
@@ -222,7 +222,8 @@ static void __atlx_vlan_mode(u32 features, u32 *ctrl)
        }
 }
 
-static void atlx_vlan_mode(struct net_device *netdev, u32 features)
+static void atlx_vlan_mode(struct net_device *netdev,
+       netdev_features_t features)
 {
        struct atlx_adapter *adapter = netdev_priv(netdev);
        unsigned long flags;
@@ -242,7 +243,8 @@ static void atlx_restore_vlan(struct atlx_adapter *adapter)
        atlx_vlan_mode(adapter->netdev, adapter->netdev->features);
 }
 
-static u32 atlx_fix_features(struct net_device *netdev, u32 features)
+static netdev_features_t atlx_fix_features(struct net_device *netdev,
+       netdev_features_t features)
 {
        /*
         * Since there is no support for separate rx/tx vlan accel
@@ -256,9 +258,10 @@ static u32 atlx_fix_features(struct net_device *netdev, u32 features)
        return features;
 }
 
-static int atlx_set_features(struct net_device *netdev, u32 features)
+static int atlx_set_features(struct net_device *netdev,
+       netdev_features_t features)
 {
-       u32 changed = netdev->features ^ features;
+       netdev_features_t changed = netdev->features ^ features;
 
        if (changed & NETIF_F_HW_VLAN_RX)
                atlx_vlan_mode(netdev, features);
index 965c723..d573169 100644 (file)
@@ -409,7 +409,7 @@ static int bnx2_unregister_cnic(struct net_device *dev)
        mutex_lock(&bp->cnic_lock);
        cp->drv_state = 0;
        bnapi->cnic_present = 0;
-       rcu_assign_pointer(bp->cnic_ops, NULL);
+       RCU_INIT_POINTER(bp->cnic_ops, NULL);
        mutex_unlock(&bp->cnic_lock);
        synchronize_rcu();
        return 0;
@@ -2054,8 +2054,8 @@ __acquires(&bp->phy_lock)
 
        if (bp->autoneg & AUTONEG_SPEED) {
                u32 adv_reg, adv1000_reg;
-               u32 new_adv_reg = 0;
-               u32 new_adv1000_reg = 0;
+               u32 new_adv = 0;
+               u32 new_adv1000 = 0;
 
                bnx2_read_phy(bp, bp->mii_adv, &adv_reg);
                adv_reg &= (PHY_ALL_10_100_SPEED | ADVERTISE_PAUSE_CAP |
@@ -2064,27 +2064,18 @@ __acquires(&bp->phy_lock)
                bnx2_read_phy(bp, MII_CTRL1000, &adv1000_reg);
                adv1000_reg &= PHY_ALL_1000_SPEED;
 
-               if (bp->advertising & ADVERTISED_10baseT_Half)
-                       new_adv_reg |= ADVERTISE_10HALF;
-               if (bp->advertising & ADVERTISED_10baseT_Full)
-                       new_adv_reg |= ADVERTISE_10FULL;
-               if (bp->advertising & ADVERTISED_100baseT_Half)
-                       new_adv_reg |= ADVERTISE_100HALF;
-               if (bp->advertising & ADVERTISED_100baseT_Full)
-                       new_adv_reg |= ADVERTISE_100FULL;
-               if (bp->advertising & ADVERTISED_1000baseT_Full)
-                       new_adv1000_reg |= ADVERTISE_1000FULL;
+               new_adv = ethtool_adv_to_mii_adv_t(bp->advertising);
+               new_adv |= ADVERTISE_CSMA;
+               new_adv |= bnx2_phy_get_pause_adv(bp);
 
-               new_adv_reg |= ADVERTISE_CSMA;
+               new_adv1000 |= ethtool_adv_to_mii_ctrl1000_t(bp->advertising);
 
-               new_adv_reg |= bnx2_phy_get_pause_adv(bp);
-
-               if ((adv1000_reg != new_adv1000_reg) ||
-                       (adv_reg != new_adv_reg) ||
+               if ((adv1000_reg != new_adv1000) ||
+                       (adv_reg != new_adv) ||
                        ((bmcr & BMCR_ANENABLE) == 0)) {
 
-                       bnx2_write_phy(bp, bp->mii_adv, new_adv_reg);
-                       bnx2_write_phy(bp, MII_CTRL1000, new_adv1000_reg);
+                       bnx2_write_phy(bp, bp->mii_adv, new_adv);
+                       bnx2_write_phy(bp, MII_CTRL1000, new_adv1000);
                        bnx2_write_phy(bp, bp->mii_bmcr, BMCR_ANRESTART |
                                BMCR_ANENABLE);
                }
@@ -2734,31 +2725,27 @@ bnx2_free_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index)
 }
 
 static inline int
-bnx2_alloc_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index, gfp_t gfp)
+bnx2_alloc_rx_data(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index, gfp_t gfp)
 {
-       struct sk_buff *skb;
+       u8 *data;
        struct sw_bd *rx_buf = &rxr->rx_buf_ring[index];
        dma_addr_t mapping;
        struct rx_bd *rxbd = &rxr->rx_desc_ring[RX_RING(index)][RX_IDX(index)];
-       unsigned long align;
 
-       skb = __netdev_alloc_skb(bp->dev, bp->rx_buf_size, gfp);
-       if (skb == NULL) {
+       data = kmalloc(bp->rx_buf_size, gfp);
+       if (!data)
                return -ENOMEM;
-       }
 
-       if (unlikely((align = (unsigned long) skb->data & (BNX2_RX_ALIGN - 1))))
-               skb_reserve(skb, BNX2_RX_ALIGN - align);
-
-       mapping = dma_map_single(&bp->pdev->dev, skb->data, bp->rx_buf_use_size,
+       mapping = dma_map_single(&bp->pdev->dev,
+                                get_l2_fhdr(data),
+                                bp->rx_buf_use_size,
                                 PCI_DMA_FROMDEVICE);
        if (dma_mapping_error(&bp->pdev->dev, mapping)) {
-               dev_kfree_skb(skb);
+               kfree(data);
                return -EIO;
        }
 
-       rx_buf->skb = skb;
-       rx_buf->desc = (struct l2_fhdr *) skb->data;
+       rx_buf->data = data;
        dma_unmap_addr_set(rx_buf, mapping, mapping);
 
        rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
@@ -2965,8 +2952,8 @@ bnx2_reuse_rx_skb_pages(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
 }
 
 static inline void
-bnx2_reuse_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
-                 struct sk_buff *skb, u16 cons, u16 prod)
+bnx2_reuse_rx_data(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
+                  u8 *data, u16 cons, u16 prod)
 {
        struct sw_bd *cons_rx_buf, *prod_rx_buf;
        struct rx_bd *cons_bd, *prod_bd;
@@ -2980,8 +2967,7 @@ bnx2_reuse_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
 
        rxr->rx_prod_bseq += bp->rx_buf_use_size;
 
-       prod_rx_buf->skb = skb;
-       prod_rx_buf->desc = (struct l2_fhdr *) skb->data;
+       prod_rx_buf->data = data;
 
        if (cons == prod)
                return;
@@ -2995,33 +2981,39 @@ bnx2_reuse_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
        prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
 }
 
-static int
-bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, struct sk_buff *skb,
+static struct sk_buff *
+bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u8 *data,
            unsigned int len, unsigned int hdr_len, dma_addr_t dma_addr,
            u32 ring_idx)
 {
        int err;
        u16 prod = ring_idx & 0xffff;
+       struct sk_buff *skb;
 
-       err = bnx2_alloc_rx_skb(bp, rxr, prod, GFP_ATOMIC);
+       err = bnx2_alloc_rx_data(bp, rxr, prod, GFP_ATOMIC);
        if (unlikely(err)) {
-               bnx2_reuse_rx_skb(bp, rxr, skb, (u16) (ring_idx >> 16), prod);
+               bnx2_reuse_rx_data(bp, rxr, data, (u16) (ring_idx >> 16), prod);
+error:
                if (hdr_len) {
                        unsigned int raw_len = len + 4;
                        int pages = PAGE_ALIGN(raw_len - hdr_len) >> PAGE_SHIFT;
 
                        bnx2_reuse_rx_skb_pages(bp, rxr, NULL, pages);
                }
-               return err;
+               return NULL;
        }
 
-       skb_reserve(skb, BNX2_RX_OFFSET);
        dma_unmap_single(&bp->pdev->dev, dma_addr, bp->rx_buf_use_size,
                         PCI_DMA_FROMDEVICE);
-
+       skb = build_skb(data);
+       if (!skb) {
+               kfree(data);
+               goto error;
+       }
+       skb_reserve(skb, ((u8 *)get_l2_fhdr(data) - data) + BNX2_RX_OFFSET);
        if (hdr_len == 0) {
                skb_put(skb, len);
-               return 0;
+               return skb;
        } else {
                unsigned int i, frag_len, frag_size, pages;
                struct sw_pg *rx_pg;
@@ -3052,7 +3044,7 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, struct sk_buff *skb,
                                        skb_frag_size_sub(frag, tail);
                                        skb->data_len -= tail;
                                }
-                               return 0;
+                               return skb;
                        }
                        rx_pg = &rxr->rx_pg_ring[pg_cons];
 
@@ -3074,7 +3066,7 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, struct sk_buff *skb,
                                rxr->rx_pg_prod = pg_prod;
                                bnx2_reuse_rx_skb_pages(bp, rxr, skb,
                                                        pages - i);
-                               return err;
+                               return NULL;
                        }
 
                        dma_unmap_page(&bp->pdev->dev, mapping_old,
@@ -3091,7 +3083,7 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, struct sk_buff *skb,
                rxr->rx_pg_prod = pg_prod;
                rxr->rx_pg_cons = pg_cons;
        }
-       return 0;
+       return skb;
 }
 
 static inline u16
@@ -3130,19 +3122,17 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
                struct sw_bd *rx_buf, *next_rx_buf;
                struct sk_buff *skb;
                dma_addr_t dma_addr;
+               u8 *data;
 
                sw_ring_cons = RX_RING_IDX(sw_cons);
                sw_ring_prod = RX_RING_IDX(sw_prod);
 
                rx_buf = &rxr->rx_buf_ring[sw_ring_cons];
-               skb = rx_buf->skb;
-               prefetchw(skb);
-
-               next_rx_buf =
-                       &rxr->rx_buf_ring[RX_RING_IDX(NEXT_RX_BD(sw_cons))];
-               prefetch(next_rx_buf->desc);
+               data = rx_buf->data;
+               rx_buf->data = NULL;
 
-               rx_buf->skb = NULL;
+               rx_hdr = get_l2_fhdr(data);
+               prefetch(rx_hdr);
 
                dma_addr = dma_unmap_addr(rx_buf, mapping);
 
@@ -3150,7 +3140,10 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
                        BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH,
                        PCI_DMA_FROMDEVICE);
 
-               rx_hdr = rx_buf->desc;
+               next_rx_buf =
+                       &rxr->rx_buf_ring[RX_RING_IDX(NEXT_RX_BD(sw_cons))];
+               prefetch(get_l2_fhdr(next_rx_buf->data));
+
                len = rx_hdr->l2_fhdr_pkt_len;
                status = rx_hdr->l2_fhdr_status;
 
@@ -3169,7 +3162,7 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
                                       L2_FHDR_ERRORS_TOO_SHORT |
                                       L2_FHDR_ERRORS_GIANT_FRAME))) {
 
-                       bnx2_reuse_rx_skb(bp, rxr, skb, sw_ring_cons,
+                       bnx2_reuse_rx_data(bp, rxr, data, sw_ring_cons,
                                          sw_ring_prod);
                        if (pg_ring_used) {
                                int pages;
@@ -3184,30 +3177,29 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
                len -= 4;
 
                if (len <= bp->rx_copy_thresh) {
-                       struct sk_buff *new_skb;
-
-                       new_skb = netdev_alloc_skb(bp->dev, len + 6);
-                       if (new_skb == NULL) {
-                               bnx2_reuse_rx_skb(bp, rxr, skb, sw_ring_cons,
+                       skb = netdev_alloc_skb(bp->dev, len + 6);
+                       if (skb == NULL) {
+                               bnx2_reuse_rx_data(bp, rxr, data, sw_ring_cons,
                                                  sw_ring_prod);
                                goto next_rx;
                        }
 
                        /* aligned copy */
-                       skb_copy_from_linear_data_offset(skb,
-                                                        BNX2_RX_OFFSET - 6,
-                                     new_skb->data, len + 6);
-                       skb_reserve(new_skb, 6);
-                       skb_put(new_skb, len);
+                       memcpy(skb->data,
+                              (u8 *)rx_hdr + BNX2_RX_OFFSET - 6,
+                              len + 6);
+                       skb_reserve(skb, 6);
+                       skb_put(skb, len);
 
-                       bnx2_reuse_rx_skb(bp, rxr, skb,
+                       bnx2_reuse_rx_data(bp, rxr, data,
                                sw_ring_cons, sw_ring_prod);
 
-                       skb = new_skb;
-               } else if (unlikely(bnx2_rx_skb(bp, rxr, skb, len, hdr_len,
-                          dma_addr, (sw_ring_cons << 16) | sw_ring_prod)))
-                       goto next_rx;
-
+               } else {
+                       skb = bnx2_rx_skb(bp, rxr, data, len, hdr_len, dma_addr,
+                                         (sw_ring_cons << 16) | sw_ring_prod);
+                       if (!skb)
+                               goto next_rx;
+               }
                if ((status & L2_FHDR_STATUS_L2_VLAN_TAG) &&
                    !(bp->rx_mode & BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG))
                        __vlan_hwaccel_put_tag(skb, rx_hdr->l2_fhdr_vlan_tag);
@@ -5234,7 +5226,7 @@ bnx2_init_rx_ring(struct bnx2 *bp, int ring_num)
 
        ring_prod = prod = rxr->rx_prod;
        for (i = 0; i < bp->rx_ring_size; i++) {
-               if (bnx2_alloc_rx_skb(bp, rxr, ring_prod, GFP_KERNEL) < 0) {
+               if (bnx2_alloc_rx_data(bp, rxr, ring_prod, GFP_KERNEL) < 0) {
                        netdev_warn(bp->dev, "init'ed rx ring %d with %d/%d skbs only\n",
                                    ring_num, i, bp->rx_ring_size);
                        break;
@@ -5329,7 +5321,7 @@ bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size)
        rx_size = bp->dev->mtu + ETH_HLEN + BNX2_RX_OFFSET + 8;
 
        rx_space = SKB_DATA_ALIGN(rx_size + BNX2_RX_ALIGN) + NET_SKB_PAD +
-               sizeof(struct skb_shared_info);
+               SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
 
        bp->rx_copy_thresh = BNX2_RX_COPY_THRESH;
        bp->rx_pg_ring_size = 0;
@@ -5351,8 +5343,9 @@ bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size)
        }
 
        bp->rx_buf_use_size = rx_size;
-       /* hw alignment */
-       bp->rx_buf_size = bp->rx_buf_use_size + BNX2_RX_ALIGN;
+       /* hw alignment + build_skb() overhead*/
+       bp->rx_buf_size = SKB_DATA_ALIGN(bp->rx_buf_use_size + BNX2_RX_ALIGN) +
+               NET_SKB_PAD + SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
        bp->rx_jumbo_thresh = rx_size - BNX2_RX_OFFSET;
        bp->rx_ring_size = size;
        bp->rx_max_ring = bnx2_find_max_ring(size, MAX_RX_RINGS);
@@ -5418,9 +5411,9 @@ bnx2_free_rx_skbs(struct bnx2 *bp)
 
                for (j = 0; j < bp->rx_max_ring_idx; j++) {
                        struct sw_bd *rx_buf = &rxr->rx_buf_ring[j];
-                       struct sk_buff *skb = rx_buf->skb;
+                       u8 *data = rx_buf->data;
 
-                       if (skb == NULL)
+                       if (data == NULL)
                                continue;
 
                        dma_unmap_single(&bp->pdev->dev,
@@ -5428,9 +5421,9 @@ bnx2_free_rx_skbs(struct bnx2 *bp)
                                         bp->rx_buf_use_size,
                                         PCI_DMA_FROMDEVICE);
 
-                       rx_buf->skb = NULL;
+                       rx_buf->data = NULL;
 
-                       dev_kfree_skb(skb);
+                       kfree(data);
                }
                for (j = 0; j < bp->rx_max_pg_ring_idx; j++)
                        bnx2_free_rx_page(bp, rxr, j);
@@ -5736,7 +5729,8 @@ static int
 bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
 {
        unsigned int pkt_size, num_pkts, i;
-       struct sk_buff *skb, *rx_skb;
+       struct sk_buff *skb;
+       u8 *data;
        unsigned char *packet;
        u16 rx_start_idx, rx_idx;
        dma_addr_t map;
@@ -5828,14 +5822,14 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
        }
 
        rx_buf = &rxr->rx_buf_ring[rx_start_idx];
-       rx_skb = rx_buf->skb;
+       data = rx_buf->data;
 
-       rx_hdr = rx_buf->desc;
-       skb_reserve(rx_skb, BNX2_RX_OFFSET);
+       rx_hdr = get_l2_fhdr(data);
+       data = (u8 *)rx_hdr + BNX2_RX_OFFSET;
 
        dma_sync_single_for_cpu(&bp->pdev->dev,
                dma_unmap_addr(rx_buf, mapping),
-               bp->rx_buf_size, PCI_DMA_FROMDEVICE);
+               bp->rx_buf_use_size, PCI_DMA_FROMDEVICE);
 
        if (rx_hdr->l2_fhdr_status &
                (L2_FHDR_ERRORS_BAD_CRC |
@@ -5852,7 +5846,7 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
        }
 
        for (i = 14; i < pkt_size; i++) {
-               if (*(rx_skb->data + i) != (unsigned char) (i & 0xff)) {
+               if (*(data + i) != (unsigned char) (i & 0xff)) {
                        goto loopback_test_done;
                }
        }
@@ -6873,10 +6867,10 @@ bnx2_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
        struct bnx2 *bp = netdev_priv(dev);
 
-       strcpy(info->driver, DRV_MODULE_NAME);
-       strcpy(info->version, DRV_MODULE_VERSION);
-       strcpy(info->bus_info, pci_name(bp->pdev));
-       strcpy(info->fw_version, bp->fw_version);
+       strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(bp->pdev), sizeof(info->bus_info));
+       strlcpy(info->fw_version, bp->fw_version, sizeof(info->fw_version));
 }
 
 #define BNX2_REGDUMP_LEN               (32 * 1024)
@@ -7571,8 +7565,8 @@ bnx2_set_phys_id(struct net_device *dev, enum ethtool_phys_id_state state)
        return 0;
 }
 
-static u32
-bnx2_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t
+bnx2_fix_features(struct net_device *dev, netdev_features_t features)
 {
        struct bnx2 *bp = netdev_priv(dev);
 
@@ -7583,7 +7577,7 @@ bnx2_fix_features(struct net_device *dev, u32 features)
 }
 
 static int
-bnx2_set_features(struct net_device *dev, u32 features)
+bnx2_set_features(struct net_device *dev, netdev_features_t features)
 {
        struct bnx2 *bp = netdev_priv(dev);
 
index 99d31a7..1db2d51 100644 (file)
@@ -6563,12 +6563,25 @@ struct l2_fhdr {
 #define MB_TX_CID_ADDR MB_GET_CID_ADDR(TX_CID)
 #define MB_RX_CID_ADDR MB_GET_CID_ADDR(RX_CID)
 
+/*
+ * This driver uses new build_skb() API :
+ * RX ring buffer contains pointer to kmalloc() data only,
+ * skb are built only after Hardware filled the frame.
+ */
 struct sw_bd {
-       struct sk_buff          *skb;
-       struct l2_fhdr          *desc;
+       u8                      *data;
        DEFINE_DMA_UNMAP_ADDR(mapping);
 };
 
+/* Its faster to compute this from data than storing it in sw_bd
+ * (less cache misses)
+ */
+static inline struct l2_fhdr *get_l2_fhdr(u8 *data)
+{
+       return (struct l2_fhdr *)(PTR_ALIGN(data, BNX2_RX_ALIGN) + NET_SKB_PAD);
+}
+
+
 struct sw_pg {
        struct page             *page;
        DEFINE_DMA_UNMAP_ADDR(mapping);
index aec7212..0f7b7a4 100644 (file)
@@ -23,8 +23,8 @@
  * (you will need to reboot afterwards) */
 /* #define BNX2X_STOP_ON_ERROR */
 
-#define DRV_MODULE_VERSION      "1.70.30-0"
-#define DRV_MODULE_RELDATE      "2011/10/25"
+#define DRV_MODULE_VERSION      "1.70.35-0"
+#define DRV_MODULE_RELDATE      "2011/11/10"
 #define BNX2X_BC_VER            0x040200
 
 #if defined(CONFIG_DCB)
@@ -293,8 +293,13 @@ enum {
 #define FCOE_TXQ_IDX(bp)       (MAX_ETH_TXQ_IDX(bp))
 
 /* fast path */
+/*
+ * This driver uses new build_skb() API :
+ * RX ring buffer contains pointer to kmalloc() data only,
+ * skb are built only after Hardware filled the frame.
+ */
 struct sw_rx_bd {
-       struct sk_buff  *skb;
+       u8              *data;
        DEFINE_DMA_UNMAP_ADDR(mapping);
 };
 
@@ -411,8 +416,7 @@ union db_prod {
 
 
 /* Number of u64 elements in SGE mask array */
-#define RX_SGE_MASK_LEN                        ((NUM_RX_SGE_PAGES * RX_SGE_CNT) / \
-                                        BIT_VEC64_ELEM_SZ)
+#define RX_SGE_MASK_LEN                        (NUM_RX_SGE / BIT_VEC64_ELEM_SZ)
 #define RX_SGE_MASK_LEN_MASK           (RX_SGE_MASK_LEN - 1)
 #define NEXT_SGE_MASK_ELEM(el)         (((el) + 1) & RX_SGE_MASK_LEN_MASK)
 
@@ -425,8 +429,8 @@ union host_hc_status_block {
 
 struct bnx2x_agg_info {
        /*
-        * First aggregation buffer is an skb, the following - are pages.
-        * We will preallocate the skbs for each aggregation when
+        * First aggregation buffer is a data buffer, the following - are pages.
+        * We will preallocate the data buffer for each aggregation when
         * we open the interface and will replace the BD at the consumer
         * with this one when we receive the TPA_START CQE in order to
         * keep the Rx BD ring consistent.
@@ -440,6 +444,7 @@ struct bnx2x_agg_info {
        u16                     parsing_flags;
        u16                     vlan_tag;
        u16                     len_on_bd;
+       u32                     rxhash;
 };
 
 #define Q_STATS_OFFSET32(stat_name) \
@@ -507,6 +512,7 @@ struct bnx2x_fastpath {
        __le16                  fp_hc_idx;
 
        u8                      index;          /* number in fp array */
+       u8                      rx_queue;       /* index for skb_record */
        u8                      cl_id;          /* eth client id */
        u8                      cl_qzone_id;
        u8                      fw_sb_id;       /* status block number in FW */
@@ -1141,6 +1147,7 @@ struct bnx2x_fw_stats_data {
 enum {
        BNX2X_SP_RTNL_SETUP_TC,
        BNX2X_SP_RTNL_TX_TIMEOUT,
+       BNX2X_SP_RTNL_FAN_FAILURE,
 };
 
 
@@ -1186,10 +1193,20 @@ struct bnx2x {
 #define ETH_MAX_JUMBO_PACKET_SIZE      9600
 
        /* Max supported alignment is 256 (8 shift) */
-#define BNX2X_RX_ALIGN_SHIFT           ((L1_CACHE_SHIFT < 8) ? \
-                                        L1_CACHE_SHIFT : 8)
-       /* FW use 2 Cache lines Alignment for start packet and size  */
-#define BNX2X_FW_RX_ALIGN              (2 << BNX2X_RX_ALIGN_SHIFT)
+#define BNX2X_RX_ALIGN_SHIFT           min(8, L1_CACHE_SHIFT)
+
+       /* FW uses 2 Cache lines Alignment for start packet and size
+        *
+        * We assume skb_build() uses sizeof(struct skb_shared_info) bytes
+        * at the end of skb->data, to avoid wasting a full cache line.
+        * This reduces memory use (skb->truesize).
+        */
+#define BNX2X_FW_RX_ALIGN_START        (1UL << BNX2X_RX_ALIGN_SHIFT)
+
+#define BNX2X_FW_RX_ALIGN_END                                  \
+       max(1UL << BNX2X_RX_ALIGN_SHIFT,                        \
+           SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
+
 #define BNX2X_PXP_DRAM_ALIGN           (BNX2X_RX_ALIGN_SHIFT - 5)
 
        struct host_sp_status_block *def_status_blk;
@@ -1984,13 +2001,6 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
 #define HW_PRTY_ASSERT_SET_4 (AEU_INPUTS_ATTN_BITS_PGLUE_PARITY_ERROR | \
                              AEU_INPUTS_ATTN_BITS_ATC_PARITY_ERROR)
 
-#define RSS_FLAGS(bp) \
-               (TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_CAPABILITY | \
-                TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_TCP_CAPABILITY | \
-                TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_CAPABILITY | \
-                TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_TCP_CAPABILITY | \
-                (bp->multi_mode << \
-                 TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_MODE_SHIFT))
 #define MULTI_MASK                     0x7f
 
 
@@ -2055,6 +2065,8 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
 #define BNX2X_VPD_LEN                  128
 #define VENDOR_ID_LEN                  4
 
+int bnx2x_close(struct net_device *dev);
+
 /* Congestion management fairness mode */
 #define CMNG_FNS_NONE          0
 #define CMNG_FNS_MINMAX                1
index 580b44e..8336c78 100644 (file)
@@ -79,19 +79,21 @@ static inline void bnx2x_bz_fp(struct bnx2x *bp, int index)
  * @to:                destination FP index
  *
  * Makes sure the contents of the bp->fp[to].napi is kept
- * intact.
+ * intact. This is done by first copying the napi struct from
+ * the target to the source, and then mem copying the entire
+ * source onto the target
  */
 static inline void bnx2x_move_fp(struct bnx2x *bp, int from, int to)
 {
        struct bnx2x_fastpath *from_fp = &bp->fp[from];
        struct bnx2x_fastpath *to_fp = &bp->fp[to];
-       struct napi_struct orig_napi = to_fp->napi;
+
+       /* Copy the NAPI object as it has been already initialized */
+       from_fp->napi = to_fp->napi;
+
        /* Move bnx2x_fastpath contents */
        memcpy(to_fp, from_fp, sizeof(*to_fp));
        to_fp->index = to;
-
-       /* Restore the NAPI object as it has been already initialized */
-       to_fp->napi = orig_napi;
 }
 
 int load_count[2][3] = { {0} }; /* per-path: 0-common, 1-port0, 2-port1 */
@@ -292,8 +294,21 @@ static void bnx2x_update_sge_prod(struct bnx2x_fastpath *fp,
           fp->last_max_sge, fp->rx_sge_prod);
 }
 
+/* Set Toeplitz hash value in the skb using the value from the
+ * CQE (calculated by HW).
+ */
+static u32 bnx2x_get_rxhash(const struct bnx2x *bp,
+                           const struct eth_fast_path_rx_cqe *cqe)
+{
+       /* Set Toeplitz hash from CQE */
+       if ((bp->dev->features & NETIF_F_RXHASH) &&
+           (cqe->status_flags & ETH_FAST_PATH_RX_CQE_RSS_HASH_FLG))
+               return le32_to_cpu(cqe->rss_hash_result);
+       return 0;
+}
+
 static void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue,
-                           struct sk_buff *skb, u16 cons, u16 prod,
+                           u16 cons, u16 prod,
                            struct eth_fast_path_rx_cqe *cqe)
 {
        struct bnx2x *bp = fp->bp;
@@ -308,9 +323,9 @@ static void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue,
        if (tpa_info->tpa_state != BNX2X_TPA_STOP)
                BNX2X_ERR("start of bin not in stop [%d]\n", queue);
 
-       /* Try to map an empty skb from the aggregation info  */
+       /* Try to map an empty data buffer from the aggregation info  */
        mapping = dma_map_single(&bp->pdev->dev,
-                                first_buf->skb->data,
+                                first_buf->data + NET_SKB_PAD,
                                 fp->rx_buf_size, DMA_FROM_DEVICE);
        /*
         *  ...if it fails - move the skb from the consumer to the producer
@@ -320,15 +335,15 @@ static void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue,
 
        if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) {
                /* Move the BD from the consumer to the producer */
-               bnx2x_reuse_rx_skb(fp, cons, prod);
+               bnx2x_reuse_rx_data(fp, cons, prod);
                tpa_info->tpa_state = BNX2X_TPA_ERROR;
                return;
        }
 
-       /* move empty skb from pool to prod */
-       prod_rx_buf->skb = first_buf->skb;
+       /* move empty data from pool to prod */
+       prod_rx_buf->data = first_buf->data;
        dma_unmap_addr_set(prod_rx_buf, mapping, mapping);
-       /* point prod_bd to new skb */
+       /* point prod_bd to new data */
        prod_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
        prod_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
 
@@ -342,6 +357,7 @@ static void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue,
        tpa_info->tpa_state = BNX2X_TPA_START;
        tpa_info->len_on_bd = le16_to_cpu(cqe->len_on_bd);
        tpa_info->placement_offset = cqe->placement_offset;
+       tpa_info->rxhash = bnx2x_get_rxhash(bp, cqe);
 
 #ifdef BNX2X_STOP_ON_ERROR
        fp->tpa_queue_used |= (1 << queue);
@@ -469,11 +485,12 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
 {
        struct bnx2x_agg_info *tpa_info = &fp->tpa_info[queue];
        struct sw_rx_bd *rx_buf = &tpa_info->first_buf;
-       u8 pad = tpa_info->placement_offset;
+       u32 pad = tpa_info->placement_offset;
        u16 len = tpa_info->len_on_bd;
-       struct sk_buff *skb = rx_buf->skb;
+       struct sk_buff *skb = NULL;
+       u8 *data = rx_buf->data;
        /* alloc new skb */
-       struct sk_buff *new_skb;
+       u8 *new_data;
        u8 old_tpa_state = tpa_info->tpa_state;
 
        tpa_info->tpa_state = BNX2X_TPA_STOP;
@@ -484,18 +501,18 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
        if (old_tpa_state == BNX2X_TPA_ERROR)
                goto drop;
 
-       /* Try to allocate the new skb */
-       new_skb = netdev_alloc_skb(bp->dev, fp->rx_buf_size);
+       /* Try to allocate the new data */
+       new_data = kmalloc(fp->rx_buf_size + NET_SKB_PAD, GFP_ATOMIC);
 
        /* Unmap skb in the pool anyway, as we are going to change
           pool entry status to BNX2X_TPA_STOP even if new skb allocation
           fails. */
        dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(rx_buf, mapping),
                         fp->rx_buf_size, DMA_FROM_DEVICE);
+       if (likely(new_data))
+               skb = build_skb(data);
 
-       if (likely(new_skb)) {
-               prefetch(skb);
-               prefetch(((char *)(skb)) + L1_CACHE_BYTES);
+       if (likely(skb)) {
 
 #ifdef BNX2X_STOP_ON_ERROR
                if (pad + len > fp->rx_buf_size) {
@@ -507,8 +524,9 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
                }
 #endif
 
-               skb_reserve(skb, pad);
+               skb_reserve(skb, pad + NET_SKB_PAD);
                skb_put(skb, len);
+               skb->rxhash = tpa_info->rxhash;
 
                skb->protocol = eth_type_trans(skb, bp->dev);
                skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -524,8 +542,8 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
                }
 
 
-               /* put new skb in bin */
-               rx_buf->skb = new_skb;
+               /* put new data in bin */
+               rx_buf->data = new_data;
 
                return;
        }
@@ -537,19 +555,6 @@ drop:
        fp->eth_q_stats.rx_skb_alloc_failed++;
 }
 
-/* Set Toeplitz hash value in the skb using the value from the
- * CQE (calculated by HW).
- */
-static inline void bnx2x_set_skb_rxhash(struct bnx2x *bp, union eth_rx_cqe *cqe,
-                                       struct sk_buff *skb)
-{
-       /* Set Toeplitz hash from CQE */
-       if ((bp->dev->features & NETIF_F_RXHASH) &&
-           (cqe->fast_path_cqe.status_flags &
-            ETH_FAST_PATH_RX_CQE_RSS_HASH_FLG))
-               skb->rxhash =
-               le32_to_cpu(cqe->fast_path_cqe.rss_hash_result);
-}
 
 int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
 {
@@ -592,6 +597,7 @@ int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
                u8 cqe_fp_flags;
                enum eth_rx_cqe_type cqe_fp_type;
                u16 len, pad;
+               u8 *data;
 
 #ifdef BNX2X_STOP_ON_ERROR
                if (unlikely(bp->panic))
@@ -602,13 +608,6 @@ int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
                bd_prod = RX_BD(bd_prod);
                bd_cons = RX_BD(bd_cons);
 
-               /* Prefetch the page containing the BD descriptor
-                  at producer's index. It will be needed when new skb is
-                  allocated */
-               prefetch((void *)(PAGE_ALIGN((unsigned long)
-                                            (&fp->rx_desc_ring[bd_prod])) -
-                                 PAGE_SIZE + 1));
-
                cqe = &fp->rx_comp_ring[comp_ring_cons];
                cqe_fp = &cqe->fast_path_cqe;
                cqe_fp_flags = cqe_fp->type_error_flags;
@@ -624,125 +623,110 @@ int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
                if (unlikely(CQE_TYPE_SLOW(cqe_fp_type))) {
                        bnx2x_sp_event(fp, cqe);
                        goto next_cqe;
+               }
+               rx_buf = &fp->rx_buf_ring[bd_cons];
+               data = rx_buf->data;
 
-               /* this is an rx packet */
-               } else {
-                       rx_buf = &fp->rx_buf_ring[bd_cons];
-                       skb = rx_buf->skb;
-                       prefetch(skb);
-
-                       if (!CQE_TYPE_FAST(cqe_fp_type)) {
+               if (!CQE_TYPE_FAST(cqe_fp_type)) {
 #ifdef BNX2X_STOP_ON_ERROR
-                               /* sanity check */
-                               if (fp->disable_tpa &&
-                                   (CQE_TYPE_START(cqe_fp_type) ||
-                                    CQE_TYPE_STOP(cqe_fp_type)))
-                                       BNX2X_ERR("START/STOP packet while "
-                                                 "disable_tpa type %x\n",
-                                                 CQE_TYPE(cqe_fp_type));
+                       /* sanity check */
+                       if (fp->disable_tpa &&
+                           (CQE_TYPE_START(cqe_fp_type) ||
+                            CQE_TYPE_STOP(cqe_fp_type)))
+                               BNX2X_ERR("START/STOP packet while "
+                                         "disable_tpa type %x\n",
+                                         CQE_TYPE(cqe_fp_type));
 #endif
 
-                               if (CQE_TYPE_START(cqe_fp_type)) {
-                                       u16 queue = cqe_fp->queue_index;
-                                       DP(NETIF_MSG_RX_STATUS,
-                                          "calling tpa_start on queue %d\n",
-                                          queue);
-
-                                       bnx2x_tpa_start(fp, queue, skb,
-                                                       bd_cons, bd_prod,
-                                                       cqe_fp);
-
-                                       /* Set Toeplitz hash for LRO skb */
-                                       bnx2x_set_skb_rxhash(bp, cqe, skb);
+                       if (CQE_TYPE_START(cqe_fp_type)) {
+                               u16 queue = cqe_fp->queue_index;
+                               DP(NETIF_MSG_RX_STATUS,
+                                  "calling tpa_start on queue %d\n",
+                                  queue);
 
-                                       goto next_rx;
-
-                               } else {
-                                       u16 queue =
-                                               cqe->end_agg_cqe.queue_index;
-                                       DP(NETIF_MSG_RX_STATUS,
-                                          "calling tpa_stop on queue %d\n",
-                                          queue);
-
-                                       bnx2x_tpa_stop(bp, fp, queue,
-                                                      &cqe->end_agg_cqe,
-                                                      comp_ring_cons);
+                               bnx2x_tpa_start(fp, queue,
+                                               bd_cons, bd_prod,
+                                               cqe_fp);
+                               goto next_rx;
+                       } else {
+                               u16 queue =
+                                       cqe->end_agg_cqe.queue_index;
+                               DP(NETIF_MSG_RX_STATUS,
+                                  "calling tpa_stop on queue %d\n",
+                                  queue);
+
+                               bnx2x_tpa_stop(bp, fp, queue,
+                                              &cqe->end_agg_cqe,
+                                              comp_ring_cons);
 #ifdef BNX2X_STOP_ON_ERROR
-                                       if (bp->panic)
-                                               return 0;
+                               if (bp->panic)
+                                       return 0;
 #endif
 
-                                       bnx2x_update_sge_prod(fp, cqe_fp);
-                                       goto next_cqe;
-                               }
+                               bnx2x_update_sge_prod(fp, cqe_fp);
+                               goto next_cqe;
                        }
-                       /* non TPA */
-                       len = le16_to_cpu(cqe_fp->pkt_len);
-                       pad = cqe_fp->placement_offset;
-                       dma_sync_single_for_cpu(&bp->pdev->dev,
+               }
+               /* non TPA */
+               len = le16_to_cpu(cqe_fp->pkt_len);
+               pad = cqe_fp->placement_offset;
+               dma_sync_single_for_cpu(&bp->pdev->dev,
                                        dma_unmap_addr(rx_buf, mapping),
-                                                      pad + RX_COPY_THRESH,
-                                                      DMA_FROM_DEVICE);
-                       prefetch(((char *)(skb)) + L1_CACHE_BYTES);
+                                       pad + RX_COPY_THRESH,
+                                       DMA_FROM_DEVICE);
+               pad += NET_SKB_PAD;
+               prefetch(data + pad); /* speedup eth_type_trans() */
+               /* is this an error packet? */
+               if (unlikely(cqe_fp_flags & ETH_RX_ERROR_FALGS)) {
+                       DP(NETIF_MSG_RX_ERR,
+                          "ERROR  flags %x  rx packet %u\n",
+                          cqe_fp_flags, sw_comp_cons);
+                       fp->eth_q_stats.rx_err_discard_pkt++;
+                       goto reuse_rx;
+               }
 
-                       /* is this an error packet? */
-                       if (unlikely(cqe_fp_flags & ETH_RX_ERROR_FALGS)) {
+               /* Since we don't have a jumbo ring
+                * copy small packets if mtu > 1500
+                */
+               if ((bp->dev->mtu > ETH_MAX_PACKET_SIZE) &&
+                   (len <= RX_COPY_THRESH)) {
+                       skb = netdev_alloc_skb_ip_align(bp->dev, len);
+                       if (skb == NULL) {
                                DP(NETIF_MSG_RX_ERR,
-                                  "ERROR  flags %x  rx packet %u\n",
-                                  cqe_fp_flags, sw_comp_cons);
-                               fp->eth_q_stats.rx_err_discard_pkt++;
+                                  "ERROR  packet dropped because of alloc failure\n");
+                               fp->eth_q_stats.rx_skb_alloc_failed++;
                                goto reuse_rx;
                        }
-
-                       /* Since we don't have a jumbo ring
-                        * copy small packets if mtu > 1500
-                        */
-                       if ((bp->dev->mtu > ETH_MAX_PACKET_SIZE) &&
-                           (len <= RX_COPY_THRESH)) {
-                               struct sk_buff *new_skb;
-
-                               new_skb = netdev_alloc_skb(bp->dev, len + pad);
-                               if (new_skb == NULL) {
-                                       DP(NETIF_MSG_RX_ERR,
-                                          "ERROR  packet dropped "
-                                          "because of alloc failure\n");
-                                       fp->eth_q_stats.rx_skb_alloc_failed++;
-                                       goto reuse_rx;
-                               }
-
-                               /* aligned copy */
-                               skb_copy_from_linear_data_offset(skb, pad,
-                                                   new_skb->data + pad, len);
-                               skb_reserve(new_skb, pad);
-                               skb_put(new_skb, len);
-
-                               bnx2x_reuse_rx_skb(fp, bd_cons, bd_prod);
-
-                               skb = new_skb;
-
-                       } else
-                       if (likely(bnx2x_alloc_rx_skb(bp, fp, bd_prod) == 0)) {
+                       memcpy(skb->data, data + pad, len);
+                       bnx2x_reuse_rx_data(fp, bd_cons, bd_prod);
+               } else {
+                       if (likely(bnx2x_alloc_rx_data(bp, fp, bd_prod) == 0)) {
                                dma_unmap_single(&bp->pdev->dev,
-                                       dma_unmap_addr(rx_buf, mapping),
+                                                dma_unmap_addr(rx_buf, mapping),
                                                 fp->rx_buf_size,
                                                 DMA_FROM_DEVICE);
+                               skb = build_skb(data);
+                               if (unlikely(!skb)) {
+                                       kfree(data);
+                                       fp->eth_q_stats.rx_skb_alloc_failed++;
+                                       goto next_rx;
+                               }
                                skb_reserve(skb, pad);
-                               skb_put(skb, len);
-
                        } else {
                                DP(NETIF_MSG_RX_ERR,
                                   "ERROR  packet dropped because "
                                   "of alloc failure\n");
                                fp->eth_q_stats.rx_skb_alloc_failed++;
 reuse_rx:
-                               bnx2x_reuse_rx_skb(fp, bd_cons, bd_prod);
+                               bnx2x_reuse_rx_data(fp, bd_cons, bd_prod);
                                goto next_rx;
                        }
 
+                       skb_put(skb, len);
                        skb->protocol = eth_type_trans(skb, bp->dev);
 
                        /* Set Toeplitz hash for a none-LRO skb */
-                       bnx2x_set_skb_rxhash(bp, cqe, skb);
+                       skb->rxhash = bnx2x_get_rxhash(bp, cqe_fp);
 
                        skb_checksum_none_assert(skb);
 
@@ -755,7 +739,7 @@ reuse_rx:
                        }
                }
 
-               skb_record_rx_queue(skb, fp->index);
+               skb_record_rx_queue(skb, fp->rx_queue);
 
                if (le16_to_cpu(cqe_fp->pars_flags.flags) &
                    PARSING_FLAGS_VLAN)
@@ -765,7 +749,7 @@ reuse_rx:
 
 
 next_rx:
-               rx_buf->skb = NULL;
+               rx_buf->data = NULL;
 
                bd_cons = NEXT_RX_IDX(bd_cons);
                bd_prod = NEXT_RX_IDX(bd_prod);
@@ -1011,9 +995,9 @@ void bnx2x_init_rx_rings(struct bnx2x *bp)
                                struct sw_rx_bd *first_buf =
                                        &tpa_info->first_buf;
 
-                               first_buf->skb = netdev_alloc_skb(bp->dev,
-                                                      fp->rx_buf_size);
-                               if (!first_buf->skb) {
+                               first_buf->data = kmalloc(fp->rx_buf_size + NET_SKB_PAD,
+                                                         GFP_ATOMIC);
+                               if (!first_buf->data) {
                                        BNX2X_ERR("Failed to allocate TPA "
                                                  "skb pool for queue[%d] - "
                                                  "disabling TPA on this "
@@ -1094,13 +1078,11 @@ static void bnx2x_free_tx_skbs(struct bnx2x *bp)
                for_each_cos_in_tx_queue(fp, cos) {
                        struct bnx2x_fp_txdata *txdata = &fp->txdata[cos];
 
-                       u16 bd_cons = txdata->tx_bd_cons;
                        u16 sw_prod = txdata->tx_pkt_prod;
                        u16 sw_cons = txdata->tx_pkt_cons;
 
                        while (sw_cons != sw_prod) {
-                               bd_cons = bnx2x_free_tx_pkt(bp, txdata,
-                                                           TX_BD(sw_cons));
+                               bnx2x_free_tx_pkt(bp, txdata, TX_BD(sw_cons));
                                sw_cons++;
                        }
                }
@@ -1118,16 +1100,16 @@ static void bnx2x_free_rx_bds(struct bnx2x_fastpath *fp)
 
        for (i = 0; i < NUM_RX_BD; i++) {
                struct sw_rx_bd *rx_buf = &fp->rx_buf_ring[i];
-               struct sk_buff *skb = rx_buf->skb;
+               u8 *data = rx_buf->data;
 
-               if (skb == NULL)
+               if (data == NULL)
                        continue;
                dma_unmap_single(&bp->pdev->dev,
                                 dma_unmap_addr(rx_buf, mapping),
                                 fp->rx_buf_size, DMA_FROM_DEVICE);
 
-               rx_buf->skb = NULL;
-               dev_kfree_skb(skb);
+               rx_buf->data = NULL;
+               kfree(data);
        }
 }
 
@@ -1509,6 +1491,7 @@ static inline void bnx2x_set_rx_buf_size(struct bnx2x *bp)
 
        for_each_queue(bp, i) {
                struct bnx2x_fastpath *fp = &bp->fp[i];
+               u32 mtu;
 
                /* Always use a mini-jumbo MTU for the FCoE L2 ring */
                if (IS_FCOE_IDX(i))
@@ -1518,13 +1501,15 @@ static inline void bnx2x_set_rx_buf_size(struct bnx2x *bp)
                         * IP_HEADER_ALIGNMENT_PADDING to prevent a buffer
                         * overrun attack.
                         */
-                       fp->rx_buf_size =
-                               BNX2X_FCOE_MINI_JUMBO_MTU + ETH_OVREHEAD +
-                               BNX2X_FW_RX_ALIGN + IP_HEADER_ALIGNMENT_PADDING;
+                       mtu = BNX2X_FCOE_MINI_JUMBO_MTU;
                else
-                       fp->rx_buf_size =
-                               bp->dev->mtu + ETH_OVREHEAD +
-                               BNX2X_FW_RX_ALIGN + IP_HEADER_ALIGNMENT_PADDING;
+                       mtu = bp->dev->mtu;
+               fp->rx_buf_size = BNX2X_FW_RX_ALIGN_START +
+                                 IP_HEADER_ALIGNMENT_PADDING +
+                                 ETH_OVREHEAD +
+                                 mtu +
+                                 BNX2X_FW_RX_ALIGN_END;
+               /* Note : rx_buf_size doesnt take into account NET_SKB_PAD */
        }
 }
 
@@ -1929,13 +1914,17 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
                break;
        }
 
-       if (!bp->port.pmf)
+       if (bp->port.pmf)
+               bnx2x_update_drv_flags(bp, DRV_FLAGS_DCB_CONFIGURED, 0);
+       else
                bnx2x__link_status_update(bp);
 
        /* start the timer */
        mod_timer(&bp->timer, jiffies + bp->current_interval);
 
 #ifdef BCM_CNIC
+       /* re-read iscsi info */
+       bnx2x_get_iscsi_info(bp);
        bnx2x_setup_cnic_irq_info(bp);
        if (bp->state == BNX2X_STATE_OPEN)
                bnx2x_cnic_notify(bp, CNIC_CTL_START_CMD);
@@ -3409,7 +3398,8 @@ int bnx2x_change_mtu(struct net_device *dev, int new_mtu)
        return bnx2x_reload_if_running(dev);
 }
 
-u32 bnx2x_fix_features(struct net_device *dev, u32 features)
+netdev_features_t bnx2x_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        struct bnx2x *bp = netdev_priv(dev);
 
@@ -3420,7 +3410,7 @@ u32 bnx2x_fix_features(struct net_device *dev, u32 features)
        return features;
 }
 
-int bnx2x_set_features(struct net_device *dev, u32 features)
+int bnx2x_set_features(struct net_device *dev, netdev_features_t features)
 {
        struct bnx2x *bp = netdev_priv(dev);
        u32 flags = bp->flags;
index 283d663..80c5ed0 100644 (file)
@@ -533,8 +533,9 @@ int bnx2x_change_mtu(struct net_device *dev, int new_mtu);
  */
 int bnx2x_fcoe_get_wwn(struct net_device *dev, u64 *wwn, int type);
 #endif
-u32 bnx2x_fix_features(struct net_device *dev, u32 features);
-int bnx2x_set_features(struct net_device *dev, u32 features);
+netdev_features_t bnx2x_fix_features(struct net_device *dev,
+       netdev_features_t features);
+int bnx2x_set_features(struct net_device *dev, netdev_features_t features);
 
 /**
  * bnx2x_tx_timeout - tx timeout netdev callback
@@ -874,8 +875,7 @@ static inline void bnx2x_clear_sge_mask_next_elems(struct bnx2x_fastpath *fp)
 static inline void bnx2x_init_sge_ring_bit_mask(struct bnx2x_fastpath *fp)
 {
        /* Set the mask to all 1-s: it's faster to compare to 0 than to 0xf-s */
-       memset(fp->sge_mask, 0xff,
-              (NUM_RX_SGE >> BIT_VEC64_ELEM_SHIFT)*sizeof(u64));
+       memset(fp->sge_mask, 0xff, sizeof(fp->sge_mask));
 
        /* Clear the two last indices in the page to 1:
           these are the indices that correspond to the "next" element,
@@ -911,26 +911,27 @@ static inline int bnx2x_alloc_rx_sge(struct bnx2x *bp,
        return 0;
 }
 
-static inline int bnx2x_alloc_rx_skb(struct bnx2x *bp,
-                                    struct bnx2x_fastpath *fp, u16 index)
+static inline int bnx2x_alloc_rx_data(struct bnx2x *bp,
+                                     struct bnx2x_fastpath *fp, u16 index)
 {
-       struct sk_buff *skb;
+       u8 *data;
        struct sw_rx_bd *rx_buf = &fp->rx_buf_ring[index];
        struct eth_rx_bd *rx_bd = &fp->rx_desc_ring[index];
        dma_addr_t mapping;
 
-       skb = netdev_alloc_skb(bp->dev, fp->rx_buf_size);
-       if (unlikely(skb == NULL))
+       data = kmalloc(fp->rx_buf_size + NET_SKB_PAD, GFP_ATOMIC);
+       if (unlikely(data == NULL))
                return -ENOMEM;
 
-       mapping = dma_map_single(&bp->pdev->dev, skb->data, fp->rx_buf_size,
+       mapping = dma_map_single(&bp->pdev->dev, data + NET_SKB_PAD,
+                                fp->rx_buf_size,
                                 DMA_FROM_DEVICE);
        if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) {
-               dev_kfree_skb_any(skb);
+               kfree(data);
                return -ENOMEM;
        }
 
-       rx_buf->skb = skb;
+       rx_buf->data = data;
        dma_unmap_addr_set(rx_buf, mapping, mapping);
 
        rx_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
@@ -939,12 +940,12 @@ static inline int bnx2x_alloc_rx_skb(struct bnx2x *bp,
        return 0;
 }
 
-/* note that we are not allocating a new skb,
+/* note that we are not allocating a new buffer,
  * we are just moving one from cons to prod
  * we are not creating a new mapping,
  * so there is no need to check for dma_mapping_error().
  */
-static inline void bnx2x_reuse_rx_skb(struct bnx2x_fastpath *fp,
+static inline void bnx2x_reuse_rx_data(struct bnx2x_fastpath *fp,
                                      u16 cons, u16 prod)
 {
        struct sw_rx_bd *cons_rx_buf = &fp->rx_buf_ring[cons];
@@ -954,7 +955,7 @@ static inline void bnx2x_reuse_rx_skb(struct bnx2x_fastpath *fp,
 
        dma_unmap_addr_set(prod_rx_buf, mapping,
                           dma_unmap_addr(cons_rx_buf, mapping));
-       prod_rx_buf->skb = cons_rx_buf->skb;
+       prod_rx_buf->data = cons_rx_buf->data;
        *prod_bd = *cons_bd;
 }
 
@@ -1030,9 +1031,9 @@ static inline void bnx2x_free_tpa_pool(struct bnx2x *bp,
        for (i = 0; i < last; i++) {
                struct bnx2x_agg_info *tpa_info = &fp->tpa_info[i];
                struct sw_rx_bd *first_buf = &tpa_info->first_buf;
-               struct sk_buff *skb = first_buf->skb;
+               u8 *data = first_buf->data;
 
-               if (skb == NULL) {
+               if (data == NULL) {
                        DP(NETIF_MSG_IFDOWN, "tpa bin %d empty on free\n", i);
                        continue;
                }
@@ -1040,8 +1041,8 @@ static inline void bnx2x_free_tpa_pool(struct bnx2x *bp,
                        dma_unmap_single(&bp->pdev->dev,
                                         dma_unmap_addr(first_buf, mapping),
                                         fp->rx_buf_size, DMA_FROM_DEVICE);
-               dev_kfree_skb(skb);
-               first_buf->skb = NULL;
+               kfree(data);
+               first_buf->data = NULL;
        }
 }
 
@@ -1149,7 +1150,7 @@ static inline int bnx2x_alloc_rx_bds(struct bnx2x_fastpath *fp,
         * fp->eth_q_stats.rx_skb_alloc_failed = 0
         */
        for (i = 0; i < rx_ring_size; i++) {
-               if (bnx2x_alloc_rx_skb(bp, fp, ring_prod) < 0) {
+               if (bnx2x_alloc_rx_data(bp, fp, ring_prod) < 0) {
                        fp->eth_q_stats.rx_skb_alloc_failed++;
                        continue;
                }
@@ -1318,6 +1319,7 @@ static inline void bnx2x_init_fcoe_fp(struct bnx2x *bp)
        struct bnx2x_fastpath *fp = bnx2x_fcoe_fp(bp);
        unsigned long q_type = 0;
 
+       bnx2x_fcoe(bp, rx_queue) = BNX2X_NUM_ETH_QUEUES(bp);
        bnx2x_fcoe(bp, cl_id) = bnx2x_cnic_eth_cl_id(bp,
                                                     BNX2X_FCOE_ETH_CL_ID_IDX);
        /** Current BNX2X_FCOE_ETH_CID deffinition implies not more than
@@ -1488,4 +1490,68 @@ static inline u16 bnx2x_extract_max_cfg(struct bnx2x *bp, u32 mf_cfg)
        return max_cfg;
 }
 
+#ifdef BCM_CNIC
+/**
+ * bnx2x_get_iscsi_info - update iSCSI params according to licensing info.
+ *
+ * @bp:                driver handle
+ *
+ */
+void bnx2x_get_iscsi_info(struct bnx2x *bp);
+#endif
+
+/* returns func by VN for current port */
+static inline int func_by_vn(struct bnx2x *bp, int vn)
+{
+       return 2 * vn + BP_PORT(bp);
+}
+
+/**
+ * bnx2x_link_sync_notify - send notification to other functions.
+ *
+ * @bp:                driver handle
+ *
+ */
+static inline void bnx2x_link_sync_notify(struct bnx2x *bp)
+{
+       int func;
+       int vn;
+
+       /* Set the attention towards other drivers on the same port */
+       for (vn = VN_0; vn < BP_MAX_VN_NUM(bp); vn++) {
+               if (vn == BP_VN(bp))
+                       continue;
+
+               func = func_by_vn(bp, vn);
+               REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_0 +
+                      (LINK_SYNC_ATTENTION_BIT_FUNC_0 + func)*4, 1);
+       }
+}
+
+/**
+ * bnx2x_update_drv_flags - update flags in shmem
+ *
+ * @bp:                driver handle
+ * @flags:     flags to update
+ * @set:       set or clear
+ *
+ */
+static inline void bnx2x_update_drv_flags(struct bnx2x *bp, u32 flags, u32 set)
+{
+       if (SHMEM2_HAS(bp, drv_flags)) {
+               u32 drv_flags;
+               bnx2x_acquire_hw_lock(bp, HW_LOCK_DRV_FLAGS);
+               drv_flags = SHMEM2_RD(bp, drv_flags);
+
+               if (set)
+                       SET_FLAGS(drv_flags, flags);
+               else
+                       RESET_FLAGS(drv_flags, flags);
+
+               SHMEM2_WR(bp, drv_flags, drv_flags);
+               DP(NETIF_MSG_HW, "drv_flags 0x%08x\n", drv_flags);
+               bnx2x_release_hw_lock(bp, HW_LOCK_DRV_FLAGS);
+       }
+}
+
 #endif /* BNX2X_CMN_H */
index 51bd748..5051cf3 100644 (file)
@@ -685,24 +685,6 @@ int bnx2x_dcbnl_update_applist(struct bnx2x *bp, bool delall)
 }
 #endif
 
-static inline void bnx2x_update_drv_flags(struct bnx2x *bp, u32 flags, u32 set)
-{
-       if (SHMEM2_HAS(bp, drv_flags)) {
-               u32 drv_flags;
-               bnx2x_acquire_hw_lock(bp, HW_LOCK_DRV_FLAGS);
-               drv_flags = SHMEM2_RD(bp, drv_flags);
-
-               if (set)
-                       SET_FLAGS(drv_flags, flags);
-               else
-                       RESET_FLAGS(drv_flags, flags);
-
-               SHMEM2_WR(bp, drv_flags, drv_flags);
-               DP(NETIF_MSG_HW, "drv_flags 0x%08x\n", drv_flags);
-               bnx2x_release_hw_lock(bp, HW_LOCK_DRV_FLAGS);
-       }
-}
-
 static inline void bnx2x_dcbx_update_tc_mapping(struct bnx2x *bp)
 {
        u8 prio, cos;
@@ -755,18 +737,26 @@ void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state)
                        /* mark DCBX result for PMF migration */
                        bnx2x_update_drv_flags(bp, DRV_FLAGS_DCB_CONFIGURED, 1);
 #ifdef BCM_DCBNL
-                       /**
+                       /*
                         * Add new app tlvs to dcbnl
                         */
                        bnx2x_dcbnl_update_applist(bp, false);
 #endif
-                       bnx2x_dcbx_stop_hw_tx(bp);
-
-                       /* reconfigure the netdevice with the results of the new
+                       /*
+                        * reconfigure the netdevice with the results of the new
                         * dcbx negotiation.
                         */
                        bnx2x_dcbx_update_tc_mapping(bp);
 
+                       /*
+                        * allow other funtions to update their netdevices
+                        * accordingly
+                        */
+                       if (IS_MF(bp))
+                               bnx2x_link_sync_notify(bp);
+
+                       bnx2x_dcbx_stop_hw_tx(bp);
+
                        return;
                }
        case BNX2X_DCBX_STATE_TX_PAUSED:
@@ -775,6 +765,7 @@ void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state)
 
                bnx2x_dcbx_update_ets_params(bp);
                bnx2x_dcbx_resume_hw_tx(bp);
+
                return;
        case BNX2X_DCBX_STATE_TX_RELEASED:
                DP(NETIF_MSG_LINK, "BNX2X_DCBX_STATE_TX_RELEASED\n");
@@ -883,7 +874,7 @@ static void bnx2x_dcbx_admin_mib_updated_params(struct bnx2x *bp,
                /*For IEEE admin_recommendation_bw_precentage
                 *For IEEE admin_recommendation_ets_pg */
                af->pfc.pri_en_bitmap = (u8)dp->admin_pfc_bitmap;
-               for (i = 0; i < 4; i++) {
+               for (i = 0; i < DCBX_CONFIG_MAX_APP_PROTOCOL; i++) {
                        if (dp->admin_priority_app_table[i].valid) {
                                struct bnx2x_admin_priority_app_table *table =
                                        dp->admin_priority_app_table;
@@ -923,7 +914,7 @@ static void bnx2x_dcbx_admin_mib_updated_params(struct bnx2x *bp,
 
 void bnx2x_dcbx_set_state(struct bnx2x *bp, bool dcb_on, u32 dcbx_enabled)
 {
-       if (!CHIP_IS_E1x(bp) && !CHIP_IS_E3(bp)) {
+       if (!CHIP_IS_E1x(bp)) {
                bp->dcb_state = dcb_on;
                bp->dcbx_enabled = dcbx_enabled;
        } else {
@@ -1863,7 +1854,7 @@ static void bnx2x_dcbx_fw_struct(struct bnx2x *bp,
 void bnx2x_dcbx_pmf_update(struct bnx2x *bp)
 {
        /* if we need to syncronize DCBX result from prev PMF
-        * read it from shmem and update bp accordingly
+        * read it from shmem and update bp and netdev accordingly
         */
        if (SHMEM2_HAS(bp, drv_flags) &&
           GET_FLAGS(SHMEM2_RD(bp, drv_flags), DRV_FLAGS_DCB_CONFIGURED)) {
@@ -1875,6 +1866,22 @@ void bnx2x_dcbx_pmf_update(struct bnx2x *bp)
                                          bp->dcbx_error);
                bnx2x_get_dcbx_drv_param(bp, &bp->dcbx_local_feat,
                                         bp->dcbx_error);
+#ifdef BCM_DCBNL
+               /*
+                * Add new app tlvs to dcbnl
+                */
+               bnx2x_dcbnl_update_applist(bp, false);
+               /*
+                * Send a notification for the new negotiated parameters
+                */
+               dcbnl_cee_notify(bp->dev, RTM_GETDCB, DCB_CMD_CEE_GET, 0, 0);
+#endif
+               /*
+                * reconfigure the netdevice with the results of the new
+                * dcbx negotiation.
+                */
+               bnx2x_dcbx_update_tc_mapping(bp);
+
        }
 }
 
@@ -2242,7 +2249,7 @@ static int bnx2x_set_admin_app_up(struct bnx2x *bp, u8 idtype, u16 idval, u8 up)
        int i, ff;
 
        /* iterate over the app entries looking for idtype and idval */
-       for (i = 0, ff = -1; i < 4; i++) {
+       for (i = 0, ff = -1; i < DCBX_CONFIG_MAX_APP_PROTOCOL; i++) {
                struct bnx2x_admin_priority_app_table *app_ent =
                        &bp->dcbx_config_params.admin_priority_app_table[i];
                if (bnx2x_admin_app_is_equal(app_ent, idtype, idval))
@@ -2251,7 +2258,7 @@ static int bnx2x_set_admin_app_up(struct bnx2x *bp, u8 idtype, u16 idval, u8 up)
                if (ff < 0 && !app_ent->valid)
                        ff = i;
        }
-       if (i < 4)
+       if (i < DCBX_CONFIG_MAX_APP_PROTOCOL)
                /* if found overwrite up */
                bp->dcbx_config_params.
                        admin_priority_app_table[i].priority = up;
index 2c6a3bc..2ab9254 100644 (file)
@@ -90,6 +90,7 @@ struct bnx2x_admin_priority_app_table {
                u32 app_id;
 };
 
+#define DCBX_CONFIG_MAX_APP_PROTOCOL 4
 struct bnx2x_config_dcbx_params {
        u32 overwrite_settings;
        u32 admin_dcbx_version;
@@ -109,7 +110,8 @@ struct bnx2x_config_dcbx_params {
        u32 admin_recommendation_bw_precentage[8];
        u32 admin_recommendation_ets_pg[8];
        u32 admin_pfc_bitmap;
-       struct bnx2x_admin_priority_app_table admin_priority_app_table[4];
+       struct bnx2x_admin_priority_app_table
+               admin_priority_app_table[DCBX_CONFIG_MAX_APP_PROTOCOL];
        u32 admin_default_priority;
 };
 
index f0ca8b2..ec31871 100644 (file)
@@ -761,8 +761,8 @@ static void bnx2x_get_drvinfo(struct net_device *dev,
        struct bnx2x *bp = netdev_priv(dev);
        u8 phy_fw_ver[PHY_FW_VER_LEN];
 
-       strcpy(info->driver, DRV_MODULE_NAME);
-       strcpy(info->version, DRV_MODULE_VERSION);
+       strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
 
        phy_fw_ver[0] = '\0';
        if (bp->port.pmf) {
@@ -773,14 +773,14 @@ static void bnx2x_get_drvinfo(struct net_device *dev,
                bnx2x_release_phy_lock(bp);
        }
 
-       strncpy(info->fw_version, bp->fw_ver, 32);
+       strlcpy(info->fw_version, bp->fw_ver, sizeof(info->fw_version));
        snprintf(info->fw_version + strlen(bp->fw_ver), 32 - strlen(bp->fw_ver),
                 "bc %d.%d.%d%s%s",
                 (bp->common.bc_ver & 0xff0000) >> 16,
                 (bp->common.bc_ver & 0xff00) >> 8,
                 (bp->common.bc_ver & 0xff),
                 ((phy_fw_ver[0] != '\0') ? " phy " : ""), phy_fw_ver);
-       strcpy(info->bus_info, pci_name(bp->pdev));
+       strlcpy(info->bus_info, pci_name(bp->pdev), sizeof(info->bus_info));
        info->n_stats = BNX2X_NUM_STATS;
        info->testinfo_len = BNX2X_NUM_TESTS;
        info->eedump_len = bp->common.flash_size;
@@ -1740,6 +1740,7 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode)
        struct sw_rx_bd *rx_buf;
        u16 len;
        int rc = -ENODEV;
+       u8 *data;
 
        /* check the loopback mode */
        switch (loopback_mode) {
@@ -1865,10 +1866,9 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode)
        dma_sync_single_for_cpu(&bp->pdev->dev,
                                   dma_unmap_addr(rx_buf, mapping),
                                   fp_rx->rx_buf_size, DMA_FROM_DEVICE);
-       skb = rx_buf->skb;
-       skb_reserve(skb, cqe->fast_path_cqe.placement_offset);
+       data = rx_buf->data + NET_SKB_PAD + cqe->fast_path_cqe.placement_offset;
        for (i = ETH_HLEN; i < pkt_size; i++)
-               if (*(skb->data + i) != (unsigned char) (i & 0xff))
+               if (*(data + i) != (unsigned char) (i & 0xff))
                        goto test_loopback_rx_exit;
 
        rc = 0;
index 6486ab8..0cdbb70 100644 (file)
@@ -2318,12 +2318,6 @@ static void bnx2x_calc_vn_weight_sum(struct bnx2x *bp)
                                        CMNG_FLAGS_PER_PORT_FAIRNESS_VN;
 }
 
-/* returns func by VN for current port */
-static inline int func_by_vn(struct bnx2x *bp, int vn)
-{
-       return 2 * vn + BP_PORT(bp);
-}
-
 static void bnx2x_init_vn_minmax(struct bnx2x *bp, int vn)
 {
        struct rate_shaping_vars_per_vn m_rs_vn;
@@ -2475,22 +2469,6 @@ static void bnx2x_cmng_fns_init(struct bnx2x *bp, u8 read_cfg, u8 cmng_type)
           "rate shaping and fairness are disabled\n");
 }
 
-static inline void bnx2x_link_sync_notify(struct bnx2x *bp)
-{
-       int func;
-       int vn;
-
-       /* Set the attention towards other drivers on the same port */
-       for (vn = VN_0; vn < BP_MAX_VN_NUM(bp); vn++) {
-               if (vn == BP_VN(bp))
-                       continue;
-
-               func = func_by_vn(bp, vn);
-               REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_0 +
-                      (LINK_SYNC_ATTENTION_BIT_FUNC_0 + func)*4, 1);
-       }
-}
-
 /* This function is called upon link interrupt */
 static void bnx2x_link_attn(struct bnx2x *bp)
 {
@@ -2549,6 +2527,9 @@ void bnx2x__link_status_update(struct bnx2x *bp)
        if (bp->state != BNX2X_STATE_OPEN)
                return;
 
+       /* read updated dcb configuration */
+       bnx2x_dcbx_pmf_update(bp);
+
        bnx2x_link_status_update(&bp->link_params, &bp->link_vars);
 
        if (bp->link_vars.link_up)
@@ -2808,8 +2789,8 @@ static void bnx2x_pf_rx_q_prep(struct bnx2x *bp,
        /* This should be a maximum number of data bytes that may be
         * placed on the BD (not including paddings).
         */
-       rxq_init->buf_sz = fp->rx_buf_size - BNX2X_FW_RX_ALIGN -
-               IP_HEADER_ALIGNMENT_PADDING;
+       rxq_init->buf_sz = fp->rx_buf_size - BNX2X_FW_RX_ALIGN_START -
+               BNX2X_FW_RX_ALIGN_END - IP_HEADER_ALIGNMENT_PADDING;
 
        rxq_init->cl_qzone_id = fp->cl_qzone_id;
        rxq_init->tpa_agg_sz = tpa_agg_size;
@@ -3318,6 +3299,17 @@ static inline void bnx2x_fan_failure(struct bnx2x *bp)
        netdev_err(bp->dev, "Fan Failure on Network Controller has caused"
               " the driver to shutdown the card to prevent permanent"
               " damage.  Please contact OEM Support for assistance\n");
+
+       /*
+        * Scheudle device reset (unload)
+        * This is due to some boards consuming sufficient power when driver is
+        * up to overheat if fan fails.
+        */
+       smp_mb__before_clear_bit();
+       set_bit(BNX2X_SP_RTNL_FAN_FAILURE, &bp->sp_rtnl_state);
+       smp_mb__after_clear_bit();
+       schedule_delayed_work(&bp->sp_rtnl_task, 0);
+
 }
 
 static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn)
@@ -5247,7 +5239,7 @@ static void bnx2x_init_eth_fp(struct bnx2x *bp, int fp_idx)
        u8 cos;
        unsigned long q_type = 0;
        u32 cids[BNX2X_MULTI_TX_COS] = { 0 };
-
+       fp->rx_queue = fp_idx;
        fp->cid = fp_idx;
        fp->cl_id = bnx2x_fp_cl_id(fp);
        fp->fw_sb_id = bnx2x_fp_fw_sb_id(fp);
@@ -8522,6 +8514,17 @@ sp_rtnl_not_reset:
        if (test_and_clear_bit(BNX2X_SP_RTNL_SETUP_TC, &bp->sp_rtnl_state))
                bnx2x_setup_tc(bp->dev, bp->dcbx_port_params.ets.num_of_cos);
 
+       /*
+        * in case of fan failure we need to reset id if the "stop on error"
+        * debug flag is set, since we trying to prevent permanent overheating
+        * damage
+        */
+       if (test_and_clear_bit(BNX2X_SP_RTNL_FAN_FAILURE, &bp->sp_rtnl_state)) {
+               DP(BNX2X_MSG_SP, "fan failure detected. Unloading driver\n");
+               netif_device_detach(bp->dev);
+               bnx2x_close(bp->dev);
+       }
+
 sp_rtnl_exit:
        rtnl_unlock();
 }
@@ -9268,21 +9271,38 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
 }
 
 #ifdef BCM_CNIC
-static void __devinit bnx2x_get_cnic_info(struct bnx2x *bp)
+void bnx2x_get_iscsi_info(struct bnx2x *bp)
 {
        int port = BP_PORT(bp);
-       int func = BP_ABS_FUNC(bp);
 
        u32 max_iscsi_conn = FW_ENCODE_32BIT_PATTERN ^ SHMEM_RD(bp,
                                drv_lic_key[port].max_iscsi_conn);
-       u32 max_fcoe_conn = FW_ENCODE_32BIT_PATTERN ^ SHMEM_RD(bp,
-                               drv_lic_key[port].max_fcoe_conn);
 
-       /* Get the number of maximum allowed iSCSI and FCoE connections */
+       /* Get the number of maximum allowed iSCSI connections */
        bp->cnic_eth_dev.max_iscsi_conn =
                (max_iscsi_conn & BNX2X_MAX_ISCSI_INIT_CONN_MASK) >>
                BNX2X_MAX_ISCSI_INIT_CONN_SHIFT;
 
+       BNX2X_DEV_INFO("max_iscsi_conn 0x%x\n",
+                      bp->cnic_eth_dev.max_iscsi_conn);
+
+       /*
+        * If maximum allowed number of connections is zero -
+        * disable the feature.
+        */
+       if (!bp->cnic_eth_dev.max_iscsi_conn)
+               bp->flags |= NO_ISCSI_FLAG;
+}
+
+static void __devinit bnx2x_get_fcoe_info(struct bnx2x *bp)
+{
+       int port = BP_PORT(bp);
+       int func = BP_ABS_FUNC(bp);
+
+       u32 max_fcoe_conn = FW_ENCODE_32BIT_PATTERN ^ SHMEM_RD(bp,
+                               drv_lic_key[port].max_fcoe_conn);
+
+       /* Get the number of maximum allowed FCoE connections */
        bp->cnic_eth_dev.max_fcoe_conn =
                (max_fcoe_conn & BNX2X_MAX_FCOE_INIT_CONN_MASK) >>
                BNX2X_MAX_FCOE_INIT_CONN_SHIFT;
@@ -9334,20 +9354,26 @@ static void __devinit bnx2x_get_cnic_info(struct bnx2x *bp)
                }
        }
 
-       BNX2X_DEV_INFO("max_iscsi_conn 0x%x max_fcoe_conn 0x%x\n",
-                      bp->cnic_eth_dev.max_iscsi_conn,
-                      bp->cnic_eth_dev.max_fcoe_conn);
+       BNX2X_DEV_INFO("max_fcoe_conn 0x%x\n", bp->cnic_eth_dev.max_fcoe_conn);
 
        /*
         * If maximum allowed number of connections is zero -
         * disable the feature.
         */
-       if (!bp->cnic_eth_dev.max_iscsi_conn)
-               bp->flags |= NO_ISCSI_OOO_FLAG | NO_ISCSI_FLAG;
-
        if (!bp->cnic_eth_dev.max_fcoe_conn)
                bp->flags |= NO_FCOE_FLAG;
 }
+
+static void __devinit bnx2x_get_cnic_info(struct bnx2x *bp)
+{
+       /*
+        * iSCSI may be dynamically disabled but reading
+        * info here we will decrease memory usage by driver
+        * if the feature is disabled for good
+        */
+       bnx2x_get_iscsi_info(bp);
+       bnx2x_get_fcoe_info(bp);
+}
 #endif
 
 static void __devinit bnx2x_get_mac_hwinfo(struct bnx2x *bp)
@@ -9965,7 +9991,7 @@ static int bnx2x_open(struct net_device *dev)
 }
 
 /* called with rtnl_lock */
-static int bnx2x_close(struct net_device *dev)
+int bnx2x_close(struct net_device *dev)
 {
        struct bnx2x *bp = netdev_priv(dev);
 
@@ -10548,33 +10574,38 @@ do {                                                                  \
 
 int bnx2x_init_firmware(struct bnx2x *bp)
 {
-       const char *fw_file_name;
        struct bnx2x_fw_file_hdr *fw_hdr;
        int rc;
 
-       if (CHIP_IS_E1(bp))
-               fw_file_name = FW_FILE_NAME_E1;
-       else if (CHIP_IS_E1H(bp))
-               fw_file_name = FW_FILE_NAME_E1H;
-       else if (!CHIP_IS_E1x(bp))
-               fw_file_name = FW_FILE_NAME_E2;
-       else {
-               BNX2X_ERR("Unsupported chip revision\n");
-               return -EINVAL;
-       }
 
-       BNX2X_DEV_INFO("Loading %s\n", fw_file_name);
+       if (!bp->firmware) {
+               const char *fw_file_name;
 
-       rc = request_firmware(&bp->firmware, fw_file_name, &bp->pdev->dev);
-       if (rc) {
-               BNX2X_ERR("Can't load firmware file %s\n", fw_file_name);
-               goto request_firmware_exit;
-       }
+               if (CHIP_IS_E1(bp))
+                       fw_file_name = FW_FILE_NAME_E1;
+               else if (CHIP_IS_E1H(bp))
+                       fw_file_name = FW_FILE_NAME_E1H;
+               else if (!CHIP_IS_E1x(bp))
+                       fw_file_name = FW_FILE_NAME_E2;
+               else {
+                       BNX2X_ERR("Unsupported chip revision\n");
+                       return -EINVAL;
+               }
+               BNX2X_DEV_INFO("Loading %s\n", fw_file_name);
 
-       rc = bnx2x_check_firmware(bp);
-       if (rc) {
-               BNX2X_ERR("Corrupt firmware file %s\n", fw_file_name);
-               goto request_firmware_exit;
+               rc = request_firmware(&bp->firmware, fw_file_name,
+                                     &bp->pdev->dev);
+               if (rc) {
+                       BNX2X_ERR("Can't load firmware file %s\n",
+                                 fw_file_name);
+                       goto request_firmware_exit;
+               }
+
+               rc = bnx2x_check_firmware(bp);
+               if (rc) {
+                       BNX2X_ERR("Corrupt firmware file %s\n", fw_file_name);
+                       goto request_firmware_exit;
+               }
        }
 
        fw_hdr = (struct bnx2x_fw_file_hdr *)bp->firmware->data;
@@ -10630,6 +10661,7 @@ static void bnx2x_release_firmware(struct bnx2x *bp)
        kfree(bp->init_ops);
        kfree(bp->init_data);
        release_firmware(bp->firmware);
+       bp->firmware = NULL;
 }
 
 
@@ -10817,8 +10849,8 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
        bp->qm_cid_count = bnx2x_set_qm_cid_count(bp);
 
 #ifdef BCM_CNIC
-       /* disable FCOE L2 queue for E1x and E3*/
-       if (CHIP_IS_E1x(bp) || CHIP_IS_E3(bp))
+       /* disable FCOE L2 queue for E1x */
+       if (CHIP_IS_E1x(bp))
                bp->flags |= NO_FCOE_FLAG;
 
 #endif
@@ -10925,6 +10957,8 @@ static void __devexit bnx2x_remove_one(struct pci_dev *pdev)
        if (bp->doorbells)
                iounmap(bp->doorbells);
 
+       bnx2x_release_firmware(bp);
+
        bnx2x_free_mem_bp(bp);
 
        free_netdev(dev);
@@ -11553,7 +11587,7 @@ static int bnx2x_unregister_cnic(struct net_device *dev)
 
        mutex_lock(&bp->cnic_mutex);
        cp->drv_state = 0;
-       rcu_assign_pointer(bp->cnic_ops, NULL);
+       RCU_INIT_POINTER(bp->cnic_ops, NULL);
        mutex_unlock(&bp->cnic_mutex);
        synchronize_rcu();
        kfree(bp->cnic_kwq);
index 0440425..1451769 100644 (file)
@@ -5380,7 +5380,7 @@ static int bnx2x_func_hw_init(struct bnx2x *bp,
        rc = drv->init_fw(bp);
        if (rc) {
                BNX2X_ERR("Error loading firmware\n");
-               goto fw_init_err;
+               goto init_err;
        }
 
        /* Handle the beginning of COMMON_XXX pases separatelly... */
@@ -5388,25 +5388,25 @@ static int bnx2x_func_hw_init(struct bnx2x *bp,
        case FW_MSG_CODE_DRV_LOAD_COMMON_CHIP:
                rc = bnx2x_func_init_cmn_chip(bp, drv);
                if (rc)
-                       goto init_hw_err;
+                       goto init_err;
 
                break;
        case FW_MSG_CODE_DRV_LOAD_COMMON:
                rc = bnx2x_func_init_cmn(bp, drv);
                if (rc)
-                       goto init_hw_err;
+                       goto init_err;
 
                break;
        case FW_MSG_CODE_DRV_LOAD_PORT:
                rc = bnx2x_func_init_port(bp, drv);
                if (rc)
-                       goto init_hw_err;
+                       goto init_err;
 
                break;
        case FW_MSG_CODE_DRV_LOAD_FUNCTION:
                rc = bnx2x_func_init_func(bp, drv);
                if (rc)
-                       goto init_hw_err;
+                       goto init_err;
 
                break;
        default:
@@ -5414,10 +5414,7 @@ static int bnx2x_func_hw_init(struct bnx2x *bp,
                rc = -EINVAL;
        }
 
-init_hw_err:
-       drv->release_fw(bp);
-
-fw_init_err:
+init_err:
        drv->gunzip_end(bp);
 
        /* In case of success, complete the comand immediatelly: no ramrods
index 02ac6a7..3034f0e 100644 (file)
@@ -1349,12 +1349,14 @@ void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event)
        enum bnx2x_stats_state state;
        if (unlikely(bp->panic))
                return;
-       bnx2x_stats_stm[bp->stats_state][event].action(bp);
+
        spin_lock_bh(&bp->stats_lock);
        state = bp->stats_state;
        bp->stats_state = bnx2x_stats_stm[state][event].next_state;
        spin_unlock_bh(&bp->stats_lock);
 
+       bnx2x_stats_stm[state][event].action(bp);
+
        if ((event != STATS_EVENT_UPDATE) || netif_msg_timer(bp))
                DP(BNX2X_MSG_STATS, "state %d -> event %d -> state %d\n",
                   state, event, bp->stats_state);
index 6f10c69..b336e55 100644 (file)
@@ -506,7 +506,7 @@ int cnic_unregister_driver(int ulp_type)
        }
        read_unlock(&cnic_dev_lock);
 
-       rcu_assign_pointer(cnic_ulp_tbl[ulp_type], NULL);
+       RCU_INIT_POINTER(cnic_ulp_tbl[ulp_type], NULL);
 
        mutex_unlock(&cnic_lock);
        synchronize_rcu();
@@ -579,7 +579,7 @@ static int cnic_unregister_device(struct cnic_dev *dev, int ulp_type)
        }
        mutex_lock(&cnic_lock);
        if (rcu_dereference(cp->ulp_ops[ulp_type])) {
-               rcu_assign_pointer(cp->ulp_ops[ulp_type], NULL);
+               RCU_INIT_POINTER(cp->ulp_ops[ulp_type], NULL);
                cnic_put(dev);
        } else {
                pr_err("%s: device not registered to this ulp type %d\n",
@@ -3475,7 +3475,7 @@ static int cnic_get_v6_route(struct sockaddr_in6 *dst_addr,
        struct flowi6 fl6;
 
        memset(&fl6, 0, sizeof(fl6));
-       ipv6_addr_copy(&fl6.daddr, &dst_addr->sin6_addr);
+       fl6.daddr = dst_addr->sin6_addr;
        if (ipv6_addr_type(&fl6.daddr) & IPV6_ADDR_LINKLOCAL)
                fl6.flowi6_oif = dst_addr->sin6_scope_id;
 
@@ -5134,7 +5134,7 @@ static void cnic_stop_hw(struct cnic_dev *dev)
                }
                cnic_shutdown_rings(dev);
                clear_bit(CNIC_F_CNIC_UP, &dev->flags);
-               rcu_assign_pointer(cp->ulp_ops[CNIC_ULP_L4], NULL);
+               RCU_INIT_POINTER(cp->ulp_ops[CNIC_ULP_L4], NULL);
                synchronize_rcu();
                cnic_cm_shutdown(dev);
                cp->stop_hw(dev);
index 0a1d7f2..aa58f9e 100644 (file)
@@ -163,7 +163,6 @@ enum sbmac_state {
 #define SBMAC_MAX_TXDESCR      256
 #define SBMAC_MAX_RXDESCR      256
 
-#define ETHER_ADDR_LEN         6
 #define ENET_PACKET_SIZE       1518
 /*#define ENET_PACKET_SIZE     9216 */
 
@@ -266,7 +265,7 @@ struct sbmac_softc {
        int                     sbm_pause;      /* current pause setting */
        int                     sbm_link;       /* current link state */
 
-       unsigned char           sbm_hwaddr[ETHER_ADDR_LEN];
+       unsigned char           sbm_hwaddr[ETH_ALEN];
 
        struct sbmacdma         sbm_txdma;      /* only channel 0 for now */
        struct sbmacdma         sbm_rxdma;
index bf40741..0acb279 100644 (file)
@@ -194,7 +194,7 @@ static inline void _tg3_flag_clear(enum TG3_FLAGS flag, unsigned long *bits)
 #if (NET_IP_ALIGN != 0)
 #define TG3_RX_OFFSET(tp)      ((tp)->rx_offset)
 #else
-#define TG3_RX_OFFSET(tp)      0
+#define TG3_RX_OFFSET(tp)      (NET_SKB_PAD)
 #endif
 
 /* minimum number of free TX descriptors required to wake up TX process */
@@ -1706,18 +1706,12 @@ static u8 tg3_resolve_flowctrl_1000X(u16 lcladv, u16 rmtadv)
 {
        u8 cap = 0;
 
-       if (lcladv & ADVERTISE_1000XPAUSE) {
-               if (lcladv & ADVERTISE_1000XPSE_ASYM) {
-                       if (rmtadv & LPA_1000XPAUSE)
-                               cap = FLOW_CTRL_TX | FLOW_CTRL_RX;
-                       else if (rmtadv & LPA_1000XPAUSE_ASYM)
-                               cap = FLOW_CTRL_RX;
-               } else {
-                       if (rmtadv & LPA_1000XPAUSE)
-                               cap = FLOW_CTRL_TX | FLOW_CTRL_RX;
-               }
-       } else if (lcladv & ADVERTISE_1000XPSE_ASYM) {
-               if ((rmtadv & LPA_1000XPAUSE) && (rmtadv & LPA_1000XPAUSE_ASYM))
+       if (lcladv & rmtadv & ADVERTISE_1000XPAUSE) {
+               cap = FLOW_CTRL_TX | FLOW_CTRL_RX;
+       } else if (lcladv & rmtadv & ADVERTISE_1000XPSE_ASYM) {
+               if (lcladv & ADVERTISE_1000XPAUSE)
+                       cap = FLOW_CTRL_RX;
+               if (rmtadv & ADVERTISE_1000XPAUSE)
                        cap = FLOW_CTRL_TX;
        }
 
@@ -3594,15 +3588,7 @@ static int tg3_phy_autoneg_cfg(struct tg3 *tp, u32 advertise, u32 flowctrl)
        u32 val, new_adv;
 
        new_adv = ADVERTISE_CSMA;
-       if (advertise & ADVERTISED_10baseT_Half)
-               new_adv |= ADVERTISE_10HALF;
-       if (advertise & ADVERTISED_10baseT_Full)
-               new_adv |= ADVERTISE_10FULL;
-       if (advertise & ADVERTISED_100baseT_Half)
-               new_adv |= ADVERTISE_100HALF;
-       if (advertise & ADVERTISED_100baseT_Full)
-               new_adv |= ADVERTISE_100FULL;
-
+       new_adv |= ethtool_adv_to_mii_adv_t(advertise) & ADVERTISE_ALL;
        new_adv |= tg3_advert_flowctrl_1000T(flowctrl);
 
        err = tg3_writephy(tp, MII_ADVERTISE, new_adv);
@@ -3612,11 +3598,7 @@ static int tg3_phy_autoneg_cfg(struct tg3 *tp, u32 advertise, u32 flowctrl)
        if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY)
                goto done;
 
-       new_adv = 0;
-       if (advertise & ADVERTISED_1000baseT_Half)
-               new_adv |= ADVERTISE_1000HALF;
-       if (advertise & ADVERTISED_1000baseT_Full)
-               new_adv |= ADVERTISE_1000FULL;
+       new_adv = ethtool_adv_to_mii_ctrl1000_t(advertise);
 
        if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
            tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)
@@ -3790,14 +3772,7 @@ static int tg3_copper_is_advertising_all(struct tg3 *tp, u32 mask)
 {
        u32 adv_reg, all_mask = 0;
 
-       if (mask & ADVERTISED_10baseT_Half)
-               all_mask |= ADVERTISE_10HALF;
-       if (mask & ADVERTISED_10baseT_Full)
-               all_mask |= ADVERTISE_10FULL;
-       if (mask & ADVERTISED_100baseT_Half)
-               all_mask |= ADVERTISE_100HALF;
-       if (mask & ADVERTISED_100baseT_Full)
-               all_mask |= ADVERTISE_100FULL;
+       all_mask = ethtool_adv_to_mii_adv_t(mask) & ADVERTISE_ALL;
 
        if (tg3_readphy(tp, MII_ADVERTISE, &adv_reg))
                return 0;
@@ -3808,11 +3783,7 @@ static int tg3_copper_is_advertising_all(struct tg3 *tp, u32 mask)
        if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY)) {
                u32 tg3_ctrl;
 
-               all_mask = 0;
-               if (mask & ADVERTISED_1000baseT_Half)
-                       all_mask |= ADVERTISE_1000HALF;
-               if (mask & ADVERTISED_1000baseT_Full)
-                       all_mask |= ADVERTISE_1000FULL;
+               all_mask = ethtool_adv_to_mii_ctrl1000_t(mask);
 
                if (tg3_readphy(tp, MII_CTRL1000, &tg3_ctrl))
                        return 0;
@@ -3961,6 +3932,7 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
        current_link_up = 0;
        current_speed = SPEED_INVALID;
        current_duplex = DUPLEX_INVALID;
+       tp->phy_flags &= ~TG3_PHYFLG_MDIX_STATE;
 
        if (tp->phy_flags & TG3_PHYFLG_CAPACITIVE_COUPLING) {
                err = tg3_phy_auxctl_read(tp,
@@ -4033,8 +4005,22 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
                }
 
                if (current_link_up == 1 &&
-                   tp->link_config.active_duplex == DUPLEX_FULL)
+                   tp->link_config.active_duplex == DUPLEX_FULL) {
+                       u32 reg, bit;
+
+                       if (tp->phy_flags & TG3_PHYFLG_IS_FET) {
+                               reg = MII_TG3_FET_GEN_STAT;
+                               bit = MII_TG3_FET_GEN_STAT_MDIXSTAT;
+                       } else {
+                               reg = MII_TG3_EXT_STAT;
+                               bit = MII_TG3_EXT_STAT_MDIX;
+                       }
+
+                       if (!tg3_readphy(tp, reg, &val) && (val & bit))
+                               tp->phy_flags |= TG3_PHYFLG_MDIX_STATE;
+
                        tg3_setup_flow_control(tp, lcl_adv, rmt_adv);
+               }
        }
 
 relink:
@@ -4903,23 +4889,19 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
            (tp->phy_flags & TG3_PHYFLG_PARALLEL_DETECT)) {
                /* do nothing, just check for link up at the end */
        } else if (tp->link_config.autoneg == AUTONEG_ENABLE) {
-               u32 adv, new_adv;
+               u32 adv, newadv;
 
                err |= tg3_readphy(tp, MII_ADVERTISE, &adv);
-               new_adv = adv & ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF |
-                                 ADVERTISE_1000XPAUSE |
-                                 ADVERTISE_1000XPSE_ASYM |
-                                 ADVERTISE_SLCT);
-
-               new_adv |= tg3_advert_flowctrl_1000X(tp->link_config.flowctrl);
+               newadv = adv & ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF |
+                                ADVERTISE_1000XPAUSE |
+                                ADVERTISE_1000XPSE_ASYM |
+                                ADVERTISE_SLCT);
 
-               if (tp->link_config.advertising & ADVERTISED_1000baseT_Half)
-                       new_adv |= ADVERTISE_1000XHALF;
-               if (tp->link_config.advertising & ADVERTISED_1000baseT_Full)
-                       new_adv |= ADVERTISE_1000XFULL;
+               newadv |= tg3_advert_flowctrl_1000X(tp->link_config.flowctrl);
+               newadv |= ethtool_adv_to_mii_adv_x(tp->link_config.advertising);
 
-               if ((new_adv != adv) || !(bmcr & BMCR_ANENABLE)) {
-                       tg3_writephy(tp, MII_ADVERTISE, new_adv);
+               if ((newadv != adv) || !(bmcr & BMCR_ANENABLE)) {
+                       tg3_writephy(tp, MII_ADVERTISE, newadv);
                        bmcr |= BMCR_ANENABLE | BMCR_ANRESTART;
                        tg3_writephy(tp, MII_BMCR, bmcr);
 
@@ -5397,15 +5379,15 @@ static void tg3_tx(struct tg3_napi *tnapi)
        }
 }
 
-static void tg3_rx_skb_free(struct tg3 *tp, struct ring_info *ri, u32 map_sz)
+static void tg3_rx_data_free(struct tg3 *tp, struct ring_info *ri, u32 map_sz)
 {
-       if (!ri->skb)
+       if (!ri->data)
                return;
 
        pci_unmap_single(tp->pdev, dma_unmap_addr(ri, mapping),
                         map_sz, PCI_DMA_FROMDEVICE);
-       dev_kfree_skb_any(ri->skb);
-       ri->skb = NULL;
+       kfree(ri->data);
+       ri->data = NULL;
 }
 
 /* Returns size of skb allocated or < 0 on error.
@@ -5419,28 +5401,28 @@ static void tg3_rx_skb_free(struct tg3 *tp, struct ring_info *ri, u32 map_sz)
  * buffers the cpu only reads the last cacheline of the RX descriptor
  * (to fetch the error flags, vlan tag, checksum, and opaque cookie).
  */
-static int tg3_alloc_rx_skb(struct tg3 *tp, struct tg3_rx_prodring_set *tpr,
+static int tg3_alloc_rx_data(struct tg3 *tp, struct tg3_rx_prodring_set *tpr,
                            u32 opaque_key, u32 dest_idx_unmasked)
 {
        struct tg3_rx_buffer_desc *desc;
        struct ring_info *map;
-       struct sk_buff *skb;
+       u8 *data;
        dma_addr_t mapping;
-       int skb_size, dest_idx;
+       int skb_size, data_size, dest_idx;
 
        switch (opaque_key) {
        case RXD_OPAQUE_RING_STD:
                dest_idx = dest_idx_unmasked & tp->rx_std_ring_mask;
                desc = &tpr->rx_std[dest_idx];
                map = &tpr->rx_std_buffers[dest_idx];
-               skb_size = tp->rx_pkt_map_sz;
+               data_size = tp->rx_pkt_map_sz;
                break;
 
        case RXD_OPAQUE_RING_JUMBO:
                dest_idx = dest_idx_unmasked & tp->rx_jmb_ring_mask;
                desc = &tpr->rx_jmb[dest_idx].std;
                map = &tpr->rx_jmb_buffers[dest_idx];
-               skb_size = TG3_RX_JMB_MAP_SZ;
+               data_size = TG3_RX_JMB_MAP_SZ;
                break;
 
        default:
@@ -5453,31 +5435,33 @@ static int tg3_alloc_rx_skb(struct tg3 *tp, struct tg3_rx_prodring_set *tpr,
         * Callers depend upon this behavior and assume that
         * we leave everything unchanged if we fail.
         */
-       skb = netdev_alloc_skb(tp->dev, skb_size + TG3_RX_OFFSET(tp));
-       if (skb == NULL)
+       skb_size = SKB_DATA_ALIGN(data_size + TG3_RX_OFFSET(tp)) +
+                  SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+       data = kmalloc(skb_size, GFP_ATOMIC);
+       if (!data)
                return -ENOMEM;
 
-       skb_reserve(skb, TG3_RX_OFFSET(tp));
-
-       mapping = pci_map_single(tp->pdev, skb->data, skb_size,
+       mapping = pci_map_single(tp->pdev,
+                                data + TG3_RX_OFFSET(tp),
+                                data_size,
                                 PCI_DMA_FROMDEVICE);
        if (pci_dma_mapping_error(tp->pdev, mapping)) {
-               dev_kfree_skb(skb);
+               kfree(data);
                return -EIO;
        }
 
-       map->skb = skb;
+       map->data = data;
        dma_unmap_addr_set(map, mapping, mapping);
 
        desc->addr_hi = ((u64)mapping >> 32);
        desc->addr_lo = ((u64)mapping & 0xffffffff);
 
-       return skb_size;
+       return data_size;
 }
 
 /* We only need to move over in the address because the other
  * members of the RX descriptor are invariant.  See notes above
- * tg3_alloc_rx_skb for full details.
+ * tg3_alloc_rx_data for full details.
  */
 static void tg3_recycle_rx(struct tg3_napi *tnapi,
                           struct tg3_rx_prodring_set *dpr,
@@ -5511,7 +5495,7 @@ static void tg3_recycle_rx(struct tg3_napi *tnapi,
                return;
        }
 
-       dest_map->skb = src_map->skb;
+       dest_map->data = src_map->data;
        dma_unmap_addr_set(dest_map, mapping,
                           dma_unmap_addr(src_map, mapping));
        dest_desc->addr_hi = src_desc->addr_hi;
@@ -5522,7 +5506,7 @@ static void tg3_recycle_rx(struct tg3_napi *tnapi,
         */
        smp_wmb();
 
-       src_map->skb = NULL;
+       src_map->data = NULL;
 }
 
 /* The RX ring scheme is composed of multiple rings which post fresh
@@ -5576,19 +5560,20 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
                struct sk_buff *skb;
                dma_addr_t dma_addr;
                u32 opaque_key, desc_idx, *post_ptr;
+               u8 *data;
 
                desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK;
                opaque_key = desc->opaque & RXD_OPAQUE_RING_MASK;
                if (opaque_key == RXD_OPAQUE_RING_STD) {
                        ri = &tp->napi[0].prodring.rx_std_buffers[desc_idx];
                        dma_addr = dma_unmap_addr(ri, mapping);
-                       skb = ri->skb;
+                       data = ri->data;
                        post_ptr = &std_prod_idx;
                        rx_std_posted++;
                } else if (opaque_key == RXD_OPAQUE_RING_JUMBO) {
                        ri = &tp->napi[0].prodring.rx_jmb_buffers[desc_idx];
                        dma_addr = dma_unmap_addr(ri, mapping);
-                       skb = ri->skb;
+                       data = ri->data;
                        post_ptr = &jmb_prod_idx;
                } else
                        goto next_pkt_nopost;
@@ -5606,13 +5591,14 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
                        goto next_pkt;
                }
 
+               prefetch(data + TG3_RX_OFFSET(tp));
                len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) -
                      ETH_FCS_LEN;
 
                if (len > TG3_RX_COPY_THRESH(tp)) {
                        int skb_size;
 
-                       skb_size = tg3_alloc_rx_skb(tp, tpr, opaque_key,
+                       skb_size = tg3_alloc_rx_data(tp, tpr, opaque_key,
                                                    *post_ptr);
                        if (skb_size < 0)
                                goto drop_it;
@@ -5620,35 +5606,37 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
                        pci_unmap_single(tp->pdev, dma_addr, skb_size,
                                         PCI_DMA_FROMDEVICE);
 
-                       /* Ensure that the update to the skb happens
+                       skb = build_skb(data);
+                       if (!skb) {
+                               kfree(data);
+                               goto drop_it_no_recycle;
+                       }
+                       skb_reserve(skb, TG3_RX_OFFSET(tp));
+                       /* Ensure that the update to the data happens
                         * after the usage of the old DMA mapping.
                         */
                        smp_wmb();
 
-                       ri->skb = NULL;
+                       ri->data = NULL;
 
-                       skb_put(skb, len);
                } else {
-                       struct sk_buff *copy_skb;
-
                        tg3_recycle_rx(tnapi, tpr, opaque_key,
                                       desc_idx, *post_ptr);
 
-                       copy_skb = netdev_alloc_skb(tp->dev, len +
-                                                   TG3_RAW_IP_ALIGN);
-                       if (copy_skb == NULL)
+                       skb = netdev_alloc_skb(tp->dev,
+                                              len + TG3_RAW_IP_ALIGN);
+                       if (skb == NULL)
                                goto drop_it_no_recycle;
 
-                       skb_reserve(copy_skb, TG3_RAW_IP_ALIGN);
-                       skb_put(copy_skb, len);
+                       skb_reserve(skb, TG3_RAW_IP_ALIGN);
                        pci_dma_sync_single_for_cpu(tp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE);
-                       skb_copy_from_linear_data(skb, copy_skb->data, len);
+                       memcpy(skb->data,
+                              data + TG3_RX_OFFSET(tp),
+                              len);
                        pci_dma_sync_single_for_device(tp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE);
-
-                       /* We'll reuse the original ring buffer. */
-                       skb = copy_skb;
                }
 
+               skb_put(skb, len);
                if ((tp->dev->features & NETIF_F_RXCSUM) &&
                    (desc->type_flags & RXD_FLAG_TCPUDP_CSUM) &&
                    (((desc->ip_tcp_csum & RXD_TCPCSUM_MASK)
@@ -5787,7 +5775,7 @@ static int tg3_rx_prodring_xfer(struct tg3 *tp,
                di = dpr->rx_std_prod_idx;
 
                for (i = di; i < di + cpycnt; i++) {
-                       if (dpr->rx_std_buffers[i].skb) {
+                       if (dpr->rx_std_buffers[i].data) {
                                cpycnt = i - di;
                                err = -ENOSPC;
                                break;
@@ -5845,7 +5833,7 @@ static int tg3_rx_prodring_xfer(struct tg3 *tp,
                di = dpr->rx_jmb_prod_idx;
 
                for (i = di; i < di + cpycnt; i++) {
-                       if (dpr->rx_jmb_buffers[i].skb) {
+                       if (dpr->rx_jmb_buffers[i].data) {
                                cpycnt = i - di;
                                err = -ENOSPC;
                                break;
@@ -6968,7 +6956,7 @@ static int tg3_phy_lpbk_set(struct tg3 *tp, u32 speed, bool extlpbk)
        return 0;
 }
 
-static void tg3_set_loopback(struct net_device *dev, u32 features)
+static void tg3_set_loopback(struct net_device *dev, netdev_features_t features)
 {
        struct tg3 *tp = netdev_priv(dev);
 
@@ -6994,7 +6982,8 @@ static void tg3_set_loopback(struct net_device *dev, u32 features)
        }
 }
 
-static u32 tg3_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t tg3_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        struct tg3 *tp = netdev_priv(dev);
 
@@ -7004,9 +6993,9 @@ static u32 tg3_fix_features(struct net_device *dev, u32 features)
        return features;
 }
 
-static int tg3_set_features(struct net_device *dev, u32 features)
+static int tg3_set_features(struct net_device *dev, netdev_features_t features)
 {
-       u32 changed = dev->features ^ features;
+       netdev_features_t changed = dev->features ^ features;
 
        if ((changed & NETIF_F_LOOPBACK) && netif_running(dev))
                tg3_set_loopback(dev, features);
@@ -7082,14 +7071,14 @@ static void tg3_rx_prodring_free(struct tg3 *tp,
        if (tpr != &tp->napi[0].prodring) {
                for (i = tpr->rx_std_cons_idx; i != tpr->rx_std_prod_idx;
                     i = (i + 1) & tp->rx_std_ring_mask)
-                       tg3_rx_skb_free(tp, &tpr->rx_std_buffers[i],
+                       tg3_rx_data_free(tp, &tpr->rx_std_buffers[i],
                                        tp->rx_pkt_map_sz);
 
                if (tg3_flag(tp, JUMBO_CAPABLE)) {
                        for (i = tpr->rx_jmb_cons_idx;
                             i != tpr->rx_jmb_prod_idx;
                             i = (i + 1) & tp->rx_jmb_ring_mask) {
-                               tg3_rx_skb_free(tp, &tpr->rx_jmb_buffers[i],
+                               tg3_rx_data_free(tp, &tpr->rx_jmb_buffers[i],
                                                TG3_RX_JMB_MAP_SZ);
                        }
                }
@@ -7098,12 +7087,12 @@ static void tg3_rx_prodring_free(struct tg3 *tp,
        }
 
        for (i = 0; i <= tp->rx_std_ring_mask; i++)
-               tg3_rx_skb_free(tp, &tpr->rx_std_buffers[i],
+               tg3_rx_data_free(tp, &tpr->rx_std_buffers[i],
                                tp->rx_pkt_map_sz);
 
        if (tg3_flag(tp, JUMBO_CAPABLE) && !tg3_flag(tp, 5780_CLASS)) {
                for (i = 0; i <= tp->rx_jmb_ring_mask; i++)
-                       tg3_rx_skb_free(tp, &tpr->rx_jmb_buffers[i],
+                       tg3_rx_data_free(tp, &tpr->rx_jmb_buffers[i],
                                        TG3_RX_JMB_MAP_SZ);
        }
 }
@@ -7159,7 +7148,7 @@ static int tg3_rx_prodring_alloc(struct tg3 *tp,
 
        /* Now allocate fresh SKBs for each rx ring. */
        for (i = 0; i < tp->rx_pending; i++) {
-               if (tg3_alloc_rx_skb(tp, tpr, RXD_OPAQUE_RING_STD, i) < 0) {
+               if (tg3_alloc_rx_data(tp, tpr, RXD_OPAQUE_RING_STD, i) < 0) {
                        netdev_warn(tp->dev,
                                    "Using a smaller RX standard ring. Only "
                                    "%d out of %d buffers were allocated "
@@ -7191,7 +7180,7 @@ static int tg3_rx_prodring_alloc(struct tg3 *tp,
        }
 
        for (i = 0; i < tp->rx_jumbo_pending; i++) {
-               if (tg3_alloc_rx_skb(tp, tpr, RXD_OPAQUE_RING_JUMBO, i) < 0) {
+               if (tg3_alloc_rx_data(tp, tpr, RXD_OPAQUE_RING_JUMBO, i) < 0) {
                        netdev_warn(tp->dev,
                                    "Using a smaller RX jumbo ring. Only %d "
                                    "out of %d buffers were allocated "
@@ -8197,7 +8186,8 @@ static void tg3_setup_rxbd_thresholds(struct tg3 *tp)
        if (!tg3_flag(tp, 5750_PLUS) ||
            tg3_flag(tp, 5780_CLASS) ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 ||
-           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752)
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
+           tg3_flag(tp, 57765_PLUS))
                bdcache_maxcnt = TG3_SRAM_RX_STD_BDCACHE_SIZE_5700;
        else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
                 GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
@@ -8217,10 +8207,7 @@ static void tg3_setup_rxbd_thresholds(struct tg3 *tp)
        if (!tg3_flag(tp, JUMBO_CAPABLE) || tg3_flag(tp, 5780_CLASS))
                return;
 
-       if (!tg3_flag(tp, 5705_PLUS))
-               bdcache_maxcnt = TG3_SRAM_RX_JMB_BDCACHE_SIZE_5700;
-       else
-               bdcache_maxcnt = TG3_SRAM_RX_JMB_BDCACHE_SIZE_5717;
+       bdcache_maxcnt = TG3_SRAM_RX_JMB_BDCACHE_SIZE_5700;
 
        host_rep_thresh = max_t(u32, tp->rx_jumbo_pending / 8, 1);
 
@@ -8581,10 +8568,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
                }
 
                if (tg3_flag(tp, 57765_PLUS)) {
-                       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
-                               val = TG3_RX_STD_MAX_SIZE_5700;
-                       else
-                               val = TG3_RX_STD_MAX_SIZE_5717;
+                       val = TG3_RX_STD_RING_SIZE(tp);
                        val <<= BDINFO_FLAGS_MAXLEN_SHIFT;
                        val |= (TG3_RX_STD_DMA_SZ << 2);
                } else
@@ -10321,9 +10305,16 @@ static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
        if (netif_running(dev)) {
                ethtool_cmd_speed_set(cmd, tp->link_config.active_speed);
                cmd->duplex = tp->link_config.active_duplex;
+               if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES)) {
+                       if (tp->phy_flags & TG3_PHYFLG_MDIX_STATE)
+                               cmd->eth_tp_mdix = ETH_TP_MDI_X;
+                       else
+                               cmd->eth_tp_mdix = ETH_TP_MDI;
+               }
        } else {
                ethtool_cmd_speed_set(cmd, SPEED_INVALID);
                cmd->duplex = DUPLEX_INVALID;
+               cmd->eth_tp_mdix = ETH_TP_MDI_INVALID;
        }
        cmd->phy_address = tp->phy_addr;
        cmd->transceiver = XCVR_INTERNAL;
@@ -10428,10 +10419,10 @@ static void tg3_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info
 {
        struct tg3 *tp = netdev_priv(dev);
 
-       strcpy(info->driver, DRV_MODULE_NAME);
-       strcpy(info->version, DRV_MODULE_VERSION);
-       strcpy(info->fw_version, tp->fw_ver);
-       strcpy(info->bus_info, pci_name(tp->pdev));
+       strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
+       strlcpy(info->fw_version, tp->fw_ver, sizeof(info->fw_version));
+       strlcpy(info->bus_info, pci_name(tp->pdev), sizeof(info->bus_info));
 }
 
 static void tg3_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
@@ -11400,8 +11391,8 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, bool tso_loopback)
        u32 rx_start_idx, rx_idx, tx_idx, opaque_key;
        u32 base_flags = 0, mss = 0, desc_idx, coal_now, data_off, val;
        u32 budget;
-       struct sk_buff *skb, *rx_skb;
-       u8 *tx_data;
+       struct sk_buff *skb;
+       u8 *tx_data, *rx_data;
        dma_addr_t map;
        int num_pkts, tx_len, rx_len, i, err;
        struct tg3_rx_buffer_desc *desc;
@@ -11569,11 +11560,11 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, bool tso_loopback)
                }
 
                if (opaque_key == RXD_OPAQUE_RING_STD) {
-                       rx_skb = tpr->rx_std_buffers[desc_idx].skb;
+                       rx_data = tpr->rx_std_buffers[desc_idx].data;
                        map = dma_unmap_addr(&tpr->rx_std_buffers[desc_idx],
                                             mapping);
                } else if (opaque_key == RXD_OPAQUE_RING_JUMBO) {
-                       rx_skb = tpr->rx_jmb_buffers[desc_idx].skb;
+                       rx_data = tpr->rx_jmb_buffers[desc_idx].data;
                        map = dma_unmap_addr(&tpr->rx_jmb_buffers[desc_idx],
                                             mapping);
                } else
@@ -11582,15 +11573,16 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, bool tso_loopback)
                pci_dma_sync_single_for_cpu(tp->pdev, map, rx_len,
                                            PCI_DMA_FROMDEVICE);
 
+               rx_data += TG3_RX_OFFSET(tp);
                for (i = data_off; i < rx_len; i++, val++) {
-                       if (*(rx_skb->data + i) != (u8) (val & 0xff))
+                       if (*(rx_data + i) != (u8) (val & 0xff))
                                goto out;
                }
        }
 
        err = 0;
 
-       /* tg3_free_rings will unmap and free the rx_skb */
+       /* tg3_free_rings will unmap and free the rx_data */
 out:
        return err;
 }
@@ -13218,8 +13210,7 @@ static u32 __devinit tg3_read_otp_phycfg(struct tg3 *tp)
 
 static void __devinit tg3_phy_init_link_config(struct tg3 *tp)
 {
-       u32 adv = ADVERTISED_Autoneg |
-                 ADVERTISED_Pause;
+       u32 adv = ADVERTISED_Autoneg;
 
        if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY))
                adv |= ADVERTISED_1000baseT_Half |
@@ -14036,7 +14027,9 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
                tg3_flag_set(tp, 4K_FIFO_LIMIT);
 
-       if (tg3_flag(tp, 5717_PLUS))
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
                tg3_flag_set(tp, LRG_PROD_RING_CAP);
 
        if (tg3_flag(tp, 57765_PLUS) &&
@@ -14548,11 +14541,11 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
        else
                tg3_flag_clear(tp, POLL_SERDES);
 
-       tp->rx_offset = NET_IP_ALIGN;
+       tp->rx_offset = NET_SKB_PAD + NET_IP_ALIGN;
        tp->rx_copy_thresh = TG3_RX_COPY_THRESHOLD;
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 &&
            tg3_flag(tp, PCIX_MODE)) {
-               tp->rx_offset = 0;
+               tp->rx_offset = NET_SKB_PAD;
 #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
                tp->rx_copy_thresh = ~(u16)0;
 #endif
@@ -15313,7 +15306,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
        u32 sndmbx, rcvmbx, intmbx;
        char str[40];
        u64 dma_mask, persist_dma_mask;
-       u32 features = 0;
+       netdev_features_t features = 0;
 
        printk_once(KERN_INFO "%s\n", version);
 
index 94b4bd0..9cc10a8 100644 (file)
 #define  MII_TG3_EXT_CTRL_TBI          0x8000
 
 #define MII_TG3_EXT_STAT               0x11 /* Extended status register */
+#define  MII_TG3_EXT_STAT_MDIX         0x2000
 #define  MII_TG3_EXT_STAT_LPASS                0x0100
 
 #define MII_TG3_RXR_COUNTERS           0x14 /* Local/Remote Receiver Counts */
 #define  MII_TG3_FET_PTEST_FRC_TX_LINK 0x1000
 #define  MII_TG3_FET_PTEST_FRC_TX_LOCK 0x0800
 
+#define MII_TG3_FET_GEN_STAT           0x1c
+#define  MII_TG3_FET_GEN_STAT_MDIXSTAT 0x2000
+
 #define MII_TG3_FET_TEST               0x1f
 #define  MII_TG3_FET_SHADOW_EN         0x0080
 
@@ -2662,9 +2666,13 @@ struct tg3_hw_stats {
 /* 'mapping' is superfluous as the chip does not write into
  * the tx/rx post rings so we could just fetch it from there.
  * But the cache behavior is better how we are doing it now.
+ *
+ * This driver uses new build_skb() API :
+ * RX ring buffer contains pointer to kmalloc() data only,
+ * skb are built only after Hardware filled the frame.
  */
 struct ring_info {
-       struct sk_buff                  *skb;
+       u8                              *data;
        DEFINE_DMA_UNMAP_ADDR(mapping);
 };
 
@@ -3131,6 +3139,7 @@ struct tg3 {
 #define TG3_PHYFLG_SERDES_PREEMPHASIS  0x00010000
 #define TG3_PHYFLG_PARALLEL_DETECT     0x00020000
 #define TG3_PHYFLG_EEE_CAP             0x00040000
+#define TG3_PHYFLG_MDIX_STATE          0x00200000
 
        u32                             led_ctrl;
        u32                             phy_otp;
index fd3dcc1..38d5c66 100644 (file)
@@ -296,8 +296,8 @@ bnad_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
        struct bfa_ioc_attr *ioc_attr;
        unsigned long flags;
 
-       strcpy(drvinfo->driver, BNAD_NAME);
-       strcpy(drvinfo->version, BNAD_VERSION);
+       strlcpy(drvinfo->driver, BNAD_NAME, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, BNAD_VERSION, sizeof(drvinfo->version));
 
        ioc_attr = kzalloc(sizeof(*ioc_attr), GFP_KERNEL);
        if (ioc_attr) {
@@ -305,12 +305,13 @@ bnad_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
                bfa_nw_ioc_get_attr(&bnad->bna.ioceth.ioc, ioc_attr);
                spin_unlock_irqrestore(&bnad->bna_lock, flags);
 
-               strncpy(drvinfo->fw_version, ioc_attr->adapter_attr.fw_ver,
-                       sizeof(drvinfo->fw_version) - 1);
+               strlcpy(drvinfo->fw_version, ioc_attr->adapter_attr.fw_ver,
+                       sizeof(drvinfo->fw_version));
                kfree(ioc_attr);
        }
 
-       strncpy(drvinfo->bus_info, pci_name(bnad->pcidev), ETHTOOL_BUSINFO_LEN);
+       strlcpy(drvinfo->bus_info, pci_name(bnad->pcidev),
+               sizeof(drvinfo->bus_info));
 }
 
 static void
index 1b3e90d..32e8f17 100644 (file)
@@ -43,8 +43,7 @@ extern char bfa_version[];
 
 #pragma pack(1)
 
-#define MAC_ADDRLEN    (6)
-typedef struct mac { u8 mac[MAC_ADDRLEN]; } mac_t;
+typedef struct mac { u8 mac[ETH_ALEN]; } mac_t;
 
 #pragma pack()
 
index 98849a1..b48378a 100644 (file)
@@ -7,6 +7,7 @@ config HAVE_NET_MACB
 
 config NET_ATMEL
        bool "Atmel devices"
+       default y
        depends on HAVE_NET_MACB || (ARM && ARCH_AT91RM9200)
        ---help---
          If you have a network (Ethernet) card belonging to this class, say Y.
index ca26d97..1d17c92 100644 (file)
@@ -434,10 +434,10 @@ static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
        struct adapter *adapter = dev->ml_priv;
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->fw_version, "N/A");
-       strcpy(info->bus_info, pci_name(adapter->pdev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(adapter->pdev),
+               sizeof(info->bus_info));
 }
 
 static int get_sset_count(struct net_device *dev, int sset)
@@ -849,7 +849,8 @@ static int t1_set_mac_addr(struct net_device *dev, void *p)
        return 0;
 }
 
-static u32 t1_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t t1_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        /*
         * Since there is no support for separate rx/tx vlan accel
@@ -863,9 +864,9 @@ static u32 t1_fix_features(struct net_device *dev, u32 features)
        return features;
 }
 
-static int t1_set_features(struct net_device *dev, u32 features)
+static int t1_set_features(struct net_device *dev, netdev_features_t features)
 {
-       u32 changed = dev->features ^ features;
+       netdev_features_t changed = dev->features ^ features;
        struct adapter *adapter = dev->ml_priv;
 
        if (changed & NETIF_F_HW_VLAN_RX)
index f9b6023..47a8435 100644 (file)
@@ -742,7 +742,7 @@ static inline void setup_ring_params(struct adapter *adapter, u64 addr,
 /*
  * Enable/disable VLAN acceleration.
  */
-void t1_vlan_mode(struct adapter *adapter, u32 features)
+void t1_vlan_mode(struct adapter *adapter, netdev_features_t features)
 {
        struct sge *sge = adapter->sge;
 
index e03980b..b9bf16b 100644 (file)
@@ -79,7 +79,7 @@ irqreturn_t t1_interrupt(int irq, void *cookie);
 int t1_poll(struct napi_struct *, int);
 
 netdev_tx_t t1_start_xmit(struct sk_buff *skb, struct net_device *dev);
-void t1_vlan_mode(struct adapter *adapter, u32 features);
+void t1_vlan_mode(struct adapter *adapter, netdev_features_t features);
 void t1_sge_start(struct sge *);
 void t1_sge_stop(struct sge *);
 int t1_sge_intr_error_handler(struct sge *);
index 4d15c8f..857cc25 100644 (file)
@@ -1576,12 +1576,11 @@ static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
        t3_get_tp_version(adapter, &tp_vers);
        spin_unlock(&adapter->stats_lock);
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, pci_name(adapter->pdev));
-       if (!fw_vers)
-               strcpy(info->fw_version, "N/A");
-       else {
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(adapter->pdev),
+               sizeof(info->bus_info));
+       if (fw_vers)
                snprintf(info->fw_version, sizeof(info->fw_version),
                         "%s %u.%u.%u TP %u.%u.%u",
                         G_FW_VERSION_TYPE(fw_vers) ? "T" : "N",
@@ -1591,7 +1590,6 @@ static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
                         G_TP_VERSION_MAJOR(tp_vers),
                         G_TP_VERSION_MINOR(tp_vers),
                         G_TP_VERSION_MICRO(tp_vers));
-       }
 }
 
 static void get_strings(struct net_device *dev, u32 stringset, u8 * data)
@@ -2531,7 +2529,7 @@ static void t3_synchronize_rx(struct adapter *adap, const struct port_info *p)
        }
 }
 
-static void cxgb_vlan_mode(struct net_device *dev, u32 features)
+static void cxgb_vlan_mode(struct net_device *dev, netdev_features_t features)
 {
        struct port_info *pi = netdev_priv(dev);
        struct adapter *adapter = pi->adapter;
@@ -2552,7 +2550,8 @@ static void cxgb_vlan_mode(struct net_device *dev, u32 features)
        t3_synchronize_rx(adapter, pi);
 }
 
-static u32 cxgb_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t cxgb_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        /*
         * Since there is no support for separate rx/tx vlan accel
@@ -2566,9 +2565,9 @@ static u32 cxgb_fix_features(struct net_device *dev, u32 features)
        return features;
 }
 
-static int cxgb_set_features(struct net_device *dev, u32 features)
+static int cxgb_set_features(struct net_device *dev, netdev_features_t features)
 {
-       u32 changed = dev->features ^ features;
+       netdev_features_t changed = dev->features ^ features;
 
        if (changed & NETIF_F_HW_VLAN_RX)
                cxgb_vlan_mode(dev, features);
index 90ff131..7f7882d 100644 (file)
@@ -1301,7 +1301,7 @@ int cxgb3_offload_activate(struct adapter *adapter)
 
 out_free_l2t:
        t3_free_l2t(L2DATA(dev));
-       rcu_assign_pointer(dev->l2opt, NULL);
+       RCU_INIT_POINTER(dev->l2opt, NULL);
 out_free:
        kfree(t);
        return err;
@@ -1329,7 +1329,7 @@ void cxgb3_offload_deactivate(struct adapter *adapter)
        rcu_read_lock();
        d = L2DATA(tdev);
        rcu_read_unlock();
-       rcu_assign_pointer(tdev->l2opt, NULL);
+       RCU_INIT_POINTER(tdev->l2opt, NULL);
        call_rcu(&d->rcu_head, clean_l2_data);
        if (t->nofail_skb)
                kfree_skb(t->nofail_skb);
index 4c8f42a..a34e7ce 100644 (file)
@@ -1002,13 +1002,12 @@ static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
        struct adapter *adapter = netdev2adap(dev);
 
-       strcpy(info->driver, KBUILD_MODNAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, pci_name(adapter->pdev));
+       strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(adapter->pdev),
+               sizeof(info->bus_info));
 
-       if (!adapter->params.fw_vers)
-               strcpy(info->fw_version, "N/A");
-       else
+       if (adapter->params.fw_vers)
                snprintf(info->fw_version, sizeof(info->fw_version),
                        "%u.%u.%u.%u, TP %u.%u.%u.%u",
                        FW_HDR_FW_VER_MAJOR_GET(adapter->params.fw_vers),
@@ -1855,10 +1854,10 @@ static int set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
        return err;
 }
 
-static int cxgb_set_features(struct net_device *dev, u32 features)
+static int cxgb_set_features(struct net_device *dev, netdev_features_t features)
 {
        const struct port_info *pi = netdev_priv(dev);
-       u32 changed = dev->features ^ features;
+       netdev_features_t changed = dev->features ^ features;
        int err;
 
        if (!(changed & NETIF_F_HW_VLAN_RX))
@@ -3537,7 +3536,7 @@ static int __devinit init_one(struct pci_dev *pdev,
 {
        int func, i, err;
        struct port_info *pi;
-       unsigned int highdma = 0;
+       bool highdma = false;
        struct adapter *adapter = NULL;
 
        printk_once(KERN_INFO "%s - version %s\n", DRV_DESC, DRV_VERSION);
@@ -3563,7 +3562,7 @@ static int __devinit init_one(struct pci_dev *pdev,
        }
 
        if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
-               highdma = NETIF_F_HIGHDMA;
+               highdma = true;
                err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
                if (err) {
                        dev_err(&pdev->dev, "unable to obtain 64-bit DMA for "
@@ -3637,7 +3636,9 @@ static int __devinit init_one(struct pci_dev *pdev,
                        NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
                        NETIF_F_RXCSUM | NETIF_F_RXHASH |
                        NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
-               netdev->features |= netdev->hw_features | highdma;
+               if (highdma)
+                       netdev->hw_features |= NETIF_F_HIGHDMA;
+               netdev->features |= netdev->hw_features;
                netdev->vlan_features = netdev->features & VLAN_FEAT;
 
                netdev->priv_flags |= IFF_UNICAST_FLT;
index 140254c..2dae795 100644 (file)
@@ -491,7 +491,7 @@ static unsigned int refill_fl(struct adapter *adap, struct sge_fl *q, int n,
        __be64 *d = &q->desc[q->pidx];
        struct rx_sw_desc *sd = &q->sdesc[q->pidx];
 
-       gfp |= __GFP_NOWARN;         /* failures are expected */
+       gfp |= __GFP_NOWARN | __GFP_COLD;
 
 #if FL_PG_ORDER > 0
        /*
@@ -528,7 +528,7 @@ static unsigned int refill_fl(struct adapter *adap, struct sge_fl *q, int n,
 #endif
 
        while (n--) {
-               pg = __netdev_alloc_page(adap->port[0], gfp);
+               pg = alloc_page(gfp);
                if (unlikely(!pg)) {
                        q->alloc_failed++;
                        break;
@@ -537,7 +537,7 @@ static unsigned int refill_fl(struct adapter *adap, struct sge_fl *q, int n,
                mapping = dma_map_page(adap->pdev_dev, pg, 0, PAGE_SIZE,
                                       PCI_DMA_FROMDEVICE);
                if (unlikely(dma_mapping_error(adap->pdev_dev, mapping))) {
-                       netdev_free_page(adap->port[0], pg);
+                       put_page(pg);
                        goto out;
                }
                *d++ = cpu_to_be64(mapping);
index da9072b..8155cfe 100644 (file)
@@ -1092,7 +1092,8 @@ static int cxgb4vf_change_mtu(struct net_device *dev, int new_mtu)
        return ret;
 }
 
-static u32 cxgb4vf_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t cxgb4vf_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        /*
         * Since there is no support for separate rx/tx vlan accel
@@ -1106,10 +1107,11 @@ static u32 cxgb4vf_fix_features(struct net_device *dev, u32 features)
        return features;
 }
 
-static int cxgb4vf_set_features(struct net_device *dev, u32 features)
+static int cxgb4vf_set_features(struct net_device *dev,
+       netdev_features_t features)
 {
        struct port_info *pi = netdev_priv(dev);
-       u32 changed = dev->features ^ features;
+       netdev_features_t changed = dev->features ^ features;
 
        if (changed & NETIF_F_HW_VLAN_RX)
                t4vf_set_rxmode(pi->adapter, pi->viid, -1, -1, -1, -1,
@@ -1203,9 +1205,10 @@ static void cxgb4vf_get_drvinfo(struct net_device *dev,
 {
        struct adapter *adapter = netdev2adap(dev);
 
-       strcpy(drvinfo->driver, KBUILD_MODNAME);
-       strcpy(drvinfo->version, DRV_VERSION);
-       strcpy(drvinfo->bus_info, pci_name(to_pci_dev(dev->dev.parent)));
+       strlcpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
+       strlcpy(drvinfo->bus_info, pci_name(to_pci_dev(dev->dev.parent)),
+               sizeof(drvinfo->bus_info));
        snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
                 "%u.%u.%u.%u, TP %u.%u.%u.%u",
                 FW_HDR_FW_VER_MAJOR_GET(adapter->params.dev.fwrev),
index 8d5d55a..c381db2 100644 (file)
@@ -653,8 +653,7 @@ static unsigned int refill_fl(struct adapter *adapter, struct sge_fl *fl,
 
 alloc_small_pages:
        while (n--) {
-               page = __netdev_alloc_page(adapter->port[0],
-                                          gfp | __GFP_NOWARN);
+               page = alloc_page(gfp | __GFP_NOWARN | __GFP_COLD);
                if (unlikely(!page)) {
                        fl->alloc_failed++;
                        break;
@@ -664,7 +663,7 @@ alloc_small_pages:
                dma_addr = dma_map_page(adapter->pdev_dev, page, 0, PAGE_SIZE,
                                       PCI_DMA_FROMDEVICE);
                if (unlikely(dma_mapping_error(adapter->pdev_dev, dma_addr))) {
-                       netdev_free_page(adapter->port[0], page);
+                       put_page(page);
                        break;
                }
                *d++ = cpu_to_be64(dma_addr);
index c3786fd..1fe5df0 100644 (file)
@@ -217,11 +217,11 @@ static void enic_get_drvinfo(struct net_device *netdev,
 
        enic_dev_fw_info(enic, &fw_info);
 
-       strncpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
-       strncpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
-       strncpy(drvinfo->fw_version, fw_info->fw_version,
+       strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
+       strlcpy(drvinfo->fw_version, fw_info->fw_version,
                sizeof(drvinfo->fw_version));
-       strncpy(drvinfo->bus_info, pci_name(enic->pdev),
+       strlcpy(drvinfo->bus_info, pci_name(enic->pdev),
                sizeof(drvinfo->bus_info));
 }
 
index 438f458..26be1df 100644 (file)
@@ -474,10 +474,11 @@ static int dm9000_nway_reset(struct net_device *dev)
        return mii_nway_restart(&dm->mii);
 }
 
-static int dm9000_set_features(struct net_device *dev, u32 features)
+static int dm9000_set_features(struct net_device *dev,
+       netdev_features_t features)
 {
        board_info_t *dm = to_dm9000_board(dev);
-       u32 changed = dev->features ^ features;
+       netdev_features_t changed = dev->features ^ features;
        unsigned long flags;
 
        if (!(changed & NETIF_F_RXCSUM))
index 1427739..1eb46a0 100644 (file)
@@ -1598,9 +1598,9 @@ static void de_get_drvinfo (struct net_device *dev,struct ethtool_drvinfo *info)
 {
        struct de_private *de = netdev_priv(dev);
 
-       strcpy (info->driver, DRV_NAME);
-       strcpy (info->version, DRV_VERSION);
-       strcpy (info->bus_info, pci_name(de->pdev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(de->pdev), sizeof(info->bus_info));
        info->eedump_len = DE_EEPROM_SIZE;
 }
 
index 17b11ee..51f7542 100644 (file)
@@ -1085,10 +1085,11 @@ static void dmfe_ethtool_get_drvinfo(struct net_device *dev,
 {
        struct dmfe_board_info *np = netdev_priv(dev);
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
        if (np->pdev)
-               strcpy(info->bus_info, pci_name(np->pdev));
+               strlcpy(info->bus_info, pci_name(np->pdev),
+                       sizeof(info->bus_info));
        else
                sprintf(info->bus_info, "EISA 0x%lx %d",
                        dev->base_addr, dev->irq);
index 9656dd0..4eb0d76 100644 (file)
@@ -871,9 +871,9 @@ static struct net_device_stats *tulip_get_stats(struct net_device *dev)
 static void tulip_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
        struct tulip_private *np = netdev_priv(dev);
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, pci_name(np->pdev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(np->pdev), sizeof(info->bus_info));
 }
 
 
index 7a44a7a..48b0b65 100644 (file)
@@ -960,10 +960,11 @@ static void netdev_get_drvinfo(struct net_device *dev,
 {
        struct uli526x_board_info *np = netdev_priv(dev);
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
        if (np->pdev)
-               strcpy(info->bus_info, pci_name(np->pdev));
+               strlcpy(info->bus_info, pci_name(np->pdev),
+                       sizeof(info->bus_info));
        else
                sprintf(info->bus_info, "EISA 0x%lx %d",
                        dev->base_addr, dev->irq);
index 4d01219..52da7b2 100644 (file)
@@ -1390,9 +1390,9 @@ static void netdev_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *
 {
        struct netdev_private *np = netdev_priv(dev);
 
-       strcpy (info->driver, DRV_NAME);
-       strcpy (info->version, DRV_VERSION);
-       strcpy (info->bus_info, pci_name(np->pci_dev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(np->pci_dev), sizeof(info->bus_info));
 }
 
 static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
index dcd7f7a..28a3a9b 100644 (file)
@@ -1634,9 +1634,9 @@ static int check_if_running(struct net_device *dev)
 static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
        struct netdev_private *np = netdev_priv(dev);
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, pci_name(np->pci_dev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(np->pci_dev), sizeof(info->bus_info));
 }
 
 static int get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
index c1063d1..d94b968 100644 (file)
@@ -804,9 +804,9 @@ static int dnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 static void dnet_get_drvinfo(struct net_device *dev,
                             struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, "0");
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, "0", sizeof(info->bus_info));
 }
 
 static const struct ethtool_ops dnet_ethtool_ops = {
index 644e8fe..34f162d 100644 (file)
@@ -289,14 +289,12 @@ struct be_drv_stats {
 
 struct be_vf_cfg {
        unsigned char vf_mac_addr[ETH_ALEN];
-       u32 vf_if_handle;
-       u32 vf_pmac_id;
+       int vf_if_handle;
+       int vf_pmac_id;
        u16 vf_vlan_tag;
        u32 vf_tx_rate;
 };
 
-#define BE_INVALID_PMAC_ID             0xffffffff
-
 struct be_adapter {
        struct pci_dev *pdev;
        struct net_device *netdev;
@@ -347,11 +345,13 @@ struct be_adapter {
 
        /* Ethtool knobs and info */
        char fw_ver[FW_VER_LEN];
-       u32 if_handle;          /* Used to configure filtering */
+       int if_handle;          /* Used to configure filtering */
        u32 pmac_id;            /* MAC addr handle used by BE card */
        u32 beacon_state;       /* for set_phys_id */
 
        bool eeh_err;
+       bool ue_detected;
+       bool fw_timeout;
        u32 port_num;
        bool promiscuous;
        bool wol;
@@ -359,7 +359,6 @@ struct be_adapter {
        u32 function_caps;
        u32 rx_fc;              /* Rx flow control */
        u32 tx_fc;              /* Tx flow control */
-       bool ue_detected;
        bool stats_cmd_sent;
        int link_speed;
        u8 port_type;
@@ -524,6 +523,11 @@ static inline bool be_multi_rxq(const struct be_adapter *adapter)
        return adapter->num_rx_qs > 1;
 }
 
+static inline bool be_error(struct be_adapter *adapter)
+{
+       return adapter->eeh_err || adapter->ue_detected || adapter->fw_timeout;
+}
+
 extern void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm,
                u16 num_popped);
 extern void be_link_status_update(struct be_adapter *adapter, u32 link_status);
index 2c7b366..64f0c1a 100644 (file)
@@ -31,11 +31,8 @@ static void be_mcc_notify(struct be_adapter *adapter)
        struct be_queue_info *mccq = &adapter->mcc_obj.q;
        u32 val = 0;
 
-       if (adapter->eeh_err) {
-               dev_info(&adapter->pdev->dev,
-                       "Error in Card Detected! Cannot issue commands\n");
+       if (be_error(adapter))
                return;
-       }
 
        val |= mccq->id & DB_MCCQ_RING_ID_MASK;
        val |= 1 << DB_MCCQ_NUM_POSTED_SHIFT;
@@ -266,10 +263,10 @@ static int be_mcc_wait_compl(struct be_adapter *adapter)
        int i, num, status = 0;
        struct be_mcc_obj *mcc_obj = &adapter->mcc_obj;
 
-       if (adapter->eeh_err)
-               return -EIO;
-
        for (i = 0; i < mcc_timeout; i++) {
+               if (be_error(adapter))
+                       return -EIO;
+
                num = be_process_mcc(adapter, &status);
                if (num)
                        be_cq_notify(adapter, mcc_obj->cq.id,
@@ -280,7 +277,8 @@ static int be_mcc_wait_compl(struct be_adapter *adapter)
                udelay(100);
        }
        if (i == mcc_timeout) {
-               dev_err(&adapter->pdev->dev, "mccq poll timed out\n");
+               dev_err(&adapter->pdev->dev, "FW not responding\n");
+               adapter->fw_timeout = true;
                return -1;
        }
        return status;
@@ -298,26 +296,21 @@ static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db)
        int msecs = 0;
        u32 ready;
 
-       if (adapter->eeh_err) {
-               dev_err(&adapter->pdev->dev,
-                       "Error detected in card.Cannot issue commands\n");
-               return -EIO;
-       }
-
        do {
+               if (be_error(adapter))
+                       return -EIO;
+
                ready = ioread32(db);
-               if (ready == 0xffffffff) {
-                       dev_err(&adapter->pdev->dev,
-                               "pci slot disconnected\n");
+               if (ready == 0xffffffff)
                        return -1;
-               }
 
                ready &= MPU_MAILBOX_DB_RDY_MASK;
                if (ready)
                        break;
 
                if (msecs > 4000) {
-                       dev_err(&adapter->pdev->dev, "mbox poll timed out\n");
+                       dev_err(&adapter->pdev->dev, "FW not responding\n");
+                       adapter->fw_timeout = true;
                        be_detect_dump_ue(adapter);
                        return -1;
                }
@@ -555,9 +548,6 @@ int be_cmd_fw_clean(struct be_adapter *adapter)
        u8 *wrb;
        int status;
 
-       if (adapter->eeh_err)
-               return -EIO;
-
        if (mutex_lock_interruptible(&adapter->mbox_lock))
                return -1;
 
@@ -695,12 +685,15 @@ err:
 }
 
 /* Uses synchronous MCCQ */
-int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, u32 pmac_id, u32 dom)
+int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, int pmac_id, u32 dom)
 {
        struct be_mcc_wrb *wrb;
        struct be_cmd_req_pmac_del *req;
        int status;
 
+       if (pmac_id == -1)
+               return 0;
+
        spin_lock_bh(&adapter->mcc_lock);
 
        wrb = wrb_from_mccq(adapter);
@@ -923,10 +916,14 @@ int be_cmd_txq_create(struct be_adapter *adapter,
        void *ctxt;
        int status;
 
-       if (mutex_lock_interruptible(&adapter->mbox_lock))
-               return -1;
+       spin_lock_bh(&adapter->mcc_lock);
+
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+               status = -EBUSY;
+               goto err;
+       }
 
-       wrb = wrb_from_mbox(adapter);
        req = embedded_payload(wrb);
        ctxt = &req->context;
 
@@ -952,14 +949,15 @@ int be_cmd_txq_create(struct be_adapter *adapter,
 
        be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
 
-       status = be_mbox_notify_wait(adapter);
+       status = be_mcc_notify_wait(adapter);
        if (!status) {
                struct be_cmd_resp_eth_tx_create *resp = embedded_payload(wrb);
                txq->id = le16_to_cpu(resp->cid);
                txq->created = true;
        }
 
-       mutex_unlock(&adapter->mbox_lock);
+err:
+       spin_unlock_bh(&adapter->mcc_lock);
 
        return status;
 }
@@ -1018,9 +1016,6 @@ int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q,
        u8 subsys = 0, opcode = 0;
        int status;
 
-       if (adapter->eeh_err)
-               return -EIO;
-
        if (mutex_lock_interruptible(&adapter->mbox_lock))
                return -1;
 
@@ -1136,16 +1131,13 @@ err:
 }
 
 /* Uses MCCQ */
-int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id, u32 domain)
+int be_cmd_if_destroy(struct be_adapter *adapter, int interface_id, u32 domain)
 {
        struct be_mcc_wrb *wrb;
        struct be_cmd_req_if_destroy *req;
        int status;
 
-       if (adapter->eeh_err)
-               return -EIO;
-
-       if (!interface_id)
+       if (interface_id == -1)
                return 0;
 
        spin_lock_bh(&adapter->mcc_lock);
@@ -1254,6 +1246,9 @@ int be_cmd_link_status_query(struct be_adapter *adapter, u8 *mac_speed,
        }
        req = embedded_payload(wrb);
 
+       if (lancer_chip(adapter))
+               req->hdr.version = 1;
+
        be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
                OPCODE_COMMON_NTWK_LINK_STATUS_QUERY, sizeof(*req), wrb, NULL);
 
@@ -1836,6 +1831,53 @@ err_unlock:
        return status;
 }
 
+int lancer_cmd_read_object(struct be_adapter *adapter, struct be_dma_mem *cmd,
+               u32 data_size, u32 data_offset, const char *obj_name,
+               u32 *data_read, u32 *eof, u8 *addn_status)
+{
+       struct be_mcc_wrb *wrb;
+       struct lancer_cmd_req_read_object *req;
+       struct lancer_cmd_resp_read_object *resp;
+       int status;
+
+       spin_lock_bh(&adapter->mcc_lock);
+
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+               status = -EBUSY;
+               goto err_unlock;
+       }
+
+       req = embedded_payload(wrb);
+
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+                       OPCODE_COMMON_READ_OBJECT,
+                       sizeof(struct lancer_cmd_req_read_object), wrb,
+                       NULL);
+
+       req->desired_read_len = cpu_to_le32(data_size);
+       req->read_offset = cpu_to_le32(data_offset);
+       strcpy(req->object_name, obj_name);
+       req->descriptor_count = cpu_to_le32(1);
+       req->buf_len = cpu_to_le32(data_size);
+       req->addr_low = cpu_to_le32((cmd->dma & 0xFFFFFFFF));
+       req->addr_high = cpu_to_le32(upper_32_bits(cmd->dma));
+
+       status = be_mcc_notify_wait(adapter);
+
+       resp = embedded_payload(wrb);
+       if (!status) {
+               *data_read = le32_to_cpu(resp->actual_read_len);
+               *eof = le32_to_cpu(resp->eof);
+       } else {
+               *addn_status = resp->additional_status;
+       }
+
+err_unlock:
+       spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+}
+
 int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd,
                        u32 flash_type, u32 flash_opcode, u32 buf_size)
 {
index a35cd03..ac11246 100644 (file)
@@ -189,6 +189,7 @@ struct be_mcc_mailbox {
 #define OPCODE_COMMON_GET_PHY_DETAILS                  102
 #define OPCODE_COMMON_SET_DRIVER_FUNCTION_CAP          103
 #define OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES   121
+#define OPCODE_COMMON_READ_OBJECT                      171
 #define OPCODE_COMMON_WRITE_OBJECT                     172
 
 #define OPCODE_ETH_RSS_CONFIG                          1
@@ -1161,6 +1162,38 @@ struct lancer_cmd_resp_write_object {
        u32 actual_write_len;
 };
 
+/************************ Lancer Read FW info **************/
+#define LANCER_READ_FILE_CHUNK                 (32*1024)
+#define LANCER_READ_FILE_EOF_MASK              0x80000000
+
+#define LANCER_FW_DUMP_FILE                    "/dbg/dump.bin"
+#define LANCER_VPD_PF_FILE                     "/vpd/ntr_pf.vpd"
+#define LANCER_VPD_VF_FILE                     "/vpd/ntr_vf.vpd"
+
+struct lancer_cmd_req_read_object {
+       struct be_cmd_req_hdr hdr;
+       u32 desired_read_len;
+       u32 read_offset;
+       u8 object_name[104];
+       u32 descriptor_count;
+       u32 buf_len;
+       u32 addr_low;
+       u32 addr_high;
+};
+
+struct lancer_cmd_resp_read_object {
+       u8 opcode;
+       u8 subsystem;
+       u8 rsvd1[2];
+       u8 status;
+       u8 additional_status;
+       u8 rsvd2[2];
+       u32 resp_len;
+       u32 actual_resp_len;
+       u32 actual_read_len;
+       u32 eof;
+};
+
 /************************ WOL *******************************/
 struct be_cmd_req_acpi_wol_magic_config{
        struct be_cmd_req_hdr hdr;
@@ -1417,11 +1450,11 @@ extern int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr,
 extern int be_cmd_pmac_add(struct be_adapter *adapter, u8 *mac_addr,
                        u32 if_id, u32 *pmac_id, u32 domain);
 extern int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id,
-                       u32 pmac_id, u32 domain);
+                       int pmac_id, u32 domain);
 extern int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags,
                        u32 en_flags, u8 *mac, u32 *if_handle, u32 *pmac_id,
                        u32 domain);
-extern int be_cmd_if_destroy(struct be_adapter *adapter, u32 if_handle,
+extern int be_cmd_if_destroy(struct be_adapter *adapter, int if_handle,
                        u32 domain);
 extern int be_cmd_eq_create(struct be_adapter *adapter,
                        struct be_queue_info *eq, int eq_delay);
@@ -1480,6 +1513,9 @@ extern int lancer_cmd_write_object(struct be_adapter *adapter,
                                u32 data_size, u32 data_offset,
                                const char *obj_name,
                                u32 *data_written, u8 *addn_status);
+int lancer_cmd_read_object(struct be_adapter *adapter, struct be_dma_mem *cmd,
+               u32 data_size, u32 data_offset, const char *obj_name,
+               u32 *data_read, u32 *eof, u8 *addn_status);
 int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc,
                                int offset);
 extern int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac,
index bf8153e..575c783 100644 (file)
@@ -127,8 +127,8 @@ static void be_get_drvinfo(struct net_device *netdev,
        memset(fw_on_flash, 0 , sizeof(fw_on_flash));
        be_cmd_get_fw_ver(adapter, adapter->fw_ver, fw_on_flash);
 
-       strcpy(drvinfo->driver, DRV_NAME);
-       strcpy(drvinfo->version, DRV_VER);
+       strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, DRV_VER, sizeof(drvinfo->version));
        strncpy(drvinfo->fw_version, adapter->fw_ver, FW_VER_LEN);
        if (memcmp(adapter->fw_ver, fw_on_flash, FW_VER_LEN) != 0) {
                strcat(drvinfo->fw_version, " [");
@@ -136,21 +136,84 @@ static void be_get_drvinfo(struct net_device *netdev,
                strcat(drvinfo->fw_version, "]");
        }
 
-       strcpy(drvinfo->bus_info, pci_name(adapter->pdev));
+       strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
+               sizeof(drvinfo->bus_info));
        drvinfo->testinfo_len = 0;
        drvinfo->regdump_len = 0;
        drvinfo->eedump_len = 0;
 }
 
+static u32
+lancer_cmd_get_file_len(struct be_adapter *adapter, u8 *file_name)
+{
+       u32 data_read = 0, eof;
+       u8 addn_status;
+       struct be_dma_mem data_len_cmd;
+       int status;
+
+       memset(&data_len_cmd, 0, sizeof(data_len_cmd));
+       /* data_offset and data_size should be 0 to get reg len */
+       status = lancer_cmd_read_object(adapter, &data_len_cmd, 0, 0,
+                               file_name, &data_read, &eof, &addn_status);
+
+       return data_read;
+}
+
+static int
+lancer_cmd_read_file(struct be_adapter *adapter, u8 *file_name,
+               u32 buf_len, void *buf)
+{
+       struct be_dma_mem read_cmd;
+       u32 read_len = 0, total_read_len = 0, chunk_size;
+       u32 eof = 0;
+       u8 addn_status;
+       int status = 0;
+
+       read_cmd.size = LANCER_READ_FILE_CHUNK;
+       read_cmd.va = pci_alloc_consistent(adapter->pdev, read_cmd.size,
+                       &read_cmd.dma);
+
+       if (!read_cmd.va) {
+               dev_err(&adapter->pdev->dev,
+                               "Memory allocation failure while reading dump\n");
+               return -ENOMEM;
+       }
+
+       while ((total_read_len < buf_len) && !eof) {
+               chunk_size = min_t(u32, (buf_len - total_read_len),
+                               LANCER_READ_FILE_CHUNK);
+               chunk_size = ALIGN(chunk_size, 4);
+               status = lancer_cmd_read_object(adapter, &read_cmd, chunk_size,
+                               total_read_len, file_name, &read_len,
+                               &eof, &addn_status);
+               if (!status) {
+                       memcpy(buf + total_read_len, read_cmd.va, read_len);
+                       total_read_len += read_len;
+                       eof &= LANCER_READ_FILE_EOF_MASK;
+               } else {
+                       status = -EIO;
+                       break;
+               }
+       }
+       pci_free_consistent(adapter->pdev, read_cmd.size, read_cmd.va,
+                       read_cmd.dma);
+
+       return status;
+}
+
 static int
 be_get_reg_len(struct net_device *netdev)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
        u32 log_size = 0;
 
-       if (be_physfn(adapter))
-               be_cmd_get_reg_len(adapter, &log_size);
-
+       if (be_physfn(adapter)) {
+               if (lancer_chip(adapter))
+                       log_size = lancer_cmd_get_file_len(adapter,
+                                       LANCER_FW_DUMP_FILE);
+               else
+                       be_cmd_get_reg_len(adapter, &log_size);
+       }
        return log_size;
 }
 
@@ -161,7 +224,11 @@ be_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *buf)
 
        if (be_physfn(adapter)) {
                memset(buf, 0, regs->len);
-               be_cmd_get_regs(adapter, regs->len, buf);
+               if (lancer_chip(adapter))
+                       lancer_cmd_read_file(adapter, LANCER_FW_DUMP_FILE,
+                                       regs->len, buf);
+               else
+                       be_cmd_get_regs(adapter, regs->len, buf);
        }
 }
 
@@ -660,7 +727,17 @@ be_do_flash(struct net_device *netdev, struct ethtool_flash *efl)
 static int
 be_get_eeprom_len(struct net_device *netdev)
 {
-       return BE_READ_SEEPROM_LEN;
+       struct be_adapter *adapter = netdev_priv(netdev);
+       if (lancer_chip(adapter)) {
+               if (be_physfn(adapter))
+                       return lancer_cmd_get_file_len(adapter,
+                                       LANCER_VPD_PF_FILE);
+               else
+                       return lancer_cmd_get_file_len(adapter,
+                                       LANCER_VPD_VF_FILE);
+       } else {
+               return BE_READ_SEEPROM_LEN;
+       }
 }
 
 static int
@@ -675,6 +752,15 @@ be_read_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom,
        if (!eeprom->len)
                return -EINVAL;
 
+       if (lancer_chip(adapter)) {
+               if (be_physfn(adapter))
+                       return lancer_cmd_read_file(adapter, LANCER_VPD_PF_FILE,
+                                       eeprom->len, data);
+               else
+                       return lancer_cmd_read_file(adapter, LANCER_VPD_VF_FILE,
+                                       eeprom->len, data);
+       }
+
        eeprom->magic = BE_VENDOR_ID | (adapter->pdev->device<<16);
 
        memset(&eeprom_cmd, 0, sizeof(struct be_dma_mem));
index bf266a0..93869d4 100644 (file)
@@ -848,15 +848,11 @@ static int be_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
        if (!is_valid_ether_addr(mac) || (vf >= num_vfs))
                return -EINVAL;
 
-       if (adapter->vf_cfg[vf].vf_pmac_id != BE_INVALID_PMAC_ID)
-               status = be_cmd_pmac_del(adapter,
-                                       adapter->vf_cfg[vf].vf_if_handle,
-                                       adapter->vf_cfg[vf].vf_pmac_id, vf + 1);
+       status = be_cmd_pmac_del(adapter, adapter->vf_cfg[vf].vf_if_handle,
+                               adapter->vf_cfg[vf].vf_pmac_id, vf + 1);
 
-       status = be_cmd_pmac_add(adapter, mac,
-                               adapter->vf_cfg[vf].vf_if_handle,
+       status = be_cmd_pmac_add(adapter, mac, adapter->vf_cfg[vf].vf_if_handle,
                                &adapter->vf_cfg[vf].vf_pmac_id, vf + 1);
-
        if (status)
                dev_err(&adapter->pdev->dev, "MAC %pM set on VF %d Failed\n",
                                mac, vf);
@@ -1693,9 +1689,6 @@ static int be_tx_queues_create(struct be_adapter *adapter)
                if (be_queue_alloc(adapter, q, TX_Q_LEN,
                        sizeof(struct be_eth_wrb)))
                        goto err;
-
-               if (be_cmd_txq_create(adapter, q, cq))
-                       goto err;
        }
        return 0;
 
@@ -1982,6 +1975,9 @@ void be_detect_dump_ue(struct be_adapter *adapter)
        u32 sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0;
        u32 i;
 
+       if (adapter->eeh_err || adapter->ue_detected)
+               return;
+
        if (lancer_chip(adapter)) {
                sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET);
                if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
@@ -2008,7 +2004,8 @@ void be_detect_dump_ue(struct be_adapter *adapter)
                sliport_status & SLIPORT_STATUS_ERR_MASK) {
                adapter->ue_detected = true;
                adapter->eeh_err = true;
-               dev_err(&adapter->pdev->dev, "UE Detected!!\n");
+               dev_err(&adapter->pdev->dev,
+                       "Unrecoverable error in the card\n");
        }
 
        if (ue_lo) {
@@ -2043,8 +2040,7 @@ static void be_worker(struct work_struct *work)
        struct be_rx_obj *rxo;
        int i;
 
-       if (!adapter->ue_detected)
-               be_detect_dump_ue(adapter);
+       be_detect_dump_ue(adapter);
 
        /* when interrupts are not yet enabled, just reap any pending
        * mcc completions */
@@ -2488,17 +2484,13 @@ static void be_vf_clear(struct be_adapter *adapter)
 {
        u32 vf;
 
-       for (vf = 0; vf < num_vfs; vf++) {
-               if (adapter->vf_cfg[vf].vf_pmac_id != BE_INVALID_PMAC_ID)
-                       be_cmd_pmac_del(adapter,
-                                       adapter->vf_cfg[vf].vf_if_handle,
-                                       adapter->vf_cfg[vf].vf_pmac_id, vf + 1);
-       }
+       for (vf = 0; vf < num_vfs; vf++)
+               be_cmd_pmac_del(adapter, adapter->vf_cfg[vf].vf_if_handle,
+                               adapter->vf_cfg[vf].vf_pmac_id, vf + 1);
 
        for (vf = 0; vf < num_vfs; vf++)
-               if (adapter->vf_cfg[vf].vf_if_handle)
-                       be_cmd_if_destroy(adapter,
-                               adapter->vf_cfg[vf].vf_if_handle, vf + 1);
+               be_cmd_if_destroy(adapter, adapter->vf_cfg[vf].vf_if_handle,
+                               vf + 1);
 }
 
 static int be_clear(struct be_adapter *adapter)
@@ -2511,22 +2503,30 @@ static int be_clear(struct be_adapter *adapter)
        be_mcc_queues_destroy(adapter);
        be_rx_queues_destroy(adapter);
        be_tx_queues_destroy(adapter);
-       adapter->eq_next_idx = 0;
-
-       adapter->be3_native = false;
-       adapter->promiscuous = false;
 
        /* tell fw we're done with firing cmds */
        be_cmd_fw_clean(adapter);
        return 0;
 }
 
+static void be_vf_setup_init(struct be_adapter *adapter)
+{
+       int vf;
+
+       for (vf = 0; vf < num_vfs; vf++) {
+               adapter->vf_cfg[vf].vf_if_handle = -1;
+               adapter->vf_cfg[vf].vf_pmac_id = -1;
+       }
+}
+
 static int be_vf_setup(struct be_adapter *adapter)
 {
        u32 cap_flags, en_flags, vf;
        u16 lnk_speed;
        int status;
 
+       be_vf_setup_init(adapter);
+
        cap_flags = en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST;
        for (vf = 0; vf < num_vfs; vf++) {
                status = be_cmd_if_create(adapter, cap_flags, en_flags, NULL,
@@ -2534,7 +2534,6 @@ static int be_vf_setup(struct be_adapter *adapter)
                                        NULL, vf+1);
                if (status)
                        goto err;
-               adapter->vf_cfg[vf].vf_pmac_id = BE_INVALID_PMAC_ID;
        }
 
        if (!lancer_chip(adapter)) {
@@ -2555,17 +2554,26 @@ err:
        return status;
 }
 
+static void be_setup_init(struct be_adapter *adapter)
+{
+       adapter->vlan_prio_bmap = 0xff;
+       adapter->link_speed = -1;
+       adapter->if_handle = -1;
+       adapter->be3_native = false;
+       adapter->promiscuous = false;
+       adapter->eq_next_idx = 0;
+}
+
 static int be_setup(struct be_adapter *adapter)
 {
        struct net_device *netdev = adapter->netdev;
        u32 cap_flags, en_flags;
        u32 tx_fc, rx_fc;
-       int status;
+       int status, i;
        u8 mac[ETH_ALEN];
+       struct be_tx_obj *txo;
 
-       /* Allow all priorities by default. A GRP5 evt may modify this */
-       adapter->vlan_prio_bmap = 0xff;
-       adapter->link_speed = -1;
+       be_setup_init(adapter);
 
        be_cmd_req_native_mode(adapter);
 
@@ -2592,7 +2600,8 @@ static int be_setup(struct be_adapter *adapter)
        en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
                        BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_PASS_L3L4_ERRORS;
        cap_flags = en_flags | BE_IF_FLAGS_MCAST_PROMISCUOUS |
-                       BE_IF_FLAGS_PROMISCUOUS;
+                       BE_IF_FLAGS_VLAN_PROMISCUOUS | BE_IF_FLAGS_PROMISCUOUS;
+
        if (adapter->function_caps & BE_FUNCTION_CAPS_RSS) {
                cap_flags |= BE_IF_FLAGS_RSS;
                en_flags |= BE_IF_FLAGS_RSS;
@@ -2603,6 +2612,12 @@ static int be_setup(struct be_adapter *adapter)
        if (status != 0)
                goto err;
 
+        for_all_tx_queues(adapter, txo, i) {
+               status = be_cmd_txq_create(adapter, &txo->q, &txo->cq);
+               if (status)
+                       goto err;
+       }
+
        /* For BEx, the VF's permanent mac queried from card is incorrect.
         * Query the mac configued by the PF using if_handle
         */
@@ -3559,6 +3574,8 @@ static pci_ers_result_t be_eeh_reset(struct pci_dev *pdev)
 
        dev_info(&adapter->pdev->dev, "EEH reset\n");
        adapter->eeh_err = false;
+       adapter->ue_detected = false;
+       adapter->fw_timeout = false;
 
        status = pci_enable_device(pdev);
        if (status)
index 61d2bdd..c82d444 100644 (file)
@@ -1818,9 +1818,9 @@ static void netdev_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *i
 {
        struct netdev_private *np = netdev_priv(dev);
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, pci_name(np->pci_dev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(np->pci_dev), sizeof(info->bus_info));
 }
 
 static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
index 52f4e8a..8dee1ae 100644 (file)
@@ -183,28 +183,10 @@ void fsl_pq_mdio_bus_name(char *name, struct device_node *np)
 }
 EXPORT_SYMBOL_GPL(fsl_pq_mdio_bus_name);
 
-/* Scan the bus in reverse, looking for an empty spot */
-static int fsl_pq_mdio_find_free(struct mii_bus *new_bus)
-{
-       int i;
-
-       for (i = PHY_MAX_ADDR; i > 0; i--) {
-               u32 phy_id;
-
-               if (get_phy_id(new_bus, i, &phy_id))
-                       return -1;
-
-               if (phy_id == 0xffffffff)
-                       break;
-       }
-
-       return i;
-}
 
-
-#if defined(CONFIG_GIANFAR) || defined(CONFIG_GIANFAR_MODULE)
 static u32 __iomem *get_gfar_tbipa(struct fsl_pq_mdio __iomem *regs, struct device_node *np)
 {
+#if defined(CONFIG_GIANFAR) || defined(CONFIG_GIANFAR_MODULE)
        struct gfar __iomem *enet_regs;
 
        /*
@@ -220,15 +202,15 @@ static u32 __iomem *get_gfar_tbipa(struct fsl_pq_mdio __iomem *regs, struct devi
        } else if (of_device_is_compatible(np, "fsl,etsec2-mdio") ||
                        of_device_is_compatible(np, "fsl,etsec2-tbi")) {
                return of_iomap(np, 1);
-       } else
-               return NULL;
-}
+       }
 #endif
+       return NULL;
+}
 
 
-#if defined(CONFIG_UCC_GETH) || defined(CONFIG_UCC_GETH_MODULE)
 static int get_ucc_id_for_range(u64 start, u64 end, u32 *ucc_id)
 {
+#if defined(CONFIG_UCC_GETH) || defined(CONFIG_UCC_GETH_MODULE)
        struct device_node *np = NULL;
        int err = 0;
 
@@ -261,9 +243,10 @@ static int get_ucc_id_for_range(u64 start, u64 end, u32 *ucc_id)
                return err;
        else
                return -EINVAL;
-}
+#else
+       return -ENODEV;
 #endif
-
+}
 
 static int fsl_pq_mdio_probe(struct platform_device *ofdev)
 {
@@ -339,19 +322,13 @@ static int fsl_pq_mdio_probe(struct platform_device *ofdev)
                        of_device_is_compatible(np, "fsl,etsec2-mdio") ||
                        of_device_is_compatible(np, "fsl,etsec2-tbi") ||
                        of_device_is_compatible(np, "gianfar")) {
-#if defined(CONFIG_GIANFAR) || defined(CONFIG_GIANFAR_MODULE)
                tbipa = get_gfar_tbipa(regs, np);
                if (!tbipa) {
                        err = -EINVAL;
                        goto err_free_irqs;
                }
-#else
-               err = -ENODEV;
-               goto err_free_irqs;
-#endif
        } else if (of_device_is_compatible(np, "fsl,ucc-mdio") ||
                        of_device_is_compatible(np, "ucc_geth_phy")) {
-#if defined(CONFIG_UCC_GETH) || defined(CONFIG_UCC_GETH_MODULE)
                u32 id;
                static u32 mii_mng_master;
 
@@ -364,10 +341,6 @@ static int fsl_pq_mdio_probe(struct platform_device *ofdev)
                        mii_mng_master = id;
                        ucc_set_qe_mux_mii_mng(id - 1);
                }
-#else
-               err = -ENODEV;
-               goto err_free_irqs;
-#endif
        } else {
                err = -ENODEV;
                goto err_free_irqs;
@@ -383,26 +356,16 @@ static int fsl_pq_mdio_probe(struct platform_device *ofdev)
 
                if (prop)
                        tbiaddr = *prop;
-       }
-
-       if (tbiaddr == -1) {
-               out_be32(tbipa, 0);
 
-               tbiaddr = fsl_pq_mdio_find_free(new_bus);
-       }
-
-       /*
-        * We define TBIPA at 0 to be illegal, opting to fail for boards that
-        * have PHYs at 1-31, rather than change tbipa and rescan.
-        */
-       if (tbiaddr == 0) {
-               err = -EBUSY;
+               if (tbiaddr == -1) {
+                       err = -EBUSY;
 
-               goto err_free_irqs;
+                       goto err_free_irqs;
+               } else {
+                       out_be32(tbipa, tbiaddr);
+               }
        }
 
-       out_be32(tbipa, tbiaddr);
-
        err = of_mdiobus_register(new_bus, np);
        if (err) {
                printk (KERN_ERR "%s: Cannot register as MDIO bus\n",
index 83199fd..8e21ceb 100644 (file)
@@ -734,7 +734,7 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
 
        mac_addr = of_get_mac_address(np);
        if (mac_addr)
-               memcpy(dev->dev_addr, mac_addr, MAC_ADDR_LEN);
+               memcpy(dev->dev_addr, mac_addr, ETH_ALEN);
 
        if (model && !strcasecmp(model, "TSEC"))
                priv->device_flags =
@@ -2306,7 +2306,7 @@ void gfar_check_rx_parser_mode(struct gfar_private *priv)
 }
 
 /* Enables and disables VLAN insertion/extraction */
-void gfar_vlan_mode(struct net_device *dev, u32 features)
+void gfar_vlan_mode(struct net_device *dev, netdev_features_t features)
 {
        struct gfar_private *priv = netdev_priv(dev);
        struct gfar __iomem *regs = NULL;
@@ -3114,7 +3114,7 @@ static void gfar_set_multi(struct net_device *dev)
 static void gfar_clear_exact_match(struct net_device *dev)
 {
        int idx;
-       static const u8 zero_arr[MAC_ADDR_LEN] = {0, 0, 0, 0, 0, 0};
+       static const u8 zero_arr[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
 
        for(idx = 1;idx < GFAR_EM_NUM + 1;idx++)
                gfar_set_mac_for_addr(dev, idx, zero_arr);
@@ -3137,7 +3137,7 @@ static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr)
 {
        u32 tempval;
        struct gfar_private *priv = netdev_priv(dev);
-       u32 result = ether_crc(MAC_ADDR_LEN, addr);
+       u32 result = ether_crc(ETH_ALEN, addr);
        int width = priv->hash_width;
        u8 whichbit = (result >> (32 - width)) & 0x1f;
        u8 whichreg = result >> (32 - width + 5);
@@ -3158,7 +3158,7 @@ static void gfar_set_mac_for_addr(struct net_device *dev, int num,
        struct gfar_private *priv = netdev_priv(dev);
        struct gfar __iomem *regs = priv->gfargrp[0].regs;
        int idx;
-       char tmpbuf[MAC_ADDR_LEN];
+       char tmpbuf[ETH_ALEN];
        u32 tempval;
        u32 __iomem *macptr = &regs->macstnaddr1;
 
@@ -3166,8 +3166,8 @@ static void gfar_set_mac_for_addr(struct net_device *dev, int num,
 
        /* Now copy it into the mac registers backwards, cuz */
        /* little endian is silly */
-       for (idx = 0; idx < MAC_ADDR_LEN; idx++)
-               tmpbuf[MAC_ADDR_LEN - 1 - idx] = addr[idx];
+       for (idx = 0; idx < ETH_ALEN; idx++)
+               tmpbuf[ETH_ALEN - 1 - idx] = addr[idx];
 
        gfar_write(macptr, *((u32 *) (tmpbuf)));
 
index 9aa4377..fe7ac3a 100644 (file)
@@ -74,9 +74,6 @@ struct ethtool_rx_list {
  * will be the next highest multiple of 512 bytes. */
 #define INCREMENTAL_BUFFER_SIZE 512
 
-
-#define MAC_ADDR_LEN 6
-
 #define PHY_INIT_TIMEOUT 100000
 #define GFAR_PHY_CHANGE_TIME 2
 
@@ -1179,9 +1176,9 @@ extern void gfar_phy_test(struct mii_bus *bus, struct phy_device *phydev,
 extern void gfar_configure_coalescing(struct gfar_private *priv,
                unsigned long tx_mask, unsigned long rx_mask);
 void gfar_init_sysfs(struct net_device *dev);
-int gfar_set_features(struct net_device *dev, u32 features);
+int gfar_set_features(struct net_device *dev, netdev_features_t features);
 extern void gfar_check_rx_parser_mode(struct gfar_private *priv);
-extern void gfar_vlan_mode(struct net_device *dev, u32 features);
+extern void gfar_vlan_mode(struct net_device *dev, netdev_features_t features);
 
 extern const struct ethtool_ops gfar_ethtool_ops;
 
index 212736b..5890f4b 100644 (file)
@@ -519,12 +519,12 @@ static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rva
        return err;
 }
 
-int gfar_set_features(struct net_device *dev, u32 features)
+int gfar_set_features(struct net_device *dev, netdev_features_t features)
 {
        struct gfar_private *priv = netdev_priv(dev);
        unsigned long flags;
        int err = 0, i = 0;
-       u32 changed = dev->features ^ features;
+       netdev_features_t changed = dev->features ^ features;
 
        if (changed & (NETIF_F_HW_VLAN_TX|NETIF_F_HW_VLAN_RX))
                gfar_vlan_mode(dev, features);
@@ -1410,10 +1410,9 @@ static int gfar_optimize_filer_masks(struct filer_table *tab)
 
        /* We need a copy of the filer table because
         * we want to change its order */
-       temp_table = kmalloc(sizeof(*temp_table), GFP_KERNEL);
+       temp_table = kmemdup(tab, sizeof(*temp_table), GFP_KERNEL);
        if (temp_table == NULL)
                return -ENOMEM;
-       memcpy(temp_table, tab, sizeof(*temp_table));
 
        mask_table = kcalloc(MAX_FILER_CACHE_IDX / 2 + 1,
                        sizeof(struct gfar_mask_entry), GFP_KERNEL);
index b5dc027..ba2dc08 100644 (file)
@@ -443,7 +443,7 @@ static void hw_add_addr_in_hash(struct ucc_geth_private *ugeth,
 
 static inline int compare_addr(u8 **addr1, u8 **addr2)
 {
-       return memcmp(addr1, addr2, ENET_NUM_OCTETS_PER_ADDRESS);
+       return memcmp(addr1, addr2, ETH_ALEN);
 }
 
 #ifdef DEBUG
index d12fcad..2e395a2 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <linux/kernel.h>
 #include <linux/list.h>
+#include <linux/if_ether.h>
 
 #include <asm/immap_qe.h>
 #include <asm/qe.h>
@@ -881,7 +882,6 @@ struct ucc_geth_hardware_statistics {
 #define TX_RING_MOD_MASK(size)                  (size-1)
 #define RX_RING_MOD_MASK(size)                  (size-1)
 
-#define ENET_NUM_OCTETS_PER_ADDRESS             6
 #define ENET_GROUP_ADDR                         0x01   /* Group address mask
                                                           for ethernet
                                                           addresses */
@@ -1051,7 +1051,7 @@ enum ucc_geth_num_of_station_addresses {
 
 /* UCC GETH 82xx Ethernet Address Container */
 struct enet_addr_container {
-       u8 address[ENET_NUM_OCTETS_PER_ADDRESS];        /* ethernet address */
+       u8 address[ETH_ALEN];   /* ethernet address */
        enum ucc_geth_enet_address_recognition_location location;       /* location in
                                                                   82xx address
                                                                   recognition
@@ -1194,7 +1194,7 @@ struct ucc_geth_private {
        u16 cpucount[NUM_TX_QUEUES];
        u16 __iomem *p_cpucount[NUM_TX_QUEUES];
        int indAddrRegUsed[NUM_OF_PADDRS];
-       u8 paddr[NUM_OF_PADDRS][ENET_NUM_OCTETS_PER_ADDRESS];   /* ethernet address */
+       u8 paddr[NUM_OF_PADDRS][ETH_ALEN];      /* ethernet address */
        u8 numGroupAddrInHash;
        u8 numIndAddrInHash;
        u8 numIndAddrInReg;
index 1541675..ee84b47 100644 (file)
@@ -1058,9 +1058,10 @@ static void fjn_rx(struct net_device *dev)
 static void netdev_get_drvinfo(struct net_device *dev,
                               struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       sprintf(info->bus_info, "PCMCIA 0x%lx", dev->base_addr);
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       snprintf(info->bus_info, sizeof(info->bus_info),
+               "PCMCIA 0x%lx", dev->base_addr);
 }
 
 static const struct ethtool_ops netdev_ethtool_ops = {
index 067c460..114cda7 100644 (file)
@@ -1726,9 +1726,10 @@ static int eepro_ethtool_get_settings(struct net_device *dev,
 static void eepro_ethtool_get_drvinfo(struct net_device *dev,
                                        struct ethtool_drvinfo *drvinfo)
 {
-       strcpy(drvinfo->driver, DRV_NAME);
-       strcpy(drvinfo->version, DRV_VERSION);
-       sprintf(drvinfo->bus_info, "ISA 0x%lx", dev->base_addr);
+       strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
+       snprintf(drvinfo->bus_info, sizeof(drvinfo->bus_info),
+               "ISA 0x%lx", dev->base_addr);
 }
 
 static const struct ethtool_ops eepro_ethtool_ops = {
index ed79b2d..2abce96 100644 (file)
@@ -2924,6 +2924,9 @@ static int __devexit emac_remove(struct platform_device *ofdev)
        if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))
                zmii_detach(dev->zmii_dev, dev->zmii_port);
 
+       busy_phy_map &= ~(1 << dev->phy.address);
+       DBG(dev, "busy_phy_map now %#x" NL, busy_phy_map);
+
        mal_unregister_commac(dev->mal, &dev->commac);
        emac_put_deps(dev);
 
index b1cd41b..e877371 100644 (file)
@@ -735,7 +735,8 @@ static void netdev_get_drvinfo(struct net_device *dev,
                sizeof(info->version) - 1);
 }
 
-static u32 ibmveth_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t ibmveth_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        /*
         * Since the ibmveth firmware interface does not have the
@@ -838,7 +839,8 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data)
        return rc1 ? rc1 : rc2;
 }
 
-static int ibmveth_set_features(struct net_device *dev, u32 features)
+static int ibmveth_set_features(struct net_device *dev,
+       netdev_features_t features)
 {
        struct ibmveth_adapter *adapter = netdev_priv(dev);
        int rx_csum = !!(features & NETIF_F_RXCSUM);
index 5a2fdf7..9436397 100644 (file)
@@ -2376,10 +2376,10 @@ static void e100_get_drvinfo(struct net_device *netdev,
        struct ethtool_drvinfo *info)
 {
        struct nic *nic = netdev_priv(netdev);
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->fw_version, "N/A");
-       strcpy(info->bus_info, pci_name(nic->pdev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(nic->pdev),
+               sizeof(info->bus_info));
 }
 
 #define E100_PHY_REGS 0x1C
index 2b223ac..3103f0b 100644 (file)
@@ -515,14 +515,14 @@ static void e1000_get_drvinfo(struct net_device *netdev,
                              struct ethtool_drvinfo *drvinfo)
 {
        struct e1000_adapter *adapter = netdev_priv(netdev);
-       char firmware_version[32];
 
-       strncpy(drvinfo->driver,  e1000_driver_name, 32);
-       strncpy(drvinfo->version, e1000_driver_version, 32);
+       strlcpy(drvinfo->driver,  e1000_driver_name,
+               sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, e1000_driver_version,
+               sizeof(drvinfo->version));
 
-       sprintf(firmware_version, "N/A");
-       strncpy(drvinfo->fw_version, firmware_version, 32);
-       strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
+       strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
+               sizeof(drvinfo->bus_info));
        drvinfo->regdump_len = e1000_get_regs_len(netdev);
        drvinfo->eedump_len = e1000_get_eeprom_len(netdev);
 }
index 5c9a840..cf7e3c0 100644 (file)
@@ -448,7 +448,6 @@ void e1000_io_write(struct e1000_hw *hw, unsigned long port, u32 value);
 #define E1000_DEV_ID_INTEL_CE4100_GBE    0x2E6E
 
 #define NODE_ADDRESS_SIZE 6
-#define ETH_LENGTH_OF_ADDRESS 6
 
 /* MAC decode size is 128K - This is the size of BAR0 */
 #define MAC_DECODE_SIZE (128 * 1024)
index cf480b5..82f4ef1 100644 (file)
@@ -167,7 +167,8 @@ static int e1000_82547_fifo_workaround(struct e1000_adapter *adapter,
                                        struct sk_buff *skb);
 
 static bool e1000_vlan_used(struct e1000_adapter *adapter);
-static void e1000_vlan_mode(struct net_device *netdev, u32 features);
+static void e1000_vlan_mode(struct net_device *netdev,
+                           netdev_features_t features);
 static void e1000_vlan_rx_add_vid(struct net_device *netdev, u16 vid);
 static void e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid);
 static void e1000_restore_vlan(struct e1000_adapter *adapter);
@@ -806,7 +807,8 @@ static int e1000_is_need_ioport(struct pci_dev *pdev)
        }
 }
 
-static u32 e1000_fix_features(struct net_device *netdev, u32 features)
+static netdev_features_t e1000_fix_features(struct net_device *netdev,
+       netdev_features_t features)
 {
        /*
         * Since there is no support for separate rx/tx vlan accel
@@ -820,10 +822,11 @@ static u32 e1000_fix_features(struct net_device *netdev, u32 features)
        return features;
 }
 
-static int e1000_set_features(struct net_device *netdev, u32 features)
+static int e1000_set_features(struct net_device *netdev,
+       netdev_features_t features)
 {
        struct e1000_adapter *adapter = netdev_priv(netdev);
-       u32 changed = features ^ netdev->features;
+       netdev_features_t changed = features ^ netdev->features;
 
        if (changed & NETIF_F_HW_VLAN_RX)
                e1000_vlan_mode(netdev, features);
@@ -4577,7 +4580,8 @@ static void e1000_vlan_filter_on_off(struct e1000_adapter *adapter,
                e1000_irq_enable(adapter);
 }
 
-static void e1000_vlan_mode(struct net_device *netdev, u32 features)
+static void e1000_vlan_mode(struct net_device *netdev,
+       netdev_features_t features)
 {
        struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
index 69c9d21..fb2c28e 100644 (file)
@@ -579,26 +579,24 @@ static void e1000_get_drvinfo(struct net_device *netdev,
                              struct ethtool_drvinfo *drvinfo)
 {
        struct e1000_adapter *adapter = netdev_priv(netdev);
-       char firmware_version[32];
 
-       strncpy(drvinfo->driver,  e1000e_driver_name,
-               sizeof(drvinfo->driver) - 1);
-       strncpy(drvinfo->version, e1000e_driver_version,
-               sizeof(drvinfo->version) - 1);
+       strlcpy(drvinfo->driver,  e1000e_driver_name,
+               sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, e1000e_driver_version,
+               sizeof(drvinfo->version));
 
        /*
         * EEPROM image version # is reported as firmware version # for
         * PCI-E controllers
         */
-       snprintf(firmware_version, sizeof(firmware_version), "%d.%d-%d",
+       snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
+               "%d.%d-%d",
                (adapter->eeprom_vers & 0xF000) >> 12,
                (adapter->eeprom_vers & 0x0FF0) >> 4,
                (adapter->eeprom_vers & 0x000F));
 
-       strncpy(drvinfo->fw_version, firmware_version,
-               sizeof(drvinfo->fw_version) - 1);
-       strncpy(drvinfo->bus_info, pci_name(adapter->pdev),
-               sizeof(drvinfo->bus_info) - 1);
+       strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
+               sizeof(drvinfo->bus_info));
        drvinfo->regdump_len = e1000_get_regs_len(netdev);
        drvinfo->eedump_len = e1000_get_eeprom_len(netdev);
 }
index a855db1..a5bd7a3 100644 (file)
@@ -163,16 +163,13 @@ static void e1000_regdump(struct e1000_hw *hw, struct e1000_reg_info *reginfo)
                        regs[n] = __er32(hw, E1000_TARC(n));
                break;
        default:
-               printk(KERN_INFO "%-15s %08x\n",
-                      reginfo->name, __er32(hw, reginfo->ofs));
+               pr_info("%-15s %08x\n",
+                       reginfo->name, __er32(hw, reginfo->ofs));
                return;
        }
 
        snprintf(rname, 16, "%s%s", reginfo->name, "[0-1]");
-       printk(KERN_INFO "%-15s ", rname);
-       for (n = 0; n < 2; n++)
-               printk(KERN_CONT "%08x ", regs[n]);
-       printk(KERN_CONT "\n");
+       pr_info("%-15s %08x %08x\n", rname, regs[0], regs[1]);
 }
 
 /*
@@ -208,16 +205,15 @@ static void e1000e_dump(struct e1000_adapter *adapter)
        /* Print netdevice Info */
        if (netdev) {
                dev_info(&adapter->pdev->dev, "Net device Info\n");
-               printk(KERN_INFO "Device Name     state            "
-                      "trans_start      last_rx\n");
-               printk(KERN_INFO "%-15s %016lX %016lX %016lX\n",
-                      netdev->name, netdev->state, netdev->trans_start,
-                      netdev->last_rx);
+               pr_info("Device Name     state            trans_start      last_rx\n");
+               pr_info("%-15s %016lX %016lX %016lX\n",
+                       netdev->name, netdev->state, netdev->trans_start,
+                       netdev->last_rx);
        }
 
        /* Print Registers */
        dev_info(&adapter->pdev->dev, "Register Dump\n");
-       printk(KERN_INFO " Register Name   Value\n");
+       pr_info(" Register Name   Value\n");
        for (reginfo = (struct e1000_reg_info *)e1000_reg_info_tbl;
             reginfo->name; reginfo++) {
                e1000_regdump(hw, reginfo);
@@ -228,15 +224,14 @@ static void e1000e_dump(struct e1000_adapter *adapter)
                goto exit;
 
        dev_info(&adapter->pdev->dev, "Tx Ring Summary\n");
-       printk(KERN_INFO "Queue [NTU] [NTC] [bi(ntc)->dma  ]"
-              " leng ntw timestamp\n");
+       pr_info("Queue [NTU] [NTC] [bi(ntc)->dma  ] leng ntw timestamp\n");
        buffer_info = &tx_ring->buffer_info[tx_ring->next_to_clean];
-       printk(KERN_INFO " %5d %5X %5X %016llX %04X %3X %016llX\n",
-              0, tx_ring->next_to_use, tx_ring->next_to_clean,
-              (unsigned long long)buffer_info->dma,
-              buffer_info->length,
-              buffer_info->next_to_watch,
-              (unsigned long long)buffer_info->time_stamp);
+       pr_info(" %5d %5X %5X %016llX %04X %3X %016llX\n",
+               0, tx_ring->next_to_use, tx_ring->next_to_clean,
+               (unsigned long long)buffer_info->dma,
+               buffer_info->length,
+               buffer_info->next_to_watch,
+               (unsigned long long)buffer_info->time_stamp);
 
        /* Print Tx Ring */
        if (!netif_msg_tx_done(adapter))
@@ -271,37 +266,32 @@ static void e1000e_dump(struct e1000_adapter *adapter)
         *   +----------------------------------------------------------------+
         *   63       48 47     40 39  36 35    32 31     24 23  20 19        0
         */
-       printk(KERN_INFO "Tl[desc]     [address 63:0  ] [SpeCssSCmCsLen]"
-              " [bi->dma       ] leng  ntw timestamp        bi->skb "
-              "<-- Legacy format\n");
-       printk(KERN_INFO "Tc[desc]     [Ce CoCsIpceCoS] [MssHlRSCm0Plen]"
-              " [bi->dma       ] leng  ntw timestamp        bi->skb "
-              "<-- Ext Context format\n");
-       printk(KERN_INFO "Td[desc]     [address 63:0  ] [VlaPoRSCm1Dlen]"
-              " [bi->dma       ] leng  ntw timestamp        bi->skb "
-              "<-- Ext Data format\n");
+       pr_info("Tl[desc]     [address 63:0  ] [SpeCssSCmCsLen] [bi->dma       ] leng  ntw timestamp        bi->skb <-- Legacy format\n");
+       pr_info("Tc[desc]     [Ce CoCsIpceCoS] [MssHlRSCm0Plen] [bi->dma       ] leng  ntw timestamp        bi->skb <-- Ext Context format\n");
+       pr_info("Td[desc]     [address 63:0  ] [VlaPoRSCm1Dlen] [bi->dma       ] leng  ntw timestamp        bi->skb <-- Ext Data format\n");
        for (i = 0; tx_ring->desc && (i < tx_ring->count); i++) {
+               const char *next_desc;
                tx_desc = E1000_TX_DESC(*tx_ring, i);
                buffer_info = &tx_ring->buffer_info[i];
                u0 = (struct my_u0 *)tx_desc;
-               printk(KERN_INFO "T%c[0x%03X]    %016llX %016llX %016llX "
-                      "%04X  %3X %016llX %p",
-                      (!(le64_to_cpu(u0->b) & (1 << 29)) ? 'l' :
-                       ((le64_to_cpu(u0->b) & (1 << 20)) ? 'd' : 'c')), i,
-                      (unsigned long long)le64_to_cpu(u0->a),
-                      (unsigned long long)le64_to_cpu(u0->b),
-                      (unsigned long long)buffer_info->dma,
-                      buffer_info->length, buffer_info->next_to_watch,
-                      (unsigned long long)buffer_info->time_stamp,
-                      buffer_info->skb);
                if (i == tx_ring->next_to_use && i == tx_ring->next_to_clean)
-                       printk(KERN_CONT " NTC/U\n");
+                       next_desc = " NTC/U";
                else if (i == tx_ring->next_to_use)
-                       printk(KERN_CONT " NTU\n");
+                       next_desc = " NTU";
                else if (i == tx_ring->next_to_clean)
-                       printk(KERN_CONT " NTC\n");
+                       next_desc = " NTC";
                else
-                       printk(KERN_CONT "\n");
+                       next_desc = "";
+               pr_info("T%c[0x%03X]    %016llX %016llX %016llX %04X  %3X %016llX %p%s\n",
+                       (!(le64_to_cpu(u0->b) & (1 << 29)) ? 'l' :
+                        ((le64_to_cpu(u0->b) & (1 << 20)) ? 'd' : 'c')),
+                       i,
+                       (unsigned long long)le64_to_cpu(u0->a),
+                       (unsigned long long)le64_to_cpu(u0->b),
+                       (unsigned long long)buffer_info->dma,
+                       buffer_info->length, buffer_info->next_to_watch,
+                       (unsigned long long)buffer_info->time_stamp,
+                       buffer_info->skb, next_desc);
 
                if (netif_msg_pktdata(adapter) && buffer_info->dma != 0)
                        print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS,
@@ -312,9 +302,9 @@ static void e1000e_dump(struct e1000_adapter *adapter)
        /* Print Rx Ring Summary */
 rx_ring_summary:
        dev_info(&adapter->pdev->dev, "Rx Ring Summary\n");
-       printk(KERN_INFO "Queue [NTU] [NTC]\n");
-       printk(KERN_INFO " %5d %5X %5X\n", 0,
-              rx_ring->next_to_use, rx_ring->next_to_clean);
+       pr_info("Queue [NTU] [NTC]\n");
+       pr_info(" %5d %5X %5X\n",
+               0, rx_ring->next_to_use, rx_ring->next_to_clean);
 
        /* Print Rx Ring */
        if (!netif_msg_rx_status(adapter))
@@ -337,10 +327,7 @@ rx_ring_summary:
                 * 24 |                Buffer Address 3 [63:0]              |
                 *    +-----------------------------------------------------+
                 */
-               printk(KERN_INFO "R  [desc]      [buffer 0 63:0 ] "
-                      "[buffer 1 63:0 ] "
-                      "[buffer 2 63:0 ] [buffer 3 63:0 ] [bi->dma       ] "
-                      "[bi->skb] <-- Ext Pkt Split format\n");
+               pr_info("R  [desc]      [buffer 0 63:0 ] [buffer 1 63:0 ] [buffer 2 63:0 ] [buffer 3 63:0 ] [bi->dma       ] [bi->skb] <-- Ext Pkt Split format\n");
                /* [Extended] Receive Descriptor (Write-Back) Format
                 *
                 *   63       48 47    32 31     13 12    8 7    4 3        0
@@ -352,35 +339,40 @@ rx_ring_summary:
                 *   +------------------------------------------------------+
                 *   63       48 47    32 31            20 19               0
                 */
-               printk(KERN_INFO "RWB[desc]      [ck ipid mrqhsh] "
-                      "[vl   l0 ee  es] "
-                      "[ l3  l2  l1 hs] [reserved      ] ---------------- "
-                      "[bi->skb] <-- Ext Rx Write-Back format\n");
+               pr_info("RWB[desc]      [ck ipid mrqhsh] [vl   l0 ee  es] [ l3  l2  l1 hs] [reserved      ] ---------------- [bi->skb] <-- Ext Rx Write-Back format\n");
                for (i = 0; i < rx_ring->count; i++) {
+                       const char *next_desc;
                        buffer_info = &rx_ring->buffer_info[i];
                        rx_desc_ps = E1000_RX_DESC_PS(*rx_ring, i);
                        u1 = (struct my_u1 *)rx_desc_ps;
                        staterr =
                            le32_to_cpu(rx_desc_ps->wb.middle.status_error);
+
+                       if (i == rx_ring->next_to_use)
+                               next_desc = " NTU";
+                       else if (i == rx_ring->next_to_clean)
+                               next_desc = " NTC";
+                       else
+                               next_desc = "";
+
                        if (staterr & E1000_RXD_STAT_DD) {
                                /* Descriptor Done */
-                               printk(KERN_INFO "RWB[0x%03X]     %016llX "
-                                      "%016llX %016llX %016llX "
-                                      "---------------- %p", i,
-                                      (unsigned long long)le64_to_cpu(u1->a),
-                                      (unsigned long long)le64_to_cpu(u1->b),
-                                      (unsigned long long)le64_to_cpu(u1->c),
-                                      (unsigned long long)le64_to_cpu(u1->d),
-                                      buffer_info->skb);
+                               pr_info("%s[0x%03X]     %016llX %016llX %016llX %016llX ---------------- %p%s\n",
+                                       "RWB", i,
+                                       (unsigned long long)le64_to_cpu(u1->a),
+                                       (unsigned long long)le64_to_cpu(u1->b),
+                                       (unsigned long long)le64_to_cpu(u1->c),
+                                       (unsigned long long)le64_to_cpu(u1->d),
+                                       buffer_info->skb, next_desc);
                        } else {
-                               printk(KERN_INFO "R  [0x%03X]     %016llX "
-                                      "%016llX %016llX %016llX %016llX %p", i,
-                                      (unsigned long long)le64_to_cpu(u1->a),
-                                      (unsigned long long)le64_to_cpu(u1->b),
-                                      (unsigned long long)le64_to_cpu(u1->c),
-                                      (unsigned long long)le64_to_cpu(u1->d),
-                                      (unsigned long long)buffer_info->dma,
-                                      buffer_info->skb);
+                               pr_info("%s[0x%03X]     %016llX %016llX %016llX %016llX %016llX %p%s\n",
+                                       "R  ", i,
+                                       (unsigned long long)le64_to_cpu(u1->a),
+                                       (unsigned long long)le64_to_cpu(u1->b),
+                                       (unsigned long long)le64_to_cpu(u1->c),
+                                       (unsigned long long)le64_to_cpu(u1->d),
+                                       (unsigned long long)buffer_info->dma,
+                                       buffer_info->skb, next_desc);
 
                                if (netif_msg_pktdata(adapter))
                                        print_hex_dump(KERN_INFO, "",
@@ -388,13 +380,6 @@ rx_ring_summary:
                                                phys_to_virt(buffer_info->dma),
                                                adapter->rx_ps_bsize0, true);
                        }
-
-                       if (i == rx_ring->next_to_use)
-                               printk(KERN_CONT " NTU\n");
-                       else if (i == rx_ring->next_to_clean)
-                               printk(KERN_CONT " NTC\n");
-                       else
-                               printk(KERN_CONT "\n");
                }
                break;
        default:
@@ -407,9 +392,7 @@ rx_ring_summary:
                 * 8 |                      Reserved                       |
                 *   +-----------------------------------------------------+
                 */
-               printk(KERN_INFO "R  [desc]      [buf addr 63:0 ] "
-                      "[reserved 63:0 ] [bi->dma       ] "
-                      "[bi->skb] <-- Ext (Read) format\n");
+               pr_info("R  [desc]      [buf addr 63:0 ] [reserved 63:0 ] [bi->dma       ] [bi->skb] <-- Ext (Read) format\n");
                /* Extended Receive Descriptor (Write-Back) Format
                 *
                 *   63       48 47    32 31    24 23            4 3        0
@@ -423,29 +406,37 @@ rx_ring_summary:
                 *   +------------------------------------------------------+
                 *   63       48 47    32 31            20 19               0
                 */
-               printk(KERN_INFO "RWB[desc]      [cs ipid    mrq] "
-                      "[vt   ln xe  xs] "
-                      "[bi->skb] <-- Ext (Write-Back) format\n");
+               pr_info("RWB[desc]      [cs ipid    mrq] [vt   ln xe  xs] [bi->skb] <-- Ext (Write-Back) format\n");
 
                for (i = 0; i < rx_ring->count; i++) {
+                       const char *next_desc;
+
                        buffer_info = &rx_ring->buffer_info[i];
                        rx_desc = E1000_RX_DESC_EXT(*rx_ring, i);
                        u1 = (struct my_u1 *)rx_desc;
                        staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+
+                       if (i == rx_ring->next_to_use)
+                               next_desc = " NTU";
+                       else if (i == rx_ring->next_to_clean)
+                               next_desc = " NTC";
+                       else
+                               next_desc = "";
+
                        if (staterr & E1000_RXD_STAT_DD) {
                                /* Descriptor Done */
-                               printk(KERN_INFO "RWB[0x%03X]     %016llX "
-                                      "%016llX ---------------- %p", i,
-                                      (unsigned long long)le64_to_cpu(u1->a),
-                                      (unsigned long long)le64_to_cpu(u1->b),
-                                      buffer_info->skb);
+                               pr_info("%s[0x%03X]     %016llX %016llX ---------------- %p%s\n",
+                                       "RWB", i,
+                                       (unsigned long long)le64_to_cpu(u1->a),
+                                       (unsigned long long)le64_to_cpu(u1->b),
+                                       buffer_info->skb, next_desc);
                        } else {
-                               printk(KERN_INFO "R  [0x%03X]     %016llX "
-                                      "%016llX %016llX %p", i,
-                                      (unsigned long long)le64_to_cpu(u1->a),
-                                      (unsigned long long)le64_to_cpu(u1->b),
-                                      (unsigned long long)buffer_info->dma,
-                                      buffer_info->skb);
+                               pr_info("%s[0x%03X]     %016llX %016llX %016llX %p%s\n",
+                                       "R  ", i,
+                                       (unsigned long long)le64_to_cpu(u1->a),
+                                       (unsigned long long)le64_to_cpu(u1->b),
+                                       (unsigned long long)buffer_info->dma,
+                                       buffer_info->skb, next_desc);
 
                                if (netif_msg_pktdata(adapter))
                                        print_hex_dump(KERN_INFO, "",
@@ -456,13 +447,6 @@ rx_ring_summary:
                                                       adapter->rx_buffer_len,
                                                       true);
                        }
-
-                       if (i == rx_ring->next_to_use)
-                               printk(KERN_CONT " NTU\n");
-                       else if (i == rx_ring->next_to_clean)
-                               printk(KERN_CONT " NTC\n");
-                       else
-                               printk(KERN_CONT "\n");
                }
        }
 
@@ -1222,8 +1206,7 @@ static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
                        adapter->flags2 |= FLAG2_IS_DISCARDING;
 
                if (adapter->flags2 & FLAG2_IS_DISCARDING) {
-                       e_dbg("Packet Split buffers didn't pick up the full "
-                             "packet\n");
+                       e_dbg("Packet Split buffers didn't pick up the full packet\n");
                        dev_kfree_skb_irq(skb);
                        if (staterr & E1000_RXD_STAT_EOP)
                                adapter->flags2 &= ~FLAG2_IS_DISCARDING;
@@ -1238,8 +1221,7 @@ static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
                length = le16_to_cpu(rx_desc->wb.middle.length0);
 
                if (!length) {
-                       e_dbg("Last part of the packet spanning multiple "
-                             "descriptors\n");
+                       e_dbg("Last part of the packet spanning multiple descriptors\n");
                        dev_kfree_skb_irq(skb);
                        goto next_desc;
                }
@@ -1917,8 +1899,7 @@ void e1000e_set_interrupt_capability(struct e1000_adapter *adapter)
                                        return;
                        }
                        /* MSI-X failed, so fall through and try MSI */
-                       e_err("Failed to initialize MSI-X interrupts.  "
-                             "Falling back to MSI interrupts.\n");
+                       e_err("Failed to initialize MSI-X interrupts.  Falling back to MSI interrupts.\n");
                        e1000e_reset_interrupt_capability(adapter);
                }
                adapter->int_mode = E1000E_INT_MODE_MSI;
@@ -1928,8 +1909,7 @@ void e1000e_set_interrupt_capability(struct e1000_adapter *adapter)
                        adapter->flags |= FLAG_MSI_ENABLED;
                } else {
                        adapter->int_mode = E1000E_INT_MODE_LEGACY;
-                       e_err("Failed to initialize MSI interrupts.  Falling "
-                             "back to legacy interrupts.\n");
+                       e_err("Failed to initialize MSI interrupts.  Falling back to legacy interrupts.\n");
                }
                /* Fall through */
        case E1000E_INT_MODE_LEGACY:
@@ -3113,79 +3093,147 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
 }
 
 /**
- *  e1000_update_mc_addr_list - Update Multicast addresses
- *  @hw: pointer to the HW structure
- *  @mc_addr_list: array of multicast addresses to program
- *  @mc_addr_count: number of multicast addresses to program
+ * e1000e_write_mc_addr_list - write multicast addresses to MTA
+ * @netdev: network interface device structure
+ *
+ * Writes multicast address list to the MTA hash table.
+ * Returns: -ENOMEM on failure
+ *                0 on no addresses written
+ *                X on writing X addresses to MTA
+ */
+static int e1000e_write_mc_addr_list(struct net_device *netdev)
+{
+       struct e1000_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+       struct netdev_hw_addr *ha;
+       u8 *mta_list;
+       int i;
+
+       if (netdev_mc_empty(netdev)) {
+               /* nothing to program, so clear mc list */
+               hw->mac.ops.update_mc_addr_list(hw, NULL, 0);
+               return 0;
+       }
+
+       mta_list = kzalloc(netdev_mc_count(netdev) * ETH_ALEN, GFP_ATOMIC);
+       if (!mta_list)
+               return -ENOMEM;
+
+       /* update_mc_addr_list expects a packed array of only addresses. */
+       i = 0;
+       netdev_for_each_mc_addr(ha, netdev)
+               memcpy(mta_list + (i++ * ETH_ALEN), ha->addr, ETH_ALEN);
+
+       hw->mac.ops.update_mc_addr_list(hw, mta_list, i);
+       kfree(mta_list);
+
+       return netdev_mc_count(netdev);
+}
+
+/**
+ * e1000e_write_uc_addr_list - write unicast addresses to RAR table
+ * @netdev: network interface device structure
  *
- *  Updates the Multicast Table Array.
- *  The caller must have a packed mc_addr_list of multicast addresses.
+ * Writes unicast address list to the RAR table.
+ * Returns: -ENOMEM on failure/insufficient address space
+ *                0 on no addresses written
+ *                X on writing X addresses to the RAR table
  **/
-static void e1000_update_mc_addr_list(struct e1000_hw *hw, u8 *mc_addr_list,
-                                     u32 mc_addr_count)
+static int e1000e_write_uc_addr_list(struct net_device *netdev)
 {
-       hw->mac.ops.update_mc_addr_list(hw, mc_addr_list, mc_addr_count);
+       struct e1000_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+       unsigned int rar_entries = hw->mac.rar_entry_count;
+       int count = 0;
+
+       /* save a rar entry for our hardware address */
+       rar_entries--;
+
+       /* save a rar entry for the LAA workaround */
+       if (adapter->flags & FLAG_RESET_OVERWRITES_LAA)
+               rar_entries--;
+
+       /* return ENOMEM indicating insufficient memory for addresses */
+       if (netdev_uc_count(netdev) > rar_entries)
+               return -ENOMEM;
+
+       if (!netdev_uc_empty(netdev) && rar_entries) {
+               struct netdev_hw_addr *ha;
+
+               /*
+                * write the addresses in reverse order to avoid write
+                * combining
+                */
+               netdev_for_each_uc_addr(ha, netdev) {
+                       if (!rar_entries)
+                               break;
+                       e1000e_rar_set(hw, ha->addr, rar_entries--);
+                       count++;
+               }
+       }
+
+       /* zero out the remaining RAR entries not used above */
+       for (; rar_entries > 0; rar_entries--) {
+               ew32(RAH(rar_entries), 0);
+               ew32(RAL(rar_entries), 0);
+       }
+       e1e_flush();
+
+       return count;
 }
 
 /**
- * e1000_set_multi - Multicast and Promiscuous mode set
+ * e1000e_set_rx_mode - secondary unicast, Multicast and Promiscuous mode set
  * @netdev: network interface device structure
  *
- * The set_multi entry point is called whenever the multicast address
- * list or the network interface flags are updated.  This routine is
- * responsible for configuring the hardware for proper multicast,
+ * The ndo_set_rx_mode entry point is called whenever the unicast or multicast
+ * address list or the network interface flags are updated.  This routine is
+ * responsible for configuring the hardware for proper unicast, multicast,
  * promiscuous mode, and all-multi behavior.
  **/
-static void e1000_set_multi(struct net_device *netdev)
+static void e1000e_set_rx_mode(struct net_device *netdev)
 {
        struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
-       struct netdev_hw_addr *ha;
-       u8  *mta_list;
        u32 rctl;
 
        /* Check for Promiscuous and All Multicast modes */
-
        rctl = er32(RCTL);
 
+       /* clear the affected bits */
+       rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE);
+
        if (netdev->flags & IFF_PROMISC) {
                rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
-               rctl &= ~E1000_RCTL_VFE;
                /* Do not hardware filter VLANs in promisc mode */
                e1000e_vlan_filter_disable(adapter);
        } else {
+               int count;
                if (netdev->flags & IFF_ALLMULTI) {
                        rctl |= E1000_RCTL_MPE;
-                       rctl &= ~E1000_RCTL_UPE;
                } else {
-                       rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE);
+                       /*
+                        * Write addresses to the MTA, if the attempt fails
+                        * then we should just turn on promiscuous mode so
+                        * that we can at least receive multicast traffic
+                        */
+                       count = e1000e_write_mc_addr_list(netdev);
+                       if (count < 0)
+                               rctl |= E1000_RCTL_MPE;
                }
                e1000e_vlan_filter_enable(adapter);
-       }
-
-       ew32(RCTL, rctl);
-
-       if (!netdev_mc_empty(netdev)) {
-               int i = 0;
-
-               mta_list = kmalloc(netdev_mc_count(netdev) * 6, GFP_ATOMIC);
-               if (!mta_list)
-                       return;
-
-               /* prepare a packed array of only addresses. */
-               netdev_for_each_mc_addr(ha, netdev)
-                       memcpy(mta_list + (i++ * ETH_ALEN), ha->addr, ETH_ALEN);
-
-               e1000_update_mc_addr_list(hw, mta_list, i);
-               kfree(mta_list);
-       } else {
                /*
-                * if we're called from probe, we might not have
-                * anything to do here, so clear out the list
+                * Write addresses to available RAR registers, if there is not
+                * sufficient space to store all the addresses then enable
+                * unicast promiscuous mode
                 */
-               e1000_update_mc_addr_list(hw, NULL, 0);
+               count = e1000e_write_uc_addr_list(netdev);
+               if (count < 0)
+                       rctl |= E1000_RCTL_UPE;
        }
 
+       ew32(RCTL, rctl);
+
        if (netdev->features & NETIF_F_HW_VLAN_RX)
                e1000e_vlan_strip_enable(adapter);
        else
@@ -3198,7 +3246,7 @@ static void e1000_set_multi(struct net_device *netdev)
  **/
 static void e1000_configure(struct e1000_adapter *adapter)
 {
-       e1000_set_multi(adapter->netdev);
+       e1000e_set_rx_mode(adapter->netdev);
 
        e1000_restore_vlan(adapter);
        e1000_init_manageability_pt(adapter);
@@ -4168,16 +4216,13 @@ static void e1000_print_link_info(struct e1000_adapter *adapter)
        u32 ctrl = er32(CTRL);
 
        /* Link status message must follow this format for user tools */
-       printk(KERN_INFO "e1000e: %s NIC Link is Up %d Mbps %s, "
-              "Flow Control: %s\n",
-              adapter->netdev->name,
-              adapter->link_speed,
-              (adapter->link_duplex == FULL_DUPLEX) ?
-              "Full Duplex" : "Half Duplex",
-              ((ctrl & E1000_CTRL_TFCE) && (ctrl & E1000_CTRL_RFCE)) ?
-              "Rx/Tx" :
-              ((ctrl & E1000_CTRL_RFCE) ? "Rx" :
-               ((ctrl & E1000_CTRL_TFCE) ? "Tx" : "None")));
+       printk(KERN_INFO "e1000e: %s NIC Link is Up %d Mbps %s Duplex, Flow Control: %s\n",
+               adapter->netdev->name,
+               adapter->link_speed,
+               adapter->link_duplex == FULL_DUPLEX ? "Full" : "Half",
+               (ctrl & E1000_CTRL_TFCE) && (ctrl & E1000_CTRL_RFCE) ? "Rx/Tx" :
+               (ctrl & E1000_CTRL_RFCE) ? "Rx" :
+               (ctrl & E1000_CTRL_TFCE) ? "Tx" : "None");
 }
 
 static bool e1000e_has_link(struct e1000_adapter *adapter)
@@ -4323,10 +4368,7 @@ static void e1000_watchdog_task(struct work_struct *work)
                                e1e_rphy(hw, PHY_AUTONEG_EXP, &autoneg_exp);
 
                                if (!(autoneg_exp & NWAY_ER_LP_NWAY_CAPS))
-                                       e_info("Autonegotiated half duplex but"
-                                              " link partner cannot autoneg. "
-                                              " Try forcing full duplex if "
-                                              "link gets many collisions.\n");
+                                       e_info("Autonegotiated half duplex but link partner cannot autoneg.  Try forcing full duplex if link gets many collisions.\n");
                        }
 
                        /* adjust timeout factor according to speed/duplex */
@@ -5110,8 +5152,7 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
        if ((adapter->hw.mac.type == e1000_pch2lan) &&
            !(adapter->flags2 & FLAG2_CRC_STRIPPING) &&
            (new_mtu > ETH_DATA_LEN)) {
-               e_err("Jumbo Frames not supported on 82579 when CRC "
-                     "stripping is disabled.\n");
+               e_err("Jumbo Frames not supported on 82579 when CRC stripping is disabled.\n");
                return -EINVAL;
        }
 
@@ -5331,7 +5372,7 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake,
 
        if (wufc) {
                e1000_setup_rctl(adapter);
-               e1000_set_multi(netdev);
+               e1000e_set_rx_mode(netdev);
 
                /* turn on all-multi mode if wake on multicast is enabled */
                if (wufc & E1000_WUFC_MC) {
@@ -5527,8 +5568,8 @@ static int __e1000_resume(struct pci_dev *pdev)
                                phy_data & E1000_WUS_MC ? "Multicast Packet" :
                                phy_data & E1000_WUS_BC ? "Broadcast Packet" :
                                phy_data & E1000_WUS_MAG ? "Magic Packet" :
-                               phy_data & E1000_WUS_LNKC ? "Link Status "
-                               " Change" : "other");
+                               phy_data & E1000_WUS_LNKC ?
+                               "Link Status Change" : "other");
                }
                e1e_wphy(&adapter->hw, BM_WUS, ~0);
        } else {
@@ -5859,10 +5900,11 @@ static void e1000_eeprom_checks(struct e1000_adapter *adapter)
        }
 }
 
-static int e1000_set_features(struct net_device *netdev, u32 features)
+static int e1000_set_features(struct net_device *netdev,
+       netdev_features_t features)
 {
        struct e1000_adapter *adapter = netdev_priv(netdev);
-       u32 changed = features ^ netdev->features;
+       netdev_features_t changed = features ^ netdev->features;
 
        if (changed & (NETIF_F_TSO | NETIF_F_TSO6))
                adapter->flags |= FLAG_TSO_FORCE;
@@ -5884,7 +5926,7 @@ static const struct net_device_ops e1000e_netdev_ops = {
        .ndo_stop               = e1000_close,
        .ndo_start_xmit         = e1000_xmit_frame,
        .ndo_get_stats64        = e1000e_get_stats64,
-       .ndo_set_rx_mode        = e1000_set_multi,
+       .ndo_set_rx_mode        = e1000e_set_rx_mode,
        .ndo_set_mac_address    = e1000_set_mac,
        .ndo_change_mtu         = e1000_change_mtu,
        .ndo_do_ioctl           = e1000_ioctl,
@@ -5949,8 +5991,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
                        err = dma_set_coherent_mask(&pdev->dev,
                                                    DMA_BIT_MASK(32));
                        if (err) {
-                               dev_err(&pdev->dev, "No usable DMA "
-                                       "configuration, aborting\n");
+                               dev_err(&pdev->dev, "No usable DMA configuration, aborting\n");
                                goto err_dma;
                        }
                }
@@ -6076,6 +6117,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
                                  NETIF_F_TSO6 |
                                  NETIF_F_HW_CSUM);
 
+       netdev->priv_flags |= IFF_UNICAST_FLT;
+
        if (pci_using_dac) {
                netdev->features |= NETIF_F_HIGHDMA;
                netdev->vlan_features |= NETIF_F_HIGHDMA;
index 7881fb9..b8e20f0 100644 (file)
@@ -29,6 +29,8 @@
  * e1000_82576
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/types.h>
 #include <linux/if_ether.h>
 
@@ -244,8 +246,7 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
         * Check for invalid size
         */
        if ((hw->mac.type == e1000_82576) && (size > 15)) {
-               printk("igb: The NVM size is not valid, "
-                       "defaulting to 32K.\n");
+               pr_notice("The NVM size is not valid, defaulting to 32K\n");
                size = 15;
        }
        nvm->word_size = 1 << size;
index 43873eb..e9335ef 100644 (file)
@@ -673,25 +673,22 @@ static void igb_get_drvinfo(struct net_device *netdev,
                            struct ethtool_drvinfo *drvinfo)
 {
        struct igb_adapter *adapter = netdev_priv(netdev);
-       char firmware_version[32];
        u16 eeprom_data;
 
-       strncpy(drvinfo->driver,  igb_driver_name, sizeof(drvinfo->driver) - 1);
-       strncpy(drvinfo->version, igb_driver_version,
-               sizeof(drvinfo->version) - 1);
+       strlcpy(drvinfo->driver,  igb_driver_name, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, igb_driver_version, sizeof(drvinfo->version));
 
        /* EEPROM image version # is reported as firmware version # for
         * 82575 controllers */
        adapter->hw.nvm.ops.read(&adapter->hw, 5, 1, &eeprom_data);
-       sprintf(firmware_version, "%d.%d-%d",
+       snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
+               "%d.%d-%d",
                (eeprom_data & 0xF000) >> 12,
                (eeprom_data & 0x0FF0) >> 4,
                eeprom_data & 0x000F);
 
-       strncpy(drvinfo->fw_version, firmware_version,
-               sizeof(drvinfo->fw_version) - 1);
-       strncpy(drvinfo->bus_info, pci_name(adapter->pdev),
-               sizeof(drvinfo->bus_info) - 1);
+       strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
+               sizeof(drvinfo->bus_info));
        drvinfo->n_stats = IGB_STATS_LEN;
        drvinfo->testinfo_len = IGB_TEST_LEN;
        drvinfo->regdump_len = igb_get_regs_len(netdev);
index ced5444..b66b8aa 100644 (file)
@@ -25,6 +25,8 @@
 
 *******************************************************************************/
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/init.h>
@@ -145,7 +147,7 @@ static bool igb_clean_rx_irq(struct igb_q_vector *, int);
 static int igb_ioctl(struct net_device *, struct ifreq *, int cmd);
 static void igb_tx_timeout(struct net_device *);
 static void igb_reset_task(struct work_struct *);
-static void igb_vlan_mode(struct net_device *netdev, u32 features);
+static void igb_vlan_mode(struct net_device *netdev, netdev_features_t features);
 static void igb_vlan_rx_add_vid(struct net_device *, u16);
 static void igb_vlan_rx_kill_vid(struct net_device *, u16);
 static void igb_restore_vlan(struct igb_adapter *);
@@ -325,16 +327,13 @@ static void igb_regdump(struct e1000_hw *hw, struct igb_reg_info *reginfo)
                        regs[n] = rd32(E1000_TXDCTL(n));
                break;
        default:
-               printk(KERN_INFO "%-15s %08x\n",
-                       reginfo->name, rd32(reginfo->ofs));
+               pr_info("%-15s %08x\n", reginfo->name, rd32(reginfo->ofs));
                return;
        }
 
        snprintf(rname, 16, "%s%s", reginfo->name, "[0-3]");
-       printk(KERN_INFO "%-15s ", rname);
-       for (n = 0; n < 4; n++)
-               printk(KERN_CONT "%08x ", regs[n]);
-       printk(KERN_CONT "\n");
+       pr_info("%-15s %08x %08x %08x %08x\n", rname, regs[0], regs[1],
+               regs[2], regs[3]);
 }
 
 /*
@@ -359,18 +358,15 @@ static void igb_dump(struct igb_adapter *adapter)
        /* Print netdevice Info */
        if (netdev) {
                dev_info(&adapter->pdev->dev, "Net device Info\n");
-               printk(KERN_INFO "Device Name     state            "
-                       "trans_start      last_rx\n");
-               printk(KERN_INFO "%-15s %016lX %016lX %016lX\n",
-               netdev->name,
-               netdev->state,
-               netdev->trans_start,
-               netdev->last_rx);
+               pr_info("Device Name     state            trans_start      "
+                       "last_rx\n");
+               pr_info("%-15s %016lX %016lX %016lX\n", netdev->name,
+                       netdev->state, netdev->trans_start, netdev->last_rx);
        }
 
        /* Print Registers */
        dev_info(&adapter->pdev->dev, "Register Dump\n");
-       printk(KERN_INFO " Register Name   Value\n");
+       pr_info(" Register Name   Value\n");
        for (reginfo = (struct igb_reg_info *)igb_reg_info_tbl;
             reginfo->name; reginfo++) {
                igb_regdump(hw, reginfo);
@@ -381,18 +377,17 @@ static void igb_dump(struct igb_adapter *adapter)
                goto exit;
 
        dev_info(&adapter->pdev->dev, "TX Rings Summary\n");
-       printk(KERN_INFO "Queue [NTU] [NTC] [bi(ntc)->dma  ]"
-               " leng ntw timestamp\n");
+       pr_info("Queue [NTU] [NTC] [bi(ntc)->dma  ] leng ntw timestamp\n");
        for (n = 0; n < adapter->num_tx_queues; n++) {
                struct igb_tx_buffer *buffer_info;
                tx_ring = adapter->tx_ring[n];
                buffer_info = &tx_ring->tx_buffer_info[tx_ring->next_to_clean];
-               printk(KERN_INFO " %5d %5X %5X %016llX %04X %p %016llX\n",
-                          n, tx_ring->next_to_use, tx_ring->next_to_clean,
-                          (u64)buffer_info->dma,
-                          buffer_info->length,
-                          buffer_info->next_to_watch,
-                          (u64)buffer_info->time_stamp);
+               pr_info(" %5d %5X %5X %016llX %04X %p %016llX\n",
+                       n, tx_ring->next_to_use, tx_ring->next_to_clean,
+                       (u64)buffer_info->dma,
+                       buffer_info->length,
+                       buffer_info->next_to_watch,
+                       (u64)buffer_info->time_stamp);
        }
 
        /* Print TX Rings */
@@ -414,36 +409,38 @@ static void igb_dump(struct igb_adapter *adapter)
 
        for (n = 0; n < adapter->num_tx_queues; n++) {
                tx_ring = adapter->tx_ring[n];
-               printk(KERN_INFO "------------------------------------\n");
-               printk(KERN_INFO "TX QUEUE INDEX = %d\n", tx_ring->queue_index);
-               printk(KERN_INFO "------------------------------------\n");
-               printk(KERN_INFO "T [desc]     [address 63:0  ] "
-                       "[PlPOCIStDDM Ln] [bi->dma       ] "
-                       "leng  ntw timestamp        bi->skb\n");
+               pr_info("------------------------------------\n");
+               pr_info("TX QUEUE INDEX = %d\n", tx_ring->queue_index);
+               pr_info("------------------------------------\n");
+               pr_info("T [desc]     [address 63:0  ] [PlPOCIStDDM Ln] "
+                       "[bi->dma       ] leng  ntw timestamp        "
+                       "bi->skb\n");
 
                for (i = 0; tx_ring->desc && (i < tx_ring->count); i++) {
+                       const char *next_desc;
                        struct igb_tx_buffer *buffer_info;
                        tx_desc = IGB_TX_DESC(tx_ring, i);
                        buffer_info = &tx_ring->tx_buffer_info[i];
                        u0 = (struct my_u0 *)tx_desc;
-                       printk(KERN_INFO "T [0x%03X]    %016llX %016llX %016llX"
-                               " %04X  %p %016llX %p", i,
+                       if (i == tx_ring->next_to_use &&
+                           i == tx_ring->next_to_clean)
+                               next_desc = " NTC/U";
+                       else if (i == tx_ring->next_to_use)
+                               next_desc = " NTU";
+                       else if (i == tx_ring->next_to_clean)
+                               next_desc = " NTC";
+                       else
+                               next_desc = "";
+
+                       pr_info("T [0x%03X]    %016llX %016llX %016llX"
+                               " %04X  %p %016llX %p%s\n", i,
                                le64_to_cpu(u0->a),
                                le64_to_cpu(u0->b),
                                (u64)buffer_info->dma,
                                buffer_info->length,
                                buffer_info->next_to_watch,
                                (u64)buffer_info->time_stamp,
-                               buffer_info->skb);
-                       if (i == tx_ring->next_to_use &&
-                               i == tx_ring->next_to_clean)
-                               printk(KERN_CONT " NTC/U\n");
-                       else if (i == tx_ring->next_to_use)
-                               printk(KERN_CONT " NTU\n");
-                       else if (i == tx_ring->next_to_clean)
-                               printk(KERN_CONT " NTC\n");
-                       else
-                               printk(KERN_CONT "\n");
+                               buffer_info->skb, next_desc);
 
                        if (netif_msg_pktdata(adapter) && buffer_info->dma != 0)
                                print_hex_dump(KERN_INFO, "",
@@ -456,11 +453,11 @@ static void igb_dump(struct igb_adapter *adapter)
        /* Print RX Rings Summary */
 rx_ring_summary:
        dev_info(&adapter->pdev->dev, "RX Rings Summary\n");
-       printk(KERN_INFO "Queue [NTU] [NTC]\n");
+       pr_info("Queue [NTU] [NTC]\n");
        for (n = 0; n < adapter->num_rx_queues; n++) {
                rx_ring = adapter->rx_ring[n];
-               printk(KERN_INFO " %5d %5X %5X\n", n,
-                          rx_ring->next_to_use, rx_ring->next_to_clean);
+               pr_info(" %5d %5X %5X\n",
+                       n, rx_ring->next_to_use, rx_ring->next_to_clean);
        }
 
        /* Print RX Rings */
@@ -492,36 +489,43 @@ rx_ring_summary:
 
        for (n = 0; n < adapter->num_rx_queues; n++) {
                rx_ring = adapter->rx_ring[n];
-               printk(KERN_INFO "------------------------------------\n");
-               printk(KERN_INFO "RX QUEUE INDEX = %d\n", rx_ring->queue_index);
-               printk(KERN_INFO "------------------------------------\n");
-               printk(KERN_INFO "R  [desc]      [ PktBuf     A0] "
-                       "[  HeadBuf   DD] [bi->dma       ] [bi->skb] "
-                       "<-- Adv Rx Read format\n");
-               printk(KERN_INFO "RWB[desc]      [PcsmIpSHl PtRs] "
-                       "[vl er S cks ln] ---------------- [bi->skb] "
-                       "<-- Adv Rx Write-Back format\n");
+               pr_info("------------------------------------\n");
+               pr_info("RX QUEUE INDEX = %d\n", rx_ring->queue_index);
+               pr_info("------------------------------------\n");
+               pr_info("R  [desc]      [ PktBuf     A0] [  HeadBuf   DD] "
+                       "[bi->dma       ] [bi->skb] <-- Adv Rx Read format\n");
+               pr_info("RWB[desc]      [PcsmIpSHl PtRs] [vl er S cks ln] -----"
+                       "----------- [bi->skb] <-- Adv Rx Write-Back format\n");
 
                for (i = 0; i < rx_ring->count; i++) {
+                       const char *next_desc;
                        struct igb_rx_buffer *buffer_info;
                        buffer_info = &rx_ring->rx_buffer_info[i];
                        rx_desc = IGB_RX_DESC(rx_ring, i);
                        u0 = (struct my_u0 *)rx_desc;
                        staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+
+                       if (i == rx_ring->next_to_use)
+                               next_desc = " NTU";
+                       else if (i == rx_ring->next_to_clean)
+                               next_desc = " NTC";
+                       else
+                               next_desc = "";
+
                        if (staterr & E1000_RXD_STAT_DD) {
                                /* Descriptor Done */
-                               printk(KERN_INFO "RWB[0x%03X]     %016llX "
-                                       "%016llX ---------------- %p", i,
+                               pr_info("%s[0x%03X]     %016llX %016llX -------"
+                                       "--------- %p%s\n", "RWB", i,
                                        le64_to_cpu(u0->a),
                                        le64_to_cpu(u0->b),
-                                       buffer_info->skb);
+                                       buffer_info->skb, next_desc);
                        } else {
-                               printk(KERN_INFO "R  [0x%03X]     %016llX "
-                                       "%016llX %016llX %p", i,
+                               pr_info("%s[0x%03X]     %016llX %016llX %016llX"
+                                       " %p%s\n", "R  ", i,
                                        le64_to_cpu(u0->a),
                                        le64_to_cpu(u0->b),
                                        (u64)buffer_info->dma,
-                                       buffer_info->skb);
+                                       buffer_info->skb, next_desc);
 
                                if (netif_msg_pktdata(adapter)) {
                                        print_hex_dump(KERN_INFO, "",
@@ -538,14 +542,6 @@ rx_ring_summary:
                                          PAGE_SIZE/2, true);
                                }
                        }
-
-                       if (i == rx_ring->next_to_use)
-                               printk(KERN_CONT " NTU\n");
-                       else if (i == rx_ring->next_to_clean)
-                               printk(KERN_CONT " NTC\n");
-                       else
-                               printk(KERN_CONT "\n");
-
                }
        }
 
@@ -599,10 +595,10 @@ struct net_device *igb_get_hw_dev(struct e1000_hw *hw)
 static int __init igb_init_module(void)
 {
        int ret;
-       printk(KERN_INFO "%s - version %s\n",
+       pr_info("%s - version %s\n",
               igb_driver_string, igb_driver_version);
 
-       printk(KERN_INFO "%s\n", igb_copyright);
+       pr_info("%s\n", igb_copyright);
 
 #ifdef CONFIG_IGB_DCA
        dca_register_notify(&dca_notifier);
@@ -1742,7 +1738,8 @@ void igb_reset(struct igb_adapter *adapter)
        igb_get_phy_info(hw);
 }
 
-static u32 igb_fix_features(struct net_device *netdev, u32 features)
+static netdev_features_t igb_fix_features(struct net_device *netdev,
+       netdev_features_t features)
 {
        /*
         * Since there is no support for separate rx/tx vlan accel
@@ -1756,9 +1753,10 @@ static u32 igb_fix_features(struct net_device *netdev, u32 features)
        return features;
 }
 
-static int igb_set_features(struct net_device *netdev, u32 features)
+static int igb_set_features(struct net_device *netdev,
+       netdev_features_t features)
 {
-       u32 changed = netdev->features ^ features;
+       netdev_features_t changed = netdev->features ^ features;
 
        if (changed & NETIF_F_HW_VLAN_RX)
                igb_vlan_mode(netdev, features);
@@ -3640,23 +3638,23 @@ static void igb_watchdog_task(struct work_struct *work)
 
                        ctrl = rd32(E1000_CTRL);
                        /* Links status message must follow this format */
-                       printk(KERN_INFO "igb: %s NIC Link is Up %d Mbps %s, "
-                                "Flow Control: %s\n",
+                       printk(KERN_INFO "igb: %s NIC Link is Up %d Mbps %s "
+                              "Duplex, Flow Control: %s\n",
                               netdev->name,
                               adapter->link_speed,
                               adapter->link_duplex == FULL_DUPLEX ?
-                                "Full Duplex" : "Half Duplex",
-                              ((ctrl & E1000_CTRL_TFCE) &&
-                               (ctrl & E1000_CTRL_RFCE)) ? "RX/TX" :
-                              ((ctrl & E1000_CTRL_RFCE) ?  "RX" :
-                              ((ctrl & E1000_CTRL_TFCE) ?  "TX" : "None")));
+                              "Full" : "Half",
+                              (ctrl & E1000_CTRL_TFCE) &&
+                              (ctrl & E1000_CTRL_RFCE) ? "RX/TX" :
+                              (ctrl & E1000_CTRL_RFCE) ?  "RX" :
+                              (ctrl & E1000_CTRL_TFCE) ?  "TX" : "None");
 
                        /* check for thermal sensor event */
-                       if (igb_thermal_sensor_event(hw, E1000_THSTAT_LINK_THROTTLE)) {
-                               printk(KERN_INFO "igb: %s The network adapter "
-                                                "link speed was downshifted "
-                                                "because it overheated.\n",
-                                                netdev->name);
+                       if (igb_thermal_sensor_event(hw,
+                           E1000_THSTAT_LINK_THROTTLE)) {
+                               netdev_info(netdev, "The network adapter link "
+                                           "speed was downshifted because it "
+                                           "overheated\n");
                        }
 
                        /* adjust timeout factor according to speed/duplex */
@@ -3686,11 +3684,10 @@ static void igb_watchdog_task(struct work_struct *work)
                        adapter->link_duplex = 0;
 
                        /* check for thermal sensor event */
-                       if (igb_thermal_sensor_event(hw, E1000_THSTAT_PWR_DOWN)) {
-                               printk(KERN_ERR "igb: %s The network adapter "
-                                               "was stopped because it "
-                                               "overheated.\n",
-                                               netdev->name);
+                       if (igb_thermal_sensor_event(hw,
+                           E1000_THSTAT_PWR_DOWN)) {
+                               netdev_err(netdev, "The network adapter was "
+                                          "stopped because it overheated\n");
                        }
 
                        /* Links status message must follow this format */
@@ -6138,7 +6135,7 @@ static bool igb_alloc_mapped_page(struct igb_ring *rx_ring,
                return true;
 
        if (!page) {
-               page = netdev_alloc_page(rx_ring->netdev);
+               page = alloc_page(GFP_ATOMIC | __GFP_COLD);
                bi->page = page;
                if (unlikely(!page)) {
                        rx_ring->rx_stats.alloc_failed++;
@@ -6467,7 +6464,7 @@ s32 igb_write_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value)
        return 0;
 }
 
-static void igb_vlan_mode(struct net_device *netdev, u32 features)
+static void igb_vlan_mode(struct net_device *netdev, netdev_features_t features)
 {
        struct igb_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
index 2c25858..7b600a1 100644 (file)
@@ -191,12 +191,12 @@ static void igbvf_get_drvinfo(struct net_device *netdev,
                               struct ethtool_drvinfo *drvinfo)
 {
        struct igbvf_adapter *adapter = netdev_priv(netdev);
-       char firmware_version[32] = "N/A";
 
-       strncpy(drvinfo->driver,  igbvf_driver_name, 32);
-       strncpy(drvinfo->version, igbvf_driver_version, 32);
-       strncpy(drvinfo->fw_version, firmware_version, 32);
-       strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
+       strlcpy(drvinfo->driver,  igbvf_driver_name, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, igbvf_driver_version,
+               sizeof(drvinfo->version));
+       strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
+               sizeof(drvinfo->bus_info));
        drvinfo->regdump_len = igbvf_get_regs_len(netdev);
        drvinfo->eedump_len = igbvf_get_eeprom_len(netdev);
 }
index cca7812..c358973 100644 (file)
@@ -25,6 +25,8 @@
 
 *******************************************************************************/
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/init.h>
@@ -1746,10 +1748,9 @@ void igbvf_update_stats(struct igbvf_adapter *adapter)
 
 static void igbvf_print_link_info(struct igbvf_adapter *adapter)
 {
-       dev_info(&adapter->pdev->dev, "Link is Up %d Mbps %s\n",
-                adapter->link_speed,
-                ((adapter->link_duplex == FULL_DUPLEX) ?
-                 "Full Duplex" : "Half Duplex"));
+       dev_info(&adapter->pdev->dev, "Link is Up %d Mbps %s Duplex\n",
+                adapter->link_speed,
+                adapter->link_duplex == FULL_DUPLEX ? "Full" : "Half");
 }
 
 static bool igbvf_has_link(struct igbvf_adapter *adapter)
@@ -2532,7 +2533,8 @@ static void igbvf_print_device_info(struct igbvf_adapter *adapter)
        dev_info(&pdev->dev, "Address: %pM\n", netdev->dev_addr);
 }
 
-static int igbvf_set_features(struct net_device *netdev, u32 features)
+static int igbvf_set_features(struct net_device *netdev,
+       netdev_features_t features)
 {
        struct igbvf_adapter *adapter = netdev_priv(netdev);
 
@@ -2842,9 +2844,8 @@ static struct pci_driver igbvf_driver = {
 static int __init igbvf_init_module(void)
 {
        int ret;
-       printk(KERN_INFO "%s - version %s\n",
-              igbvf_driver_string, igbvf_driver_version);
-       printk(KERN_INFO "%s\n", igbvf_copyright);
+       pr_info("%s - version %s\n", igbvf_driver_string, igbvf_driver_version);
+       pr_info("%s\n", igbvf_copyright);
 
        ret = pci_register_driver(&igbvf_driver);
 
index 9dfce7d..dbb7dd2 100644 (file)
@@ -473,10 +473,12 @@ ixgb_get_drvinfo(struct net_device *netdev,
 {
        struct ixgb_adapter *adapter = netdev_priv(netdev);
 
-       strncpy(drvinfo->driver,  ixgb_driver_name, 32);
-       strncpy(drvinfo->version, ixgb_driver_version, 32);
-       strncpy(drvinfo->fw_version, "N/A", 32);
-       strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
+       strlcpy(drvinfo->driver,  ixgb_driver_name,
+               sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, ixgb_driver_version,
+               sizeof(drvinfo->version));
+       strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
+               sizeof(drvinfo->bus_info));
        drvinfo->n_stats = IXGB_STATS_LEN;
        drvinfo->regdump_len = ixgb_get_regs_len(netdev);
        drvinfo->eedump_len = ixgb_get_eeprom_len(netdev);
index e21148f..247cf92 100644 (file)
@@ -325,8 +325,8 @@ ixgb_reset(struct ixgb_adapter *adapter)
        }
 }
 
-static u32
-ixgb_fix_features(struct net_device *netdev, u32 features)
+static netdev_features_t
+ixgb_fix_features(struct net_device *netdev, netdev_features_t features)
 {
        /*
         * Tx VLAN insertion does not work per HW design when Rx stripping is
@@ -339,10 +339,10 @@ ixgb_fix_features(struct net_device *netdev, u32 features)
 }
 
 static int
-ixgb_set_features(struct net_device *netdev, u32 features)
+ixgb_set_features(struct net_device *netdev, netdev_features_t features)
 {
        struct ixgb_adapter *adapter = netdev_priv(netdev);
-       u32 changed = features ^ netdev->features;
+       netdev_features_t changed = features ^ netdev->features;
 
        if (!(changed & (NETIF_F_RXCSUM|NETIF_F_HW_VLAN_RX)))
                return 0;
index 70d58c3..91f871b 100644 (file)
@@ -888,23 +888,19 @@ static void ixgbe_get_drvinfo(struct net_device *netdev,
                               struct ethtool_drvinfo *drvinfo)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
-       char firmware_version[32];
        u32 nvm_track_id;
 
-       strncpy(drvinfo->driver, ixgbe_driver_name,
-               sizeof(drvinfo->driver) - 1);
-       strncpy(drvinfo->version, ixgbe_driver_version,
-               sizeof(drvinfo->version) - 1);
+       strlcpy(drvinfo->driver, ixgbe_driver_name, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, ixgbe_driver_version,
+               sizeof(drvinfo->version));
 
        nvm_track_id = (adapter->eeprom_verh << 16) |
                        adapter->eeprom_verl;
-       snprintf(firmware_version, sizeof(firmware_version), "0x%08x",
+       snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), "0x%08x",
                 nvm_track_id);
 
-       strncpy(drvinfo->fw_version, firmware_version,
-               sizeof(drvinfo->fw_version) - 1);
-       strncpy(drvinfo->bus_info, pci_name(adapter->pdev),
-               sizeof(drvinfo->bus_info) - 1);
+       strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
+               sizeof(drvinfo->bus_info));
        drvinfo->n_stats = IXGBE_STATS_LEN;
        drvinfo->testinfo_len = IXGBE_TEST_LEN;
        drvinfo->regdump_len = ixgbe_get_regs_len(netdev);
index 8ef92d1..1b28ed9 100644 (file)
@@ -1140,7 +1140,7 @@ void ixgbe_alloc_rx_buffers(struct ixgbe_ring *rx_ring, u16 cleaned_count)
 
                if (ring_is_ps_enabled(rx_ring)) {
                        if (!bi->page) {
-                               bi->page = netdev_alloc_page(rx_ring->netdev);
+                               bi->page = alloc_page(GFP_ATOMIC | __GFP_COLD);
                                if (!bi->page) {
                                        rx_ring->rx_stats.alloc_rx_page_failed++;
                                        goto no_buffers;
@@ -7174,7 +7174,8 @@ void ixgbe_do_reset(struct net_device *netdev)
                ixgbe_reset(adapter);
 }
 
-static u32 ixgbe_fix_features(struct net_device *netdev, u32 data)
+static netdev_features_t ixgbe_fix_features(struct net_device *netdev,
+       netdev_features_t data)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
 
@@ -7204,7 +7205,8 @@ static u32 ixgbe_fix_features(struct net_device *netdev, u32 data)
        return data;
 }
 
-static int ixgbe_set_features(struct net_device *netdev, u32 data)
+static int ixgbe_set_features(struct net_device *netdev,
+       netdev_features_t data)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
        bool need_reset = false;
index 00fcd39..cf6812d 100644 (file)
@@ -572,7 +572,7 @@ static int ixgbe_rcv_msg_from_vf(struct ixgbe_adapter *adapter, u32 vf)
 
                /* reply to reset with ack and vf mac address */
                msgbuf[0] = IXGBE_VF_RESET | IXGBE_VT_MSGTYPE_ACK;
-               memcpy(new_mac, vf_mac, IXGBE_ETH_LENGTH_OF_ADDRESS);
+               memcpy(new_mac, vf_mac, ETH_ALEN);
                /*
                 * Piggyback the multicast filter type so VF can compute the
                 * correct vectors
index 6c5cca8..242643a 100644 (file)
@@ -1710,8 +1710,6 @@ enum {
 #define IXGBE_NVM_POLL_WRITE       1  /* Flag for polling for write complete */
 #define IXGBE_NVM_POLL_READ        0  /* Flag for polling for read complete */
 
-#define IXGBE_ETH_LENGTH_OF_ADDRESS   6
-
 #define IXGBE_EEPROM_PAGE_SIZE_MAX       128
 #define IXGBE_EEPROM_RD_BUFFER_MAX_COUNT 512 /* EEPROM words # read in burst */
 #define IXGBE_EEPROM_WR_BUFFER_MAX_COUNT 256 /* EEPROM words # wr in burst */
@@ -2802,9 +2800,9 @@ struct ixgbe_eeprom_info {
 struct ixgbe_mac_info {
        struct ixgbe_mac_operations     ops;
        enum ixgbe_mac_type             type;
-       u8                              addr[IXGBE_ETH_LENGTH_OF_ADDRESS];
-       u8                              perm_addr[IXGBE_ETH_LENGTH_OF_ADDRESS];
-       u8                              san_addr[IXGBE_ETH_LENGTH_OF_ADDRESS];
+       u8                              addr[ETH_ALEN];
+       u8                              perm_addr[ETH_ALEN];
+       u8                              san_addr[ETH_ALEN];
        /* prefix for World Wide Node Name (WWNN) */
        u16                             wwnn_prefix;
        /* prefix for World Wide Port Name (WWPN) */
index e5101e9..8cc5ecc 100644 (file)
@@ -751,16 +751,20 @@ static s32 ixgbe_blink_led_start_X540(struct ixgbe_hw *hw, u32 index)
 {
        u32 macc_reg;
        u32 ledctl_reg;
+       ixgbe_link_speed speed;
+       bool link_up;
 
        /*
-        * In order for the blink bit in the LED control register
-        * to work, link and speed must be forced in the MAC. We
-        * will reverse this when we stop the blinking.
+        * Link should be up in order for the blink bit in the LED control
+        * register to work. Force link and speed in the MAC if link is down.
+        * This will be reversed when we stop the blinking.
         */
-       macc_reg = IXGBE_READ_REG(hw, IXGBE_MACC);
-       macc_reg |= IXGBE_MACC_FLU | IXGBE_MACC_FSV_10G | IXGBE_MACC_FS;
-       IXGBE_WRITE_REG(hw, IXGBE_MACC, macc_reg);
-
+       hw->mac.ops.check_link(hw, &speed, &link_up, false);
+       if (link_up == false) {
+               macc_reg = IXGBE_READ_REG(hw, IXGBE_MACC);
+               macc_reg |= IXGBE_MACC_FLU | IXGBE_MACC_FSV_10G | IXGBE_MACC_FS;
+               IXGBE_WRITE_REG(hw, IXGBE_MACC, macc_reg);
+       }
        /* Set the LED to LINK_UP + BLINK. */
        ledctl_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
        ledctl_reg &= ~IXGBE_LED_MODE_MASK(index);
index 78abb6f..2eb89cb 100644 (file)
@@ -35,7 +35,6 @@
 #define IXGBE_VF_IRQ_CLEAR_MASK         7
 #define IXGBE_VF_MAX_TX_QUEUES          1
 #define IXGBE_VF_MAX_RX_QUEUES          1
-#define IXGBE_ETH_LENGTH_OF_ADDRESS     6
 
 /* Link speed */
 typedef u32 ixgbe_link_speed;
index e29ba45..dc8e651 100644 (file)
@@ -27,6 +27,8 @@
 
 /* ethtool support for ixgbevf */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/slab.h>
@@ -265,11 +267,11 @@ static void ixgbevf_get_drvinfo(struct net_device *netdev,
 {
        struct ixgbevf_adapter *adapter = netdev_priv(netdev);
 
-       strlcpy(drvinfo->driver, ixgbevf_driver_name, 32);
-       strlcpy(drvinfo->version, ixgbevf_driver_version, 32);
-
-       strlcpy(drvinfo->fw_version, "N/A", 4);
-       strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
+       strlcpy(drvinfo->driver, ixgbevf_driver_name, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, ixgbevf_driver_version,
+               sizeof(drvinfo->version));
+       strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
+               sizeof(drvinfo->bus_info));
 }
 
 static void ixgbevf_get_ringparam(struct net_device *netdev,
@@ -549,8 +551,8 @@ static const u32 register_test_patterns[] = {
        writel((W & M), (adapter->hw.hw_addr + R));                           \
        val = readl(adapter->hw.hw_addr + R);                                 \
        if ((W & M) != (val & M)) {                                           \
-               printk(KERN_ERR "set/check reg %04X test failed: got 0x%08X " \
-                                "expected 0x%08X\n", R, (val & M), (W & M)); \
+               pr_err("set/check reg %04X test failed: got 0x%08X expected " \
+                      "0x%08X\n", R, (val & M), (W & M));                    \
                *data = R;                                                    \
                writel(before, (adapter->hw.hw_addr + R));                    \
                return 1;                                                     \
index 4c8e199..5d1a643 100644 (file)
@@ -29,6 +29,9 @@
 /******************************************************************************
  Copyright (c)2006 - 2007 Myricom, Inc. for some LRO specific code
 ******************************************************************************/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/types.h>
 #include <linux/bitops.h>
 #include <linux/module.h>
@@ -363,7 +366,7 @@ static void ixgbevf_alloc_rx_buffers(struct ixgbevf_adapter *adapter,
                if (!bi->page_dma &&
                    (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED)) {
                        if (!bi->page) {
-                               bi->page = netdev_alloc_page(adapter->netdev);
+                               bi->page = alloc_page(GFP_ATOMIC | __GFP_COLD);
                                if (!bi->page) {
                                        adapter->alloc_rx_page_failed++;
                                        goto no_buffers;
@@ -1437,7 +1440,7 @@ static int ixgbevf_write_uc_addr_list(struct net_device *netdev)
        int count = 0;
 
        if ((netdev_uc_count(netdev)) > 10) {
-               printk(KERN_ERR "Too many unicast filters - No Space\n");
+               pr_err("Too many unicast filters - No Space\n");
                return -ENOSPC;
        }
 
@@ -2135,7 +2138,7 @@ static int ixgbevf_init_interrupt_scheme(struct ixgbevf_adapter *adapter)
 
        err = ixgbevf_alloc_queues(adapter);
        if (err) {
-               printk(KERN_ERR "Unable to allocate memory for queues\n");
+               pr_err("Unable to allocate memory for queues\n");
                goto err_alloc_queues;
        }
 
@@ -2189,7 +2192,7 @@ static int __devinit ixgbevf_sw_init(struct ixgbevf_adapter *adapter)
        } else {
                err = hw->mac.ops.init_hw(hw);
                if (err) {
-                       printk(KERN_ERR "init_shared_code failed: %d\n", err);
+                       pr_err("init_shared_code failed: %d\n", err);
                        goto out;
                }
        }
@@ -2630,8 +2633,8 @@ static int ixgbevf_open(struct net_device *netdev)
                 * the vf can't start. */
                if (hw->adapter_stopped) {
                        err = IXGBE_ERR_MBX;
-                       printk(KERN_ERR "Unable to start - perhaps the PF"
-                              " Driver isn't up yet\n");
+                       pr_err("Unable to start - perhaps the PF Driver isn't "
+                              "up yet\n");
                        goto err_setup_reset;
                }
        }
@@ -2842,10 +2845,8 @@ static bool ixgbevf_tx_csum(struct ixgbevf_adapter *adapter,
                                break;
                        default:
                                if (unlikely(net_ratelimit())) {
-                                       printk(KERN_WARNING
-                                              "partial checksum but "
-                                              "proto=%x!\n",
-                                              skb->protocol);
+                                       pr_warn("partial checksum but "
+                                               "proto=%x!\n", skb->protocol);
                                }
                                break;
                        }
@@ -3249,7 +3250,8 @@ static struct rtnl_link_stats64 *ixgbevf_get_stats(struct net_device *netdev,
        return stats;
 }
 
-static int ixgbevf_set_features(struct net_device *netdev, u32 features)
+static int ixgbevf_set_features(struct net_device *netdev,
+       netdev_features_t features)
 {
        struct ixgbevf_adapter *adapter = netdev_priv(netdev);
 
@@ -3414,7 +3416,7 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
        memcpy(netdev->perm_addr, adapter->hw.mac.addr, netdev->addr_len);
 
        if (!is_valid_ether_addr(netdev->dev_addr)) {
-               printk(KERN_ERR "invalid MAC address\n");
+               pr_err("invalid MAC address\n");
                err = -EIO;
                goto err_sw_init;
        }
@@ -3535,10 +3537,10 @@ static struct pci_driver ixgbevf_driver = {
 static int __init ixgbevf_init_module(void)
 {
        int ret;
-       printk(KERN_INFO "ixgbevf: %s - version %s\n", ixgbevf_driver_string,
-              ixgbevf_driver_version);
+       pr_info("%s - version %s\n", ixgbevf_driver_string,
+               ixgbevf_driver_version);
 
-       printk(KERN_INFO "%s\n", ixgbevf_copyright);
+       pr_info("%s\n", ixgbevf_copyright);
 
        ret = pci_register_driver(&ixgbevf_driver);
        return ret;
index aa3682e..21533e3 100644 (file)
@@ -108,7 +108,7 @@ static s32 ixgbevf_reset_hw_vf(struct ixgbe_hw *hw)
        if (msgbuf[0] != (IXGBE_VF_RESET | IXGBE_VT_MSGTYPE_ACK))
                return IXGBE_ERR_INVALID_MAC_ADDR;
 
-       memcpy(hw->mac.perm_addr, addr, IXGBE_ETH_LENGTH_OF_ADDRESS);
+       memcpy(hw->mac.perm_addr, addr, ETH_ALEN);
        hw->mac.mc_filter_type = msgbuf[IXGBE_VF_MC_TYPE_WORD];
 
        return 0;
@@ -211,7 +211,7 @@ static s32 ixgbevf_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr)
  **/
 static s32 ixgbevf_get_mac_addr_vf(struct ixgbe_hw *hw, u8 *mac_addr)
 {
-       memcpy(mac_addr, hw->mac.perm_addr, IXGBE_ETH_LENGTH_OF_ADDRESS);
+       memcpy(mac_addr, hw->mac.perm_addr, ETH_ALEN);
 
        return 0;
 }
index 7becff1..5c0b531 100644 (file)
@@ -1883,7 +1883,7 @@ jme_fill_tx_map(struct pci_dev *pdev,
                struct page *page,
                u32 page_offset,
                u32 len,
-               u8 hidma)
+               bool hidma)
 {
        dma_addr_t dmaaddr;
 
@@ -1917,7 +1917,7 @@ jme_map_tx_skb(struct jme_adapter *jme, struct sk_buff *skb, int idx)
        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;
+       bool hidma = jme->dev->features & NETIF_F_HIGHDMA;
        int i, nr_frags = skb_shinfo(skb)->nr_frags;
        int mask = jme->tx_ring_mask;
        const struct skb_frag_struct *frag;
@@ -2292,9 +2292,9 @@ jme_get_drvinfo(struct net_device *netdev,
 {
        struct jme_adapter *jme = netdev_priv(netdev);
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, pci_name(jme->pdev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(jme->pdev), sizeof(info->bus_info));
 }
 
 static int
@@ -2620,8 +2620,8 @@ jme_set_msglevel(struct net_device *netdev, u32 value)
        jme->msg_enable = value;
 }
 
-static u32
-jme_fix_features(struct net_device *netdev, u32 features)
+static netdev_features_t
+jme_fix_features(struct net_device *netdev, netdev_features_t features)
 {
        if (netdev->mtu > 1900)
                features &= ~(NETIF_F_ALL_TSO | NETIF_F_ALL_CSUM);
@@ -2629,7 +2629,7 @@ jme_fix_features(struct net_device *netdev, u32 features)
 }
 
 static int
-jme_set_features(struct net_device *netdev, u32 features)
+jme_set_features(struct net_device *netdev, netdev_features_t features)
 {
        struct jme_adapter *jme = netdev_priv(netdev);
 
index 6bb2b95..0b3567a 100644 (file)
@@ -34,6 +34,8 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
 
 #include <asm/checksum.h>
 
index 194a031..e87847e 100644 (file)
@@ -1502,10 +1502,12 @@ mv643xx_eth_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 static void mv643xx_eth_get_drvinfo(struct net_device *dev,
                                    struct ethtool_drvinfo *drvinfo)
 {
-       strncpy(drvinfo->driver,  mv643xx_eth_driver_name, 32);
-       strncpy(drvinfo->version, mv643xx_eth_driver_version, 32);
-       strncpy(drvinfo->fw_version, "N/A", 32);
-       strncpy(drvinfo->bus_info, "platform", 32);
+       strlcpy(drvinfo->driver, mv643xx_eth_driver_name,
+               sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, mv643xx_eth_driver_version,
+               sizeof(drvinfo->version));
+       strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
+       strlcpy(drvinfo->bus_info, "platform", sizeof(drvinfo->bus_info));
        drvinfo->n_stats = ARRAY_SIZE(mv643xx_eth_stats);
 }
 
@@ -1578,10 +1580,10 @@ mv643xx_eth_set_ringparam(struct net_device *dev, struct ethtool_ringparam *er)
 
 
 static int
-mv643xx_eth_set_features(struct net_device *dev, u32 features)
+mv643xx_eth_set_features(struct net_device *dev, netdev_features_t features)
 {
        struct mv643xx_eth_private *mp = netdev_priv(dev);
-       u32 rx_csum = features & NETIF_F_RXCSUM;
+       bool rx_csum = features & NETIF_F_RXCSUM;
 
        wrlp(mp, PORT_CONFIG, rx_csum ? 0x02000000 : 0x00000000);
 
index c7b6083..d957b2c 100644 (file)
@@ -394,10 +394,10 @@ static void skge_get_drvinfo(struct net_device *dev,
 {
        struct skge_port *skge = netdev_priv(dev);
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->fw_version, "N/A");
-       strcpy(info->bus_info, pci_name(skge->hw->pdev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(skge->hw->pdev),
+               sizeof(info->bus_info));
 }
 
 static const struct skge_stat {
index fdc6c39..29adc78 100644 (file)
@@ -50,7 +50,7 @@
 #include "sky2.h"
 
 #define DRV_NAME               "sky2"
-#define DRV_VERSION            "1.29"
+#define DRV_VERSION            "1.30"
 
 /*
  * The Yukon II chipset takes 64 bit command blocks (called list elements)
@@ -68,7 +68,7 @@
 #define MAX_SKB_TX_LE  (2 + (sizeof(dma_addr_t)/sizeof(u32))*(MAX_SKB_FRAGS+1))
 #define TX_MIN_PENDING         (MAX_SKB_TX_LE+1)
 #define TX_MAX_PENDING         1024
-#define TX_DEF_PENDING         127
+#define TX_DEF_PENDING         63
 
 #define TX_WATCHDOG            (5 * HZ)
 #define NAPI_WEIGHT            64
@@ -869,6 +869,7 @@ static void sky2_wol_init(struct sky2_port *sky2)
 
        /* block receiver */
        sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET);
+       sky2_read32(hw, B0_CTST);
 }
 
 static void sky2_set_tx_stfwd(struct sky2_hw *hw, unsigned port)
@@ -1274,8 +1275,16 @@ static void rx_set_checksum(struct sky2_port *sky2)
                     ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM);
 }
 
+/*
+ * Fixed initial key as seed to RSS.
+ */
+static const uint32_t rss_init_key[10] = {
+       0x7c3351da, 0x51c5cf4e, 0x44adbdd1, 0xe8d38d18, 0x48897c43,
+       0xb1d60e7e, 0x6a3dd760, 0x01a2e453, 0x16f46f13, 0x1a0e7b30
+};
+
 /* Enable/disable receive hash calculation (RSS) */
-static void rx_set_rss(struct net_device *dev, u32 features)
+static void rx_set_rss(struct net_device *dev, netdev_features_t features)
 {
        struct sky2_port *sky2 = netdev_priv(dev);
        struct sky2_hw *hw = sky2->hw;
@@ -1289,12 +1298,9 @@ static void rx_set_rss(struct net_device *dev, u32 features)
 
        /* Program RSS initial values */
        if (features & NETIF_F_RXHASH) {
-               u32 key[nkeys];
-
-               get_random_bytes(key, nkeys * sizeof(u32));
                for (i = 0; i < nkeys; i++)
                        sky2_write32(hw, SK_REG(sky2->port, RSS_KEY + i * 4),
-                                    key[i]);
+                                    rss_init_key[i]);
 
                /* Need to turn on (undocumented) flag to make hashing work  */
                sky2_write32(hw, SK_REG(sky2->port, RX_GMF_CTRL_T),
@@ -1396,7 +1402,7 @@ static int sky2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 
 #define SKY2_VLAN_OFFLOADS (NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO)
 
-static void sky2_vlan_mode(struct net_device *dev, u32 features)
+static void sky2_vlan_mode(struct net_device *dev, netdev_features_t features)
 {
        struct sky2_port *sky2 = netdev_priv(dev);
        struct sky2_hw *hw = sky2->hw;
@@ -1717,6 +1723,8 @@ static int sky2_setup_irq(struct sky2_hw *hw, const char *name)
        if (err)
                dev_err(&pdev->dev, "cannot assign irq %d\n", pdev->irq);
        else {
+               hw->flags |= SKY2_HW_IRQ_SETUP;
+
                napi_enable(&hw->napi);
                sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
                sky2_read32(hw, B0_IMSK);
@@ -1727,7 +1735,7 @@ static int sky2_setup_irq(struct sky2_hw *hw, const char *name)
 
 
 /* Bring up network interface. */
-static int sky2_up(struct net_device *dev)
+static int sky2_open(struct net_device *dev)
 {
        struct sky2_port *sky2 = netdev_priv(dev);
        struct sky2_hw *hw = sky2->hw;
@@ -1747,6 +1755,11 @@ static int sky2_up(struct net_device *dev)
 
        sky2_hw_up(sky2);
 
+       if (hw->chip_id == CHIP_ID_YUKON_OPT ||
+           hw->chip_id == CHIP_ID_YUKON_PRM ||
+           hw->chip_id == CHIP_ID_YUKON_OP_2)
+               imask |= Y2_IS_PHY_QLNK;        /* enable PHY Quick Link */
+
        /* Enable interrupts from phy/mac for port */
        imask = sky2_read32(hw, B0_IMSK);
        imask |= portirq_msk[port];
@@ -2040,6 +2053,8 @@ static void sky2_tx_reset(struct sky2_hw *hw, unsigned port)
 
        sky2_write32(hw, RB_ADDR(txqaddr[port], RB_CTRL), RB_RST_SET);
        sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_SET);
+
+       sky2_read32(hw, B0_CTST);
 }
 
 static void sky2_hw_down(struct sky2_port *sky2)
@@ -2090,7 +2105,7 @@ static void sky2_hw_down(struct sky2_port *sky2)
 }
 
 /* Network shutdown */
-static int sky2_down(struct net_device *dev)
+static int sky2_close(struct net_device *dev)
 {
        struct sky2_port *sky2 = netdev_priv(dev);
        struct sky2_hw *hw = sky2->hw;
@@ -2101,15 +2116,22 @@ static int sky2_down(struct net_device *dev)
 
        netif_info(sky2, ifdown, dev, "disabling interface\n");
 
-       /* Disable port IRQ */
-       sky2_write32(hw, B0_IMSK,
-                    sky2_read32(hw, B0_IMSK) & ~portirq_msk[sky2->port]);
-       sky2_read32(hw, B0_IMSK);
-
        if (hw->ports == 1) {
+               sky2_write32(hw, B0_IMSK, 0);
+               sky2_read32(hw, B0_IMSK);
+
                napi_disable(&hw->napi);
                free_irq(hw->pdev->irq, hw);
+               hw->flags &= ~SKY2_HW_IRQ_SETUP;
        } else {
+               u32 imask;
+
+               /* Disable port IRQ */
+               imask  = sky2_read32(hw, B0_IMSK);
+               imask &= ~portirq_msk[sky2->port];
+               sky2_write32(hw, B0_IMSK, imask);
+               sky2_read32(hw, B0_IMSK);
+
                synchronize_irq(hw->pdev->irq);
                napi_synchronize(&hw->napi);
        }
@@ -2587,7 +2609,7 @@ static inline void sky2_tx_done(struct net_device *dev, u16 last)
        if (netif_running(dev)) {
                sky2_tx_complete(sky2, last);
 
-               /* Wake unless it's detached, and called e.g. from sky2_down() */
+               /* Wake unless it's detached, and called e.g. from sky2_close() */
                if (tx_avail(sky2) > MAX_SKB_TX_LE + 4)
                        netif_wake_queue(dev);
        }
@@ -3258,7 +3280,6 @@ static void sky2_reset(struct sky2_hw *hw)
            hw->chip_id == CHIP_ID_YUKON_PRM ||
            hw->chip_id == CHIP_ID_YUKON_OP_2) {
                u16 reg;
-               u32 msk;
 
                if (hw->chip_id == CHIP_ID_YUKON_OPT && hw->chip_rev == 0) {
                        /* disable PCI-E PHY power down (set PHY reg 0x80, bit 7 */
@@ -3281,11 +3302,6 @@ static void sky2_reset(struct sky2_hw *hw)
                sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
                sky2_pci_write16(hw, PSM_CONFIG_REG4, reg);
 
-               /* enable PHY Quick Link */
-               msk = sky2_read32(hw, B0_IMSK);
-               msk |= Y2_IS_PHY_QLNK;
-               sky2_write32(hw, B0_IMSK, msk);
-
                /* check if PSMv2 was running before */
                reg = sky2_pci_read16(hw, PSM_CONFIG_REG3);
                if (reg & PCI_EXP_LNKCTL_ASPMC)
@@ -3383,7 +3399,7 @@ static void sky2_detach(struct net_device *dev)
                netif_tx_lock(dev);
                netif_device_detach(dev);       /* stop txq */
                netif_tx_unlock(dev);
-               sky2_down(dev);
+               sky2_close(dev);
        }
 }
 
@@ -3393,7 +3409,7 @@ static int sky2_reattach(struct net_device *dev)
        int err = 0;
 
        if (netif_running(dev)) {
-               err = sky2_up(dev);
+               err = sky2_open(dev);
                if (err) {
                        netdev_info(dev, "could not restart %d\n", err);
                        dev_close(dev);
@@ -3410,10 +3426,13 @@ static void sky2_all_down(struct sky2_hw *hw)
 {
        int i;
 
-       sky2_read32(hw, B0_IMSK);
-       sky2_write32(hw, B0_IMSK, 0);
-       synchronize_irq(hw->pdev->irq);
-       napi_disable(&hw->napi);
+       if (hw->flags & SKY2_HW_IRQ_SETUP) {
+               sky2_read32(hw, B0_IMSK);
+               sky2_write32(hw, B0_IMSK, 0);
+
+               synchronize_irq(hw->pdev->irq);
+               napi_disable(&hw->napi);
+       }
 
        for (i = 0; i < hw->ports; i++) {
                struct net_device *dev = hw->dev[i];
@@ -3446,11 +3465,12 @@ static void sky2_all_up(struct sky2_hw *hw)
                netif_wake_queue(dev);
        }
 
-       sky2_write32(hw, B0_IMSK, imask);
-       sky2_read32(hw, B0_IMSK);
-
-       sky2_read32(hw, B0_Y2_SP_LISR);
-       napi_enable(&hw->napi);
+       if (hw->flags & SKY2_HW_IRQ_SETUP) {
+               sky2_write32(hw, B0_IMSK, imask);
+               sky2_read32(hw, B0_IMSK);
+               sky2_read32(hw, B0_Y2_SP_LISR);
+               napi_enable(&hw->napi);
+       }
 }
 
 static void sky2_restart(struct work_struct *work)
@@ -3623,10 +3643,10 @@ static void sky2_get_drvinfo(struct net_device *dev,
 {
        struct sky2_port *sky2 = netdev_priv(dev);
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->fw_version, "N/A");
-       strcpy(info->bus_info, pci_name(sky2->hw->pdev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(sky2->hw->pdev),
+               sizeof(info->bus_info));
 }
 
 static const struct sky2_stat {
@@ -4071,6 +4091,16 @@ static int sky2_set_coalesce(struct net_device *dev,
        return 0;
 }
 
+/*
+ * Hardware is limited to min of 128 and max of 2048 for ring size
+ * and  rounded up to next power of two
+ * to avoid division in modulus calclation
+ */
+static unsigned long roundup_ring_size(unsigned long pending)
+{
+       return max(128ul, roundup_pow_of_two(pending+1));
+}
+
 static void sky2_get_ringparam(struct net_device *dev,
                               struct ethtool_ringparam *ering)
 {
@@ -4098,7 +4128,7 @@ static int sky2_set_ringparam(struct net_device *dev,
 
        sky2->rx_pending = ering->rx_pending;
        sky2->tx_pending = ering->tx_pending;
-       sky2->tx_ring_size = roundup_pow_of_two(sky2->tx_pending+1);
+       sky2->tx_ring_size = roundup_ring_size(sky2->tx_pending);
 
        return sky2_reattach(dev);
 }
@@ -4281,7 +4311,8 @@ static int sky2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom
        return sky2_vpd_write(sky2->hw, cap, data, eeprom->offset, eeprom->len);
 }
 
-static u32 sky2_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t sky2_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        const struct sky2_port *sky2 = netdev_priv(dev);
        const struct sky2_hw *hw = sky2->hw;
@@ -4305,13 +4336,13 @@ static u32 sky2_fix_features(struct net_device *dev, u32 features)
        return features;
 }
 
-static int sky2_set_features(struct net_device *dev, u32 features)
+static int sky2_set_features(struct net_device *dev, netdev_features_t features)
 {
        struct sky2_port *sky2 = netdev_priv(dev);
-       u32 changed = dev->features ^ features;
+       netdev_features_t changed = dev->features ^ features;
 
        if (changed & NETIF_F_RXCSUM) {
-               u32 on = features & NETIF_F_RXCSUM;
+               bool on = features & NETIF_F_RXCSUM;
                sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR),
                             on ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM);
        }
@@ -4556,7 +4587,7 @@ static int sky2_device_event(struct notifier_block *unused,
        struct net_device *dev = ptr;
        struct sky2_port *sky2 = netdev_priv(dev);
 
-       if (dev->netdev_ops->ndo_open != sky2_up || !sky2_debug)
+       if (dev->netdev_ops->ndo_open != sky2_open || !sky2_debug)
                return NOTIFY_DONE;
 
        switch (event) {
@@ -4621,8 +4652,8 @@ static __exit void sky2_debug_cleanup(void)
    not allowing netpoll on second port */
 static const struct net_device_ops sky2_netdev_ops[2] = {
   {
-       .ndo_open               = sky2_up,
-       .ndo_stop               = sky2_down,
+       .ndo_open               = sky2_open,
+       .ndo_stop               = sky2_close,
        .ndo_start_xmit         = sky2_xmit_frame,
        .ndo_do_ioctl           = sky2_ioctl,
        .ndo_validate_addr      = eth_validate_addr,
@@ -4638,8 +4669,8 @@ static const struct net_device_ops sky2_netdev_ops[2] = {
 #endif
   },
   {
-       .ndo_open               = sky2_up,
-       .ndo_stop               = sky2_down,
+       .ndo_open               = sky2_open,
+       .ndo_stop               = sky2_close,
        .ndo_start_xmit         = sky2_xmit_frame,
        .ndo_do_ioctl           = sky2_ioctl,
        .ndo_validate_addr      = eth_validate_addr,
@@ -4692,7 +4723,7 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
        spin_lock_init(&sky2->phy_lock);
 
        sky2->tx_pending = TX_DEF_PENDING;
-       sky2->tx_ring_size = roundup_pow_of_two(TX_DEF_PENDING+1);
+       sky2->tx_ring_size = roundup_ring_size(TX_DEF_PENDING);
        sky2->rx_pending = RX_DEF_PENDING;
 
        hw->dev[port] = dev;
index 0af31b8..ff6f58b 100644 (file)
@@ -2287,6 +2287,7 @@ struct sky2_hw {
 #define SKY2_HW_RSS_BROKEN     0x00000100
 #define SKY2_HW_VLAN_BROKEN     0x00000200
 #define SKY2_HW_RSS_CHKSUM     0x00000400      /* RSS requires chksum */
+#define SKY2_HW_IRQ_SETUP      0x00000800
 
        u8                   chip_id;
        u8                   chip_rev;
index 74e2a2a..ee637a2 100644 (file)
@@ -45,13 +45,16 @@ mlx4_en_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
        struct mlx4_en_priv *priv = netdev_priv(dev);
        struct mlx4_en_dev *mdev = priv->mdev;
 
-       strncpy(drvinfo->driver, DRV_NAME, 32);
-       strncpy(drvinfo->version, DRV_VERSION " (" DRV_RELDATE ")", 32);
-       sprintf(drvinfo->fw_version, "%d.%d.%d",
+       strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, DRV_VERSION " (" DRV_RELDATE ")",
+               sizeof(drvinfo->version));
+       snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
+               "%d.%d.%d",
                (u16) (mdev->dev->caps.fw_ver >> 32),
                (u16) ((mdev->dev->caps.fw_ver >> 16) & 0xffff),
                (u16) (mdev->dev->caps.fw_ver & 0xffff));
-       strncpy(drvinfo->bus_info, pci_name(mdev->dev->pdev), 32);
+       strlcpy(drvinfo->bus_info, pci_name(mdev->dev->pdev),
+               sizeof(drvinfo->bus_info));
        drvinfo->n_stats = 0;
        drvinfo->regdump_len = 0;
        drvinfo->eedump_len = 0;
index b89c36d..c2df6c3 100644 (file)
@@ -581,6 +581,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
                 * Packet is OK - process it.
                 */
                length = be32_to_cpu(cqe->byte_cnt);
+               length -= ring->fcs_del;
                ring->bytes += length;
                ring->packets++;
 
@@ -813,8 +814,11 @@ static int mlx4_en_config_rss_qp(struct mlx4_en_priv *priv, int qpn,
        context->db_rec_addr = cpu_to_be64(ring->wqres.db.dma);
 
        /* Cancel FCS removal if FW allows */
-       if (mdev->dev->caps.flags & MLX4_DEV_CAP_FLAG_FCS_KEEP)
+       if (mdev->dev->caps.flags & MLX4_DEV_CAP_FLAG_FCS_KEEP) {
                context->param3 |= cpu_to_be32(1 << 29);
+               ring->fcs_del = ETH_FCS_LEN;
+       } else
+               ring->fcs_del = 0;
 
        err = mlx4_qp_to_ready(mdev->dev, &ring->wqres.mtt, context, qp, state);
        if (err) {
index 8fda331..207b5ad 100644 (file)
@@ -272,6 +272,7 @@ struct mlx4_en_rx_ring {
        u32 prod;
        u32 cons;
        u32 buf_size;
+       u8  fcs_del;
        void *buf;
        void *rx_info;
        unsigned long bytes;
index d19c849..228c5c0 100644 (file)
@@ -1500,8 +1500,7 @@ static int ks_hw_init(struct ks_net *ks)
        ks->all_mcast = 0;
        ks->mcast_lst_size = 0;
 
-       ks->frame_head_info = (struct type_frame_head *) \
-               kmalloc(MHEADER_SIZE, GFP_KERNEL);
+       ks->frame_head_info = kmalloc(MHEADER_SIZE, GFP_KERNEL);
        if (!ks->frame_head_info) {
                pr_err("Error: Fail to allocate frame memory\n");
                return false;
index 7ece990..a718865 100644 (file)
 /* Change default LED mode. */
 #define SET_DEFAULT_LED                        LED_SPEED_DUPLEX_ACT
 
-#define MAC_ADDR_LEN                   6
-#define MAC_ADDR_ORDER(i)              (MAC_ADDR_LEN - 1 - (i))
+#define MAC_ADDR_ORDER(i)              (ETH_ALEN - 1 - (i))
 
 #define MAX_ETHERNET_BODY_SIZE         1500
 #define ETHERNET_HEADER_SIZE           14
@@ -1043,7 +1042,7 @@ enum {
  * @valid:     Valid setting indicating the entry is being used.
  */
 struct ksz_mac_table {
-       u8 mac_addr[MAC_ADDR_LEN];
+       u8 mac_addr[ETH_ALEN];
        u16 vid;
        u8 fid;
        u8 ports;
@@ -1187,8 +1186,8 @@ struct ksz_switch {
        u8 diffserv[DIFFSERV_ENTRIES];
        u8 p_802_1p[PRIO_802_1P_ENTRIES];
 
-       u8 br_addr[MAC_ADDR_LEN];
-       u8 other_addr[MAC_ADDR_LEN];
+       u8 br_addr[ETH_ALEN];
+       u8 other_addr[ETH_ALEN];
 
        u8 broad_per;
        u8 member;
@@ -1292,14 +1291,14 @@ struct ksz_hw {
        int tx_int_mask;
        int tx_size;
 
-       u8 perm_addr[MAC_ADDR_LEN];
-       u8 override_addr[MAC_ADDR_LEN];
-       u8 address[ADDITIONAL_ENTRIES][MAC_ADDR_LEN];
+       u8 perm_addr[ETH_ALEN];
+       u8 override_addr[ETH_ALEN];
+       u8 address[ADDITIONAL_ENTRIES][ETH_ALEN];
        u8 addr_list_size;
        u8 mac_override;
        u8 promiscuous;
        u8 all_multi;
-       u8 multi_list[MAX_MULTICAST_LIST][MAC_ADDR_LEN];
+       u8 multi_list[MAX_MULTICAST_LIST][ETH_ALEN];
        u8 multi_bits[HW_MULTICAST_SIZE];
        u8 multi_list_size;
 
@@ -3654,7 +3653,7 @@ static void hw_add_wol_bcast(struct ksz_hw *hw)
        static const u8 mask[] = { 0x3F };
        static const u8 pattern[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
 
-       hw_set_wol_frame(hw, 2, 1, mask, MAC_ADDR_LEN, pattern);
+       hw_set_wol_frame(hw, 2, 1, mask, ETH_ALEN, pattern);
 }
 
 /**
@@ -3689,7 +3688,7 @@ static void hw_add_wol_ucast(struct ksz_hw *hw)
 {
        static const u8 mask[] = { 0x3F };
 
-       hw_set_wol_frame(hw, 0, 1, mask, MAC_ADDR_LEN, hw->override_addr);
+       hw_set_wol_frame(hw, 0, 1, mask, ETH_ALEN, hw->override_addr);
 }
 
 /**
@@ -4055,7 +4054,7 @@ static void hw_set_addr(struct ksz_hw *hw)
 {
        int i;
 
-       for (i = 0; i < MAC_ADDR_LEN; i++)
+       for (i = 0; i < ETH_ALEN; i++)
                writeb(hw->override_addr[MAC_ADDR_ORDER(i)],
                        hw->io + KS884X_ADDR_0_OFFSET + i);
 
@@ -4072,17 +4071,16 @@ static void hw_read_addr(struct ksz_hw *hw)
 {
        int i;
 
-       for (i = 0; i < MAC_ADDR_LEN; i++)
+       for (i = 0; i < ETH_ALEN; i++)
                hw->perm_addr[MAC_ADDR_ORDER(i)] = readb(hw->io +
                        KS884X_ADDR_0_OFFSET + i);
 
        if (!hw->mac_override) {
-               memcpy(hw->override_addr, hw->perm_addr, MAC_ADDR_LEN);
+               memcpy(hw->override_addr, hw->perm_addr, ETH_ALEN);
                if (empty_addr(hw->override_addr)) {
-                       memcpy(hw->perm_addr, DEFAULT_MAC_ADDRESS,
-                               MAC_ADDR_LEN);
+                       memcpy(hw->perm_addr, DEFAULT_MAC_ADDRESS, ETH_ALEN);
                        memcpy(hw->override_addr, DEFAULT_MAC_ADDRESS,
-                               MAC_ADDR_LEN);
+                              ETH_ALEN);
                        hw->override_addr[5] += hw->id;
                        hw_set_addr(hw);
                }
@@ -4130,16 +4128,16 @@ static int hw_add_addr(struct ksz_hw *hw, u8 *mac_addr)
        int i;
        int j = ADDITIONAL_ENTRIES;
 
-       if (!memcmp(hw->override_addr, mac_addr, MAC_ADDR_LEN))
+       if (!memcmp(hw->override_addr, mac_addr, ETH_ALEN))
                return 0;
        for (i = 0; i < hw->addr_list_size; i++) {
-               if (!memcmp(hw->address[i], mac_addr, MAC_ADDR_LEN))
+               if (!memcmp(hw->address[i], mac_addr, ETH_ALEN))
                        return 0;
                if (ADDITIONAL_ENTRIES == j && empty_addr(hw->address[i]))
                        j = i;
        }
        if (j < ADDITIONAL_ENTRIES) {
-               memcpy(hw->address[j], mac_addr, MAC_ADDR_LEN);
+               memcpy(hw->address[j], mac_addr, ETH_ALEN);
                hw_ena_add_addr(hw, j, hw->address[j]);
                return 0;
        }
@@ -4151,8 +4149,8 @@ static int hw_del_addr(struct ksz_hw *hw, u8 *mac_addr)
        int i;
 
        for (i = 0; i < hw->addr_list_size; i++) {
-               if (!memcmp(hw->address[i], mac_addr, MAC_ADDR_LEN)) {
-                       memset(hw->address[i], 0, MAC_ADDR_LEN);
+               if (!memcmp(hw->address[i], mac_addr, ETH_ALEN)) {
+                       memset(hw->address[i], 0, ETH_ALEN);
                        writel(0, hw->io + ADD_ADDR_INCR * i +
                                KS_ADD_ADDR_0_HI);
                        return 0;
@@ -4382,12 +4380,10 @@ static void ksz_update_timer(struct ksz_timer_info *info)
  */
 static int ksz_alloc_soft_desc(struct ksz_desc_info *desc_info, int transmit)
 {
-       desc_info->ring = kmalloc(sizeof(struct ksz_desc) * desc_info->alloc,
-               GFP_KERNEL);
+       desc_info->ring = kzalloc(sizeof(struct ksz_desc) * desc_info->alloc,
+                                 GFP_KERNEL);
        if (!desc_info->ring)
                return 1;
-       memset((void *) desc_info->ring, 0,
-               sizeof(struct ksz_desc) * desc_info->alloc);
        hw_init_desc(desc_info, transmit);
        return 0;
 }
@@ -5676,7 +5672,7 @@ static int netdev_set_mac_address(struct net_device *dev, void *addr)
                hw_del_addr(hw, dev->dev_addr);
        else {
                hw->mac_override = 1;
-               memcpy(hw->override_addr, mac->sa_data, MAC_ADDR_LEN);
+               memcpy(hw->override_addr, mac->sa_data, ETH_ALEN);
        }
 
        memcpy(dev->dev_addr, mac->sa_data, MAX_ADDR_LEN);
@@ -5786,7 +5782,7 @@ static void netdev_set_rx_mode(struct net_device *dev)
                netdev_for_each_mc_addr(ha, dev) {
                        if (i >= MAX_MULTICAST_LIST)
                                break;
-                       memcpy(hw->multi_list[i++], ha->addr, MAC_ADDR_LEN);
+                       memcpy(hw->multi_list[i++], ha->addr, ETH_ALEN);
                }
                hw->multi_list_size = (u8) i;
                hw_set_grp_addr(hw);
@@ -6093,9 +6089,10 @@ static void netdev_get_drvinfo(struct net_device *dev,
        struct dev_priv *priv = netdev_priv(dev);
        struct dev_info *hw_priv = priv->adapter;
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, pci_name(hw_priv->pdev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(hw_priv->pdev),
+               sizeof(info->bus_info));
 }
 
 /**
@@ -6587,7 +6584,8 @@ static void netdev_get_ethtool_stats(struct net_device *dev,
  *
  * Return 0 if successful; otherwise an error code.
  */
-static int netdev_set_features(struct net_device *dev, u32 features)
+static int netdev_set_features(struct net_device *dev,
+       netdev_features_t features)
 {
        struct dev_priv *priv = netdev_priv(dev);
        struct dev_info *hw_priv = priv->adapter;
@@ -6860,7 +6858,7 @@ static void get_mac_addr(struct dev_info *hw_priv, u8 *macaddr, int port)
        int num;
 
        i = j = num = got_num = 0;
-       while (j < MAC_ADDR_LEN) {
+       while (j < ETH_ALEN) {
                if (macaddr[i]) {
                        int digit;
 
@@ -6891,7 +6889,7 @@ static void get_mac_addr(struct dev_info *hw_priv, u8 *macaddr, int port)
                }
                i++;
        }
-       if (MAC_ADDR_LEN == j) {
+       if (ETH_ALEN == j) {
                if (MAIN_PORT == port)
                        hw_priv->hw.mac_override = 1;
        }
@@ -7058,7 +7056,7 @@ static int __devinit pcidev_init(struct pci_dev *pdev,
 
        /* Multiple device interfaces mode requires a second MAC address. */
        if (hw->dev_count > 1) {
-               memcpy(sw->other_addr, hw->override_addr, MAC_ADDR_LEN);
+               memcpy(sw->other_addr, hw->override_addr, ETH_ALEN);
                read_other_addr(hw);
                if (mac1addr[0] != ':')
                        get_mac_addr(hw_priv, mac1addr, OTHER_PORT);
@@ -7108,12 +7106,11 @@ static int __devinit pcidev_init(struct pci_dev *pdev,
                dev->irq = pdev->irq;
                if (MAIN_PORT == i)
                        memcpy(dev->dev_addr, hw_priv->hw.override_addr,
-                               MAC_ADDR_LEN);
+                              ETH_ALEN);
                else {
-                       memcpy(dev->dev_addr, sw->other_addr,
-                               MAC_ADDR_LEN);
+                       memcpy(dev->dev_addr, sw->other_addr, ETH_ALEN);
                        if (!memcmp(sw->other_addr, hw->override_addr,
-                                       MAC_ADDR_LEN))
+                                   ETH_ALEN))
                                dev->dev_addr[5] += port->first_port;
                }
 
index 0778edc..20b72ec 100644 (file)
@@ -1491,7 +1491,7 @@ myri10ge_clean_rx_done(struct myri10ge_slice_state *ss, int budget)
         * access to avoid theoretical race condition with functions that
         * change NETIF_F_LRO flag at runtime.
         */
-       bool lro_enabled = ACCESS_ONCE(mgp->dev->features) & NETIF_F_LRO;
+       bool lro_enabled = !!(ACCESS_ONCE(mgp->dev->features) & NETIF_F_LRO);
 
        while (rx_done->entry[idx].length != 0 && work_done < budget) {
                length = ntohs(rx_done->entry[idx].length);
@@ -3149,7 +3149,8 @@ static int myri10ge_set_mac_address(struct net_device *dev, void *addr)
        return 0;
 }
 
-static u32 myri10ge_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t myri10ge_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        if (!(features & NETIF_F_RXCSUM))
                features &= ~NETIF_F_LRO;
index 6ca047a..ac7b16b 100644 (file)
@@ -2555,9 +2555,9 @@ static void set_rx_mode(struct net_device *dev)
 static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
        struct netdev_private *np = netdev_priv(dev);
-       strncpy(info->driver, DRV_NAME, ETHTOOL_BUSINFO_LEN);
-       strncpy(info->version, DRV_VERSION, ETHTOOL_BUSINFO_LEN);
-       strncpy(info->bus_info, pci_name(np->pci_dev), ETHTOOL_BUSINFO_LEN);
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(np->pci_dev), sizeof(info->bus_info));
 }
 
 static int get_regs_len(struct net_device *dev)
index 2b8f64d..c24b46c 100644 (file)
@@ -1364,9 +1364,9 @@ static int ns83820_set_settings(struct net_device *ndev,
 static void ns83820_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info)
 {
        struct ns83820 *dev = PRIV(ndev);
-       strcpy(info->driver, "ns83820");
-       strcpy(info->version, VERSION);
-       strcpy(info->bus_info, pci_name(dev->pci_dev));
+       strlcpy(info->driver, "ns83820", sizeof(info->driver));
+       strlcpy(info->version, VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(dev->pci_dev), sizeof(info->bus_info));
 }
 
 static u32 ns83820_get_link(struct net_device *ndev)
index c27fb3d..76ae476 100644 (file)
@@ -5391,10 +5391,10 @@ static void s2io_ethtool_gdrvinfo(struct net_device *dev,
 {
        struct s2io_nic *sp = netdev_priv(dev);
 
-       strncpy(info->driver, s2io_driver_name, sizeof(info->driver));
-       strncpy(info->version, s2io_driver_version, sizeof(info->version));
-       strncpy(info->fw_version, "", sizeof(info->fw_version));
-       strncpy(info->bus_info, pci_name(sp->pdev), sizeof(info->bus_info));
+       strlcpy(info->driver, s2io_driver_name, sizeof(info->driver));
+       strlcpy(info->version, s2io_driver_version, sizeof(info->version));
+       strlcpy(info->fw_version, "", sizeof(info->fw_version));
+       strlcpy(info->bus_info, pci_name(sp->pdev), sizeof(info->bus_info));
        info->regdump_len = XENA_REG_SPACE;
        info->eedump_len = XENA_EEPROM_SPACE;
 }
@@ -6616,10 +6616,10 @@ static void s2io_ethtool_get_strings(struct net_device *dev,
        }
 }
 
-static int s2io_set_features(struct net_device *dev, u32 features)
+static int s2io_set_features(struct net_device *dev, netdev_features_t features)
 {
        struct s2io_nic *sp = netdev_priv(dev);
-       u32 changed = (features ^ dev->features) & NETIF_F_LRO;
+       netdev_features_t changed = (features ^ dev->features) & NETIF_F_LRO;
 
        if (changed && netif_running(dev)) {
                int rc;
index a83197d..16d4d8e 100644 (file)
@@ -2662,9 +2662,10 @@ static void vxge_poll_vp_lockup(unsigned long data)
        mod_timer(&vdev->vp_lockup_timer, jiffies + HZ / 1000);
 }
 
-static u32 vxge_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t vxge_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
-       u32 changed = dev->features ^ features;
+       netdev_features_t changed = dev->features ^ features;
 
        /* Enabling RTH requires some of the logic in vxge_device_register and a
         * vpath reset.  Due to these restrictions, only allow modification
@@ -2676,10 +2677,10 @@ static u32 vxge_fix_features(struct net_device *dev, u32 features)
        return features;
 }
 
-static int vxge_set_features(struct net_device *dev, u32 features)
+static int vxge_set_features(struct net_device *dev, netdev_features_t features)
 {
        struct vxgedev *vdev = netdev_priv(dev);
-       u32 changed = dev->features ^ features;
+       netdev_features_t changed = dev->features ^ features;
 
        if (!(changed & NETIF_F_RXHASH))
                return 0;
index 1dca570..8db0b37 100644 (file)
@@ -65,7 +65,8 @@
 #include <linux/slab.h>
 #include <linux/uaccess.h>
 #include <linux/prefetch.h>
-#include  <linux/io.h>
+#include <linux/u64_stats_sync.h>
+#include <linux/io.h>
 
 #include <asm/irq.h>
 #include <asm/system.h>
@@ -609,7 +610,7 @@ struct nv_ethtool_str {
 };
 
 static const struct nv_ethtool_str nv_estats_str[] = {
-       { "tx_bytes" },
+       { "tx_bytes" }, /* includes Ethernet FCS CRC */
        { "tx_zero_rexmt" },
        { "tx_one_rexmt" },
        { "tx_many_rexmt" },
@@ -637,7 +638,7 @@ static const struct nv_ethtool_str nv_estats_str[] = {
        /* version 2 stats */
        { "tx_deferral" },
        { "tx_packets" },
-       { "rx_bytes" },
+       { "rx_bytes" }, /* includes Ethernet FCS CRC */
        { "tx_pause" },
        { "rx_pause" },
        { "rx_drop_frame" },
@@ -649,7 +650,7 @@ static const struct nv_ethtool_str nv_estats_str[] = {
 };
 
 struct nv_ethtool_stats {
-       u64 tx_bytes;
+       u64 tx_bytes; /* should be ifconfig->tx_bytes + 4*tx_packets */
        u64 tx_zero_rexmt;
        u64 tx_one_rexmt;
        u64 tx_many_rexmt;
@@ -670,14 +671,14 @@ struct nv_ethtool_stats {
        u64 rx_unicast;
        u64 rx_multicast;
        u64 rx_broadcast;
-       u64 rx_packets;
+       u64 rx_packets; /* should be ifconfig->rx_packets */
        u64 rx_errors_total;
        u64 tx_errors_total;
 
        /* version 2 stats */
        u64 tx_deferral;
-       u64 tx_packets;
-       u64 rx_bytes;
+       u64 tx_packets; /* should be ifconfig->tx_packets */
+       u64 rx_bytes;   /* should be ifconfig->rx_bytes + 4*rx_packets */
        u64 tx_pause;
        u64 rx_pause;
        u64 rx_drop_frame;
@@ -736,6 +737,16 @@ struct nv_skb_map {
  * - tx setup is lockless: it relies on netif_tx_lock. Actual submission
  *     needs netdev_priv(dev)->lock :-(
  * - set_multicast_list: preparation lockless, relies on netif_tx_lock.
+ *
+ * Hardware stats updates are protected by hwstats_lock:
+ * - updated by nv_do_stats_poll (timer). This is meant to avoid
+ *   integer wraparound in the NIC stats registers, at low frequency
+ *   (0.1 Hz)
+ * - updated by nv_get_ethtool_stats + nv_get_stats64
+ *
+ * Software stats are accessed only through 64b synchronization points
+ * and are not subject to other synchronization techniques (single
+ * update thread on the TX or RX paths).
  */
 
 /* in dev: base, irq */
@@ -745,9 +756,10 @@ struct fe_priv {
        struct net_device *dev;
        struct napi_struct napi;
 
-       /* General data:
-        * Locking: spin_lock(&np->lock); */
+       /* hardware stats are updated in syscall and timer */
+       spinlock_t hwstats_lock;
        struct nv_ethtool_stats estats;
+
        int in_shutdown;
        u32 linkspeed;
        int duplex;
@@ -798,6 +810,13 @@ struct fe_priv {
        u32 nic_poll_irq;
        int rx_ring_size;
 
+       /* RX software stats */
+       struct u64_stats_sync swstats_rx_syncp;
+       u64 stat_rx_packets;
+       u64 stat_rx_bytes; /* not always available in HW */
+       u64 stat_rx_missed_errors;
+       u64 stat_rx_dropped;
+
        /* media detection workaround.
         * Locking: Within irq hander or disable_irq+spin_lock(&np->lock);
         */
@@ -820,6 +839,12 @@ struct fe_priv {
        struct nv_skb_map *tx_end_flip;
        int tx_stop;
 
+       /* TX software stats */
+       struct u64_stats_sync swstats_tx_syncp;
+       u64 stat_tx_packets; /* not always available in HW */
+       u64 stat_tx_bytes;
+       u64 stat_tx_dropped;
+
        /* msi/msi-x fields */
        u32 msi_flags;
        struct msix_entry msi_x_entry[NV_MSI_X_MAX_VECTORS];
@@ -892,6 +917,11 @@ enum {
 static int dma_64bit = NV_DMA_64BIT_ENABLED;
 
 /*
+ * Debug output control for tx_timeout
+ */
+static bool debug_tx_timeout = false;
+
+/*
  * Crossover Detection
  * Realtek 8201 phy + some OEM boards do not work properly.
  */
@@ -1630,11 +1660,19 @@ static void nv_mac_reset(struct net_device *dev)
        pci_push(base);
 }
 
-static void nv_get_hw_stats(struct net_device *dev)
+/* Caller must appropriately lock netdev_priv(dev)->hwstats_lock */
+static void nv_update_stats(struct net_device *dev)
 {
        struct fe_priv *np = netdev_priv(dev);
        u8 __iomem *base = get_hwbase(dev);
 
+       /* If it happens that this is run in top-half context, then
+        * replace the spin_lock of hwstats_lock with
+        * spin_lock_irqsave() in calling functions. */
+       WARN_ONCE(in_irq(), "forcedeth: estats spin_lock(_bh) from top-half");
+       assert_spin_locked(&np->hwstats_lock);
+
+       /* query hardware */
        np->estats.tx_bytes += readl(base + NvRegTxCnt);
        np->estats.tx_zero_rexmt += readl(base + NvRegTxZeroReXmt);
        np->estats.tx_one_rexmt += readl(base + NvRegTxOneReXmt);
@@ -1693,33 +1731,73 @@ static void nv_get_hw_stats(struct net_device *dev)
 }
 
 /*
- * nv_get_stats: dev->get_stats function
+ * nv_get_stats64: dev->ndo_get_stats64 function
  * Get latest stats value from the nic.
  * Called with read_lock(&dev_base_lock) held for read -
  * only synchronized against unregister_netdevice.
  */
-static struct net_device_stats *nv_get_stats(struct net_device *dev)
+static struct rtnl_link_stats64*
+nv_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *storage)
+       __acquires(&netdev_priv(dev)->hwstats_lock)
+       __releases(&netdev_priv(dev)->hwstats_lock)
 {
        struct fe_priv *np = netdev_priv(dev);
+       unsigned int syncp_start;
+
+       /*
+        * Note: because HW stats are not always available and for
+        * consistency reasons, the following ifconfig stats are
+        * managed by software: rx_bytes, tx_bytes, rx_packets and
+        * tx_packets. The related hardware stats reported by ethtool
+        * should be equivalent to these ifconfig stats, with 4
+        * additional bytes per packet (Ethernet FCS CRC), except for
+        * tx_packets when TSO kicks in.
+        */
+
+       /* software stats */
+       do {
+               syncp_start = u64_stats_fetch_begin_bh(&np->swstats_rx_syncp);
+               storage->rx_packets       = np->stat_rx_packets;
+               storage->rx_bytes         = np->stat_rx_bytes;
+               storage->rx_dropped       = np->stat_rx_dropped;
+               storage->rx_missed_errors = np->stat_rx_missed_errors;
+       } while (u64_stats_fetch_retry_bh(&np->swstats_rx_syncp, syncp_start));
+
+       do {
+               syncp_start = u64_stats_fetch_begin_bh(&np->swstats_tx_syncp);
+               storage->tx_packets = np->stat_tx_packets;
+               storage->tx_bytes   = np->stat_tx_bytes;
+               storage->tx_dropped = np->stat_tx_dropped;
+       } while (u64_stats_fetch_retry_bh(&np->swstats_tx_syncp, syncp_start));
 
        /* If the nic supports hw counters then retrieve latest values */
-       if (np->driver_data & (DEV_HAS_STATISTICS_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_STATISTICS_V3)) {
-               nv_get_hw_stats(dev);
-
-               /* copy to net_device stats */
-               dev->stats.tx_packets = np->estats.tx_packets;
-               dev->stats.rx_bytes = np->estats.rx_bytes;
-               dev->stats.tx_bytes = np->estats.tx_bytes;
-               dev->stats.tx_fifo_errors = np->estats.tx_fifo_errors;
-               dev->stats.tx_carrier_errors = np->estats.tx_carrier_errors;
-               dev->stats.rx_crc_errors = np->estats.rx_crc_errors;
-               dev->stats.rx_over_errors = np->estats.rx_over_errors;
-               dev->stats.rx_fifo_errors = np->estats.rx_drop_frame;
-               dev->stats.rx_errors = np->estats.rx_errors_total;
-               dev->stats.tx_errors = np->estats.tx_errors_total;
-       }
-
-       return &dev->stats;
+       if (np->driver_data & DEV_HAS_STATISTICS_V123) {
+               spin_lock_bh(&np->hwstats_lock);
+
+               nv_update_stats(dev);
+
+               /* generic stats */
+               storage->rx_errors = np->estats.rx_errors_total;
+               storage->tx_errors = np->estats.tx_errors_total;
+
+               /* meaningful only when NIC supports stats v3 */
+               storage->multicast = np->estats.rx_multicast;
+
+               /* detailed rx_errors */
+               storage->rx_length_errors = np->estats.rx_length_error;
+               storage->rx_over_errors   = np->estats.rx_over_errors;
+               storage->rx_crc_errors    = np->estats.rx_crc_errors;
+               storage->rx_frame_errors  = np->estats.rx_frame_align_error;
+               storage->rx_fifo_errors   = np->estats.rx_drop_frame;
+
+               /* detailed tx_errors */
+               storage->tx_carrier_errors = np->estats.tx_carrier_errors;
+               storage->tx_fifo_errors    = np->estats.tx_fifo_errors;
+
+               spin_unlock_bh(&np->hwstats_lock);
+       }
+
+       return storage;
 }
 
 /*
@@ -1752,8 +1830,12 @@ static int nv_alloc_rx(struct net_device *dev)
                                np->put_rx.orig = np->first_rx.orig;
                        if (unlikely(np->put_rx_ctx++ == np->last_rx_ctx))
                                np->put_rx_ctx = np->first_rx_ctx;
-               } else
+               } else {
+                       u64_stats_update_begin(&np->swstats_rx_syncp);
+                       np->stat_rx_dropped++;
+                       u64_stats_update_end(&np->swstats_rx_syncp);
                        return 1;
+               }
        }
        return 0;
 }
@@ -1784,8 +1866,12 @@ static int nv_alloc_rx_optimized(struct net_device *dev)
                                np->put_rx.ex = np->first_rx.ex;
                        if (unlikely(np->put_rx_ctx++ == np->last_rx_ctx))
                                np->put_rx_ctx = np->first_rx_ctx;
-               } else
+               } else {
+                       u64_stats_update_begin(&np->swstats_rx_syncp);
+                       np->stat_rx_dropped++;
+                       u64_stats_update_end(&np->swstats_rx_syncp);
                        return 1;
+               }
        }
        return 0;
 }
@@ -1920,8 +2006,11 @@ static void nv_drain_tx(struct net_device *dev)
                        np->tx_ring.ex[i].bufhigh = 0;
                        np->tx_ring.ex[i].buflow = 0;
                }
-               if (nv_release_txskb(np, &np->tx_skb[i]))
-                       dev->stats.tx_dropped++;
+               if (nv_release_txskb(np, &np->tx_skb[i])) {
+                       u64_stats_update_begin(&np->swstats_tx_syncp);
+                       np->stat_tx_dropped++;
+                       u64_stats_update_end(&np->swstats_tx_syncp);
+               }
                np->tx_skb[i].dma = 0;
                np->tx_skb[i].dma_len = 0;
                np->tx_skb[i].dma_single = 0;
@@ -2378,8 +2467,14 @@ static int nv_tx_done(struct net_device *dev, int limit)
                if (np->desc_ver == DESC_VER_1) {
                        if (flags & NV_TX_LASTPACKET) {
                                if (flags & NV_TX_ERROR) {
-                                       if ((flags & NV_TX_RETRYERROR) && !(flags & NV_TX_RETRYCOUNT_MASK))
+                                       if ((flags & NV_TX_RETRYERROR)
+                                           && !(flags & NV_TX_RETRYCOUNT_MASK))
                                                nv_legacybackoff_reseed(dev);
+                               } else {
+                                       u64_stats_update_begin(&np->swstats_tx_syncp);
+                                       np->stat_tx_packets++;
+                                       np->stat_tx_bytes += np->get_tx_ctx->skb->len;
+                                       u64_stats_update_end(&np->swstats_tx_syncp);
                                }
                                dev_kfree_skb_any(np->get_tx_ctx->skb);
                                np->get_tx_ctx->skb = NULL;
@@ -2388,8 +2483,14 @@ static int nv_tx_done(struct net_device *dev, int limit)
                } else {
                        if (flags & NV_TX2_LASTPACKET) {
                                if (flags & NV_TX2_ERROR) {
-                                       if ((flags & NV_TX2_RETRYERROR) && !(flags & NV_TX2_RETRYCOUNT_MASK))
+                                       if ((flags & NV_TX2_RETRYERROR)
+                                           && !(flags & NV_TX2_RETRYCOUNT_MASK))
                                                nv_legacybackoff_reseed(dev);
+                               } else {
+                                       u64_stats_update_begin(&np->swstats_tx_syncp);
+                                       np->stat_tx_packets++;
+                                       np->stat_tx_bytes += np->get_tx_ctx->skb->len;
+                                       u64_stats_update_end(&np->swstats_tx_syncp);
                                }
                                dev_kfree_skb_any(np->get_tx_ctx->skb);
                                np->get_tx_ctx->skb = NULL;
@@ -2423,12 +2524,18 @@ static int nv_tx_done_optimized(struct net_device *dev, int limit)
 
                if (flags & NV_TX2_LASTPACKET) {
                        if (flags & NV_TX2_ERROR) {
-                               if ((flags & NV_TX2_RETRYERROR) && !(flags & NV_TX2_RETRYCOUNT_MASK)) {
+                               if ((flags & NV_TX2_RETRYERROR)
+                                   && !(flags & NV_TX2_RETRYCOUNT_MASK)) {
                                        if (np->driver_data & DEV_HAS_GEAR_MODE)
                                                nv_gear_backoff_reseed(dev);
                                        else
                                                nv_legacybackoff_reseed(dev);
                                }
+                       } else {
+                               u64_stats_update_begin(&np->swstats_tx_syncp);
+                               np->stat_tx_packets++;
+                               np->stat_tx_bytes += np->get_tx_ctx->skb->len;
+                               u64_stats_update_end(&np->swstats_tx_syncp);
                        }
 
                        dev_kfree_skb_any(np->get_tx_ctx->skb);
@@ -2461,56 +2568,64 @@ static void nv_tx_timeout(struct net_device *dev)
        u32 status;
        union ring_type put_tx;
        int saved_tx_limit;
-       int i;
 
        if (np->msi_flags & NV_MSI_X_ENABLED)
                status = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK;
        else
                status = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK;
 
-       netdev_info(dev, "Got tx_timeout. irq: %08x\n", status);
+       netdev_warn(dev, "Got tx_timeout. irq status: %08x\n", status);
 
-       netdev_info(dev, "Ring at %lx\n", (unsigned long)np->ring_addr);
-       netdev_info(dev, "Dumping tx registers\n");
-       for (i = 0; i <= np->register_size; i += 32) {
-               netdev_info(dev,
-                           "%3x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
-                           i,
-                           readl(base + i + 0), readl(base + i + 4),
-                           readl(base + i + 8), readl(base + i + 12),
-                           readl(base + i + 16), readl(base + i + 20),
-                           readl(base + i + 24), readl(base + i + 28));
-       }
-       netdev_info(dev, "Dumping tx ring\n");
-       for (i = 0; i < np->tx_ring_size; i += 4) {
-               if (!nv_optimized(np)) {
-                       netdev_info(dev,
-                                   "%03x: %08x %08x // %08x %08x // %08x %08x // %08x %08x\n",
-                                   i,
-                                   le32_to_cpu(np->tx_ring.orig[i].buf),
-                                   le32_to_cpu(np->tx_ring.orig[i].flaglen),
-                                   le32_to_cpu(np->tx_ring.orig[i+1].buf),
-                                   le32_to_cpu(np->tx_ring.orig[i+1].flaglen),
-                                   le32_to_cpu(np->tx_ring.orig[i+2].buf),
-                                   le32_to_cpu(np->tx_ring.orig[i+2].flaglen),
-                                   le32_to_cpu(np->tx_ring.orig[i+3].buf),
-                                   le32_to_cpu(np->tx_ring.orig[i+3].flaglen));
-               } else {
+       if (unlikely(debug_tx_timeout)) {
+               int i;
+
+               netdev_info(dev, "Ring at %lx\n", (unsigned long)np->ring_addr);
+               netdev_info(dev, "Dumping tx registers\n");
+               for (i = 0; i <= np->register_size; i += 32) {
                        netdev_info(dev,
-                                   "%03x: %08x %08x %08x // %08x %08x %08x // %08x %08x %08x // %08x %08x %08x\n",
+                                   "%3x: %08x %08x %08x %08x "
+                                   "%08x %08x %08x %08x\n",
                                    i,
-                                   le32_to_cpu(np->tx_ring.ex[i].bufhigh),
-                                   le32_to_cpu(np->tx_ring.ex[i].buflow),
-                                   le32_to_cpu(np->tx_ring.ex[i].flaglen),
-                                   le32_to_cpu(np->tx_ring.ex[i+1].bufhigh),
-                                   le32_to_cpu(np->tx_ring.ex[i+1].buflow),
-                                   le32_to_cpu(np->tx_ring.ex[i+1].flaglen),
-                                   le32_to_cpu(np->tx_ring.ex[i+2].bufhigh),
-                                   le32_to_cpu(np->tx_ring.ex[i+2].buflow),
-                                   le32_to_cpu(np->tx_ring.ex[i+2].flaglen),
-                                   le32_to_cpu(np->tx_ring.ex[i+3].bufhigh),
-                                   le32_to_cpu(np->tx_ring.ex[i+3].buflow),
-                                   le32_to_cpu(np->tx_ring.ex[i+3].flaglen));
+                                   readl(base + i + 0), readl(base + i + 4),
+                                   readl(base + i + 8), readl(base + i + 12),
+                                   readl(base + i + 16), readl(base + i + 20),
+                                   readl(base + i + 24), readl(base + i + 28));
+               }
+               netdev_info(dev, "Dumping tx ring\n");
+               for (i = 0; i < np->tx_ring_size; i += 4) {
+                       if (!nv_optimized(np)) {
+                               netdev_info(dev,
+                                           "%03x: %08x %08x // %08x %08x "
+                                           "// %08x %08x // %08x %08x\n",
+                                           i,
+                                           le32_to_cpu(np->tx_ring.orig[i].buf),
+                                           le32_to_cpu(np->tx_ring.orig[i].flaglen),
+                                           le32_to_cpu(np->tx_ring.orig[i+1].buf),
+                                           le32_to_cpu(np->tx_ring.orig[i+1].flaglen),
+                                           le32_to_cpu(np->tx_ring.orig[i+2].buf),
+                                           le32_to_cpu(np->tx_ring.orig[i+2].flaglen),
+                                           le32_to_cpu(np->tx_ring.orig[i+3].buf),
+                                           le32_to_cpu(np->tx_ring.orig[i+3].flaglen));
+                       } else {
+                               netdev_info(dev,
+                                           "%03x: %08x %08x %08x "
+                                           "// %08x %08x %08x "
+                                           "// %08x %08x %08x "
+                                           "// %08x %08x %08x\n",
+                                           i,
+                                           le32_to_cpu(np->tx_ring.ex[i].bufhigh),
+                                           le32_to_cpu(np->tx_ring.ex[i].buflow),
+                                           le32_to_cpu(np->tx_ring.ex[i].flaglen),
+                                           le32_to_cpu(np->tx_ring.ex[i+1].bufhigh),
+                                           le32_to_cpu(np->tx_ring.ex[i+1].buflow),
+                                           le32_to_cpu(np->tx_ring.ex[i+1].flaglen),
+                                           le32_to_cpu(np->tx_ring.ex[i+2].bufhigh),
+                                           le32_to_cpu(np->tx_ring.ex[i+2].buflow),
+                                           le32_to_cpu(np->tx_ring.ex[i+2].flaglen),
+                                           le32_to_cpu(np->tx_ring.ex[i+3].bufhigh),
+                                           le32_to_cpu(np->tx_ring.ex[i+3].buflow),
+                                           le32_to_cpu(np->tx_ring.ex[i+3].flaglen));
+                       }
                }
        }
 
@@ -2633,8 +2748,11 @@ static int nv_rx_process(struct net_device *dev, int limit)
                                        }
                                        /* the rest are hard errors */
                                        else {
-                                               if (flags & NV_RX_MISSEDFRAME)
-                                                       dev->stats.rx_missed_errors++;
+                                               if (flags & NV_RX_MISSEDFRAME) {
+                                                       u64_stats_update_begin(&np->swstats_rx_syncp);
+                                                       np->stat_rx_missed_errors++;
+                                                       u64_stats_update_end(&np->swstats_rx_syncp);
+                                               }
                                                dev_kfree_skb(skb);
                                                goto next_pkt;
                                        }
@@ -2677,7 +2795,10 @@ static int nv_rx_process(struct net_device *dev, int limit)
                skb_put(skb, len);
                skb->protocol = eth_type_trans(skb, dev);
                napi_gro_receive(&np->napi, skb);
-               dev->stats.rx_packets++;
+               u64_stats_update_begin(&np->swstats_rx_syncp);
+               np->stat_rx_packets++;
+               np->stat_rx_bytes += len;
+               u64_stats_update_end(&np->swstats_rx_syncp);
 next_pkt:
                if (unlikely(np->get_rx.orig++ == np->last_rx.orig))
                        np->get_rx.orig = np->first_rx.orig;
@@ -2760,7 +2881,10 @@ static int nv_rx_process_optimized(struct net_device *dev, int limit)
                                __vlan_hwaccel_put_tag(skb, vid);
                        }
                        napi_gro_receive(&np->napi, skb);
-                       dev->stats.rx_packets++;
+                       u64_stats_update_begin(&np->swstats_rx_syncp);
+                       np->stat_rx_packets++;
+                       np->stat_rx_bytes += len;
+                       u64_stats_update_end(&np->swstats_rx_syncp);
                } else {
                        dev_kfree_skb(skb);
                }
@@ -3003,6 +3127,73 @@ static void nv_update_pause(struct net_device *dev, u32 pause_flags)
        }
 }
 
+static void nv_force_linkspeed(struct net_device *dev, int speed, int duplex)
+{
+       struct fe_priv *np = netdev_priv(dev);
+       u8 __iomem *base = get_hwbase(dev);
+       u32 phyreg, txreg;
+       int mii_status;
+
+       np->linkspeed = NVREG_LINKSPEED_FORCE|speed;
+       np->duplex = duplex;
+
+       /* see if gigabit phy */
+       mii_status = mii_rw(dev, np->phyaddr, MII_BMSR, MII_READ);
+       if (mii_status & PHY_GIGABIT) {
+               np->gigabit = PHY_GIGABIT;
+               phyreg = readl(base + NvRegSlotTime);
+               phyreg &= ~(0x3FF00);
+               if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_10)
+                       phyreg |= NVREG_SLOTTIME_10_100_FULL;
+               else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_100)
+                       phyreg |= NVREG_SLOTTIME_10_100_FULL;
+               else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_1000)
+                       phyreg |= NVREG_SLOTTIME_1000_FULL;
+               writel(phyreg, base + NvRegSlotTime);
+       }
+
+       phyreg = readl(base + NvRegPhyInterface);
+       phyreg &= ~(PHY_HALF|PHY_100|PHY_1000);
+       if (np->duplex == 0)
+               phyreg |= PHY_HALF;
+       if ((np->linkspeed & NVREG_LINKSPEED_MASK) == NVREG_LINKSPEED_100)
+               phyreg |= PHY_100;
+       else if ((np->linkspeed & NVREG_LINKSPEED_MASK) ==
+                                                       NVREG_LINKSPEED_1000)
+               phyreg |= PHY_1000;
+       writel(phyreg, base + NvRegPhyInterface);
+
+       if (phyreg & PHY_RGMII) {
+               if ((np->linkspeed & NVREG_LINKSPEED_MASK) ==
+                                                       NVREG_LINKSPEED_1000)
+                       txreg = NVREG_TX_DEFERRAL_RGMII_1000;
+               else
+                       txreg = NVREG_TX_DEFERRAL_RGMII_10_100;
+       } else {
+               txreg = NVREG_TX_DEFERRAL_DEFAULT;
+       }
+       writel(txreg, base + NvRegTxDeferral);
+
+       if (np->desc_ver == DESC_VER_1) {
+               txreg = NVREG_TX_WM_DESC1_DEFAULT;
+       } else {
+               if ((np->linkspeed & NVREG_LINKSPEED_MASK) ==
+                                        NVREG_LINKSPEED_1000)
+                       txreg = NVREG_TX_WM_DESC2_3_1000;
+               else
+                       txreg = NVREG_TX_WM_DESC2_3_DEFAULT;
+       }
+       writel(txreg, base + NvRegTxWatermark);
+
+       writel(NVREG_MISC1_FORCE | (np->duplex ? 0 : NVREG_MISC1_HD),
+                       base + NvRegMisc1);
+       pci_push(base);
+       writel(np->linkspeed, base + NvRegLinkSpeed);
+       pci_push(base);
+
+       return;
+}
+
 /**
  * nv_update_linkspeed: Setup the MAC according to the link partner
  * @dev: Network device to be configured
@@ -3024,11 +3215,25 @@ static int nv_update_linkspeed(struct net_device *dev)
        int newls = np->linkspeed;
        int newdup = np->duplex;
        int mii_status;
+       u32 bmcr;
        int retval = 0;
        u32 control_1000, status_1000, phyreg, pause_flags, txreg;
        u32 txrxFlags = 0;
        u32 phy_exp;
 
+       /* If device loopback is enabled, set carrier on and enable max link
+        * speed.
+        */
+       bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
+       if (bmcr & BMCR_LOOPBACK) {
+               if (netif_running(dev)) {
+                       nv_force_linkspeed(dev, NVREG_LINKSPEED_1000, 1);
+                       if (!netif_carrier_ok(dev))
+                               netif_carrier_on(dev);
+               }
+               return 1;
+       }
+
        /* BMSR_LSTATUS is latched, read it twice:
         * we want the current value.
         */
@@ -3711,6 +3916,7 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
                                writel(0, base + NvRegMSIXMap0);
                                writel(0, base + NvRegMSIXMap1);
                        }
+                       netdev_info(dev, "MSI-X enabled\n");
                }
        }
        if (ret != 0 && np->msi_flags & NV_MSI_CAPABLE) {
@@ -3732,6 +3938,7 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
                        writel(0, base + NvRegMSIMap1);
                        /* enable msi vector 0 */
                        writel(NVREG_MSI_VECTOR_0_ENABLED, base + NvRegMSIIrqMask);
+                       netdev_info(dev, "MSI enabled\n");
                }
        }
        if (ret != 0) {
@@ -3886,11 +4093,18 @@ static void nv_poll_controller(struct net_device *dev)
 #endif
 
 static void nv_do_stats_poll(unsigned long data)
+       __acquires(&netdev_priv(dev)->hwstats_lock)
+       __releases(&netdev_priv(dev)->hwstats_lock)
 {
        struct net_device *dev = (struct net_device *) data;
        struct fe_priv *np = netdev_priv(dev);
 
-       nv_get_hw_stats(dev);
+       /* If lock is currently taken, the stats are being refreshed
+        * and hence fresh enough */
+       if (spin_trylock(&np->hwstats_lock)) {
+               nv_update_stats(dev);
+               spin_unlock(&np->hwstats_lock);
+       }
 
        if (!np->in_shutdown)
                mod_timer(&np->stats_poll,
@@ -3900,9 +4114,9 @@ static void nv_do_stats_poll(unsigned long data)
 static void nv_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
        struct fe_priv *np = netdev_priv(dev);
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, FORCEDETH_VERSION);
-       strcpy(info->bus_info, pci_name(np->pci_dev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, FORCEDETH_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(np->pci_dev), sizeof(info->bus_info));
 }
 
 static void nv_get_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo)
@@ -4455,7 +4669,63 @@ static int nv_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam*
        return 0;
 }
 
-static u32 nv_fix_features(struct net_device *dev, u32 features)
+static int nv_set_loopback(struct net_device *dev, netdev_features_t features)
+{
+       struct fe_priv *np = netdev_priv(dev);
+       unsigned long flags;
+       u32 miicontrol;
+       int err, retval = 0;
+
+       spin_lock_irqsave(&np->lock, flags);
+       miicontrol = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
+       if (features & NETIF_F_LOOPBACK) {
+               if (miicontrol & BMCR_LOOPBACK) {
+                       spin_unlock_irqrestore(&np->lock, flags);
+                       netdev_info(dev, "Loopback already enabled\n");
+                       return 0;
+               }
+               nv_disable_irq(dev);
+               /* Turn on loopback mode */
+               miicontrol |= BMCR_LOOPBACK | BMCR_FULLDPLX | BMCR_SPEED1000;
+               err = mii_rw(dev, np->phyaddr, MII_BMCR, miicontrol);
+               if (err) {
+                       retval = PHY_ERROR;
+                       spin_unlock_irqrestore(&np->lock, flags);
+                       phy_init(dev);
+               } else {
+                       if (netif_running(dev)) {
+                               /* Force 1000 Mbps full-duplex */
+                               nv_force_linkspeed(dev, NVREG_LINKSPEED_1000,
+                                                                        1);
+                               /* Force link up */
+                               netif_carrier_on(dev);
+                       }
+                       spin_unlock_irqrestore(&np->lock, flags);
+                       netdev_info(dev,
+                               "Internal PHY loopback mode enabled.\n");
+               }
+       } else {
+               if (!(miicontrol & BMCR_LOOPBACK)) {
+                       spin_unlock_irqrestore(&np->lock, flags);
+                       netdev_info(dev, "Loopback already disabled\n");
+                       return 0;
+               }
+               nv_disable_irq(dev);
+               /* Turn off loopback */
+               spin_unlock_irqrestore(&np->lock, flags);
+               netdev_info(dev, "Internal PHY loopback mode disabled.\n");
+               phy_init(dev);
+       }
+       msleep(500);
+       spin_lock_irqsave(&np->lock, flags);
+       nv_enable_irq(dev);
+       spin_unlock_irqrestore(&np->lock, flags);
+
+       return retval;
+}
+
+static netdev_features_t nv_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        /* vlan is dependent on rx checksum offload */
        if (features & (NETIF_F_HW_VLAN_TX|NETIF_F_HW_VLAN_RX))
@@ -4464,7 +4734,7 @@ static u32 nv_fix_features(struct net_device *dev, u32 features)
        return features;
 }
 
-static void nv_vlan_mode(struct net_device *dev, u32 features)
+static void nv_vlan_mode(struct net_device *dev, netdev_features_t features)
 {
        struct fe_priv *np = get_nvpriv(dev);
 
@@ -4485,11 +4755,18 @@ static void nv_vlan_mode(struct net_device *dev, u32 features)
        spin_unlock_irq(&np->lock);
 }
 
-static int nv_set_features(struct net_device *dev, u32 features)
+static int nv_set_features(struct net_device *dev, netdev_features_t features)
 {
        struct fe_priv *np = netdev_priv(dev);
        u8 __iomem *base = get_hwbase(dev);
-       u32 changed = dev->features ^ features;
+       netdev_features_t changed = dev->features ^ features;
+       int retval;
+
+       if ((changed & NETIF_F_LOOPBACK) && netif_running(dev)) {
+               retval = nv_set_loopback(dev, features);
+               if (retval != 0)
+                       return retval;
+       }
 
        if (changed & NETIF_F_RXCSUM) {
                spin_lock_irq(&np->lock);
@@ -4535,14 +4812,18 @@ static int nv_get_sset_count(struct net_device *dev, int sset)
        }
 }
 
-static void nv_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *estats, u64 *buffer)
+static void nv_get_ethtool_stats(struct net_device *dev,
+                                struct ethtool_stats *estats, u64 *buffer)
+       __acquires(&netdev_priv(dev)->hwstats_lock)
+       __releases(&netdev_priv(dev)->hwstats_lock)
 {
        struct fe_priv *np = netdev_priv(dev);
 
-       /* update stats */
-       nv_get_hw_stats(dev);
-
-       memcpy(buffer, &np->estats, nv_get_sset_count(dev, ETH_SS_STATS)*sizeof(u64));
+       spin_lock_bh(&np->hwstats_lock);
+       nv_update_stats(dev);
+       memcpy(buffer, &np->estats,
+              nv_get_sset_count(dev, ETH_SS_STATS)*sizeof(u64));
+       spin_unlock_bh(&np->hwstats_lock);
 }
 
 static int nv_link_test(struct net_device *dev)
@@ -5124,6 +5405,12 @@ static int nv_open(struct net_device *dev)
 
        spin_unlock_irq(&np->lock);
 
+       /* If the loopback feature was set while the device was down, make sure
+        * that it's set correctly now.
+        */
+       if (dev->features & NETIF_F_LOOPBACK)
+               nv_set_loopback(dev, dev->features);
+
        return 0;
 out_drain:
        nv_drain_rxtx(dev);
@@ -5180,7 +5467,7 @@ static int nv_close(struct net_device *dev)
 static const struct net_device_ops nv_netdev_ops = {
        .ndo_open               = nv_open,
        .ndo_stop               = nv_close,
-       .ndo_get_stats          = nv_get_stats,
+       .ndo_get_stats64        = nv_get_stats64,
        .ndo_start_xmit         = nv_start_xmit,
        .ndo_tx_timeout         = nv_tx_timeout,
        .ndo_change_mtu         = nv_change_mtu,
@@ -5197,7 +5484,7 @@ static const struct net_device_ops nv_netdev_ops = {
 static const struct net_device_ops nv_netdev_ops_optimized = {
        .ndo_open               = nv_open,
        .ndo_stop               = nv_close,
-       .ndo_get_stats          = nv_get_stats,
+       .ndo_get_stats64        = nv_get_stats64,
        .ndo_start_xmit         = nv_start_xmit_optimized,
        .ndo_tx_timeout         = nv_tx_timeout,
        .ndo_change_mtu         = nv_change_mtu,
@@ -5236,6 +5523,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
        np->dev = dev;
        np->pci_dev = pci_dev;
        spin_lock_init(&np->lock);
+       spin_lock_init(&np->hwstats_lock);
        SET_NETDEV_DEV(dev, &pci_dev->dev);
 
        init_timer(&np->oom_kick);
@@ -5244,7 +5532,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
        init_timer(&np->nic_poll);
        np->nic_poll.data = (unsigned long) dev;
        np->nic_poll.function = nv_do_nic_poll; /* timer handler */
-       init_timer(&np->stats_poll);
+       init_timer_deferrable(&np->stats_poll);
        np->stats_poll.data = (unsigned long) dev;
        np->stats_poll.function = nv_do_stats_poll;     /* timer handler */
 
@@ -5328,6 +5616,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
 
        dev->features |= dev->hw_features;
 
+       /* Add loopback capability to the device. */
+       dev->hw_features |= NETIF_F_LOOPBACK;
+
        np->pause_flags = NV_PAUSEFRAME_RX_CAPABLE | NV_PAUSEFRAME_RX_REQ | NV_PAUSEFRAME_AUTONEG;
        if ((id->driver_data & DEV_HAS_PAUSEFRAME_TX_V1) ||
            (id->driver_data & DEV_HAS_PAUSEFRAME_TX_V2) ||
@@ -5603,12 +5894,14 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
        dev_info(&pci_dev->dev, "ifname %s, PHY OUI 0x%x @ %d, addr %pM\n",
                 dev->name, np->phy_oui, np->phyaddr, dev->dev_addr);
 
-       dev_info(&pci_dev->dev, "%s%s%s%s%s%s%s%s%s%sdesc-v%u\n",
+       dev_info(&pci_dev->dev, "%s%s%s%s%s%s%s%s%s%s%sdesc-v%u\n",
                 dev->features & NETIF_F_HIGHDMA ? "highdma " : "",
                 dev->features & (NETIF_F_IP_CSUM | NETIF_F_SG) ?
                        "csum " : "",
                 dev->features & (NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX) ?
                        "vlan " : "",
+                dev->features & (NETIF_F_LOOPBACK) ?
+                       "loopback " : "",
                 id->driver_data & DEV_HAS_POWER_CNTRL ? "pwrctl " : "",
                 id->driver_data & DEV_HAS_MGMT_UNIT ? "mgmt " : "",
                 id->driver_data & DEV_NEED_TIMERIRQ ? "timirq " : "",
@@ -5982,6 +6275,9 @@ module_param(phy_cross, int, 0);
 MODULE_PARM_DESC(phy_cross, "Phy crossover detection for Realtek 8201 phy is enabled by setting to 1 and disabled by setting to 0.");
 module_param(phy_power_down, int, 0);
 MODULE_PARM_DESC(phy_power_down, "Power down phy and disable link when interface is down (1), or leave phy powered up (0).");
+module_param(debug_tx_timeout, bool, 0);
+MODULE_PARM_DESC(debug_tx_timeout,
+                "Dump tx related registers and ring when tx_timeout happens");
 
 MODULE_AUTHOR("Manfred Spraul <manfred@colorfullife.com>");
 MODULE_DESCRIPTION("Reverse Engineered nForce ethernet driver");
index 8c80271..ac4e72d 100644 (file)
@@ -161,10 +161,10 @@ static void pch_gbe_get_drvinfo(struct net_device *netdev,
 {
        struct pch_gbe_adapter *adapter = netdev_priv(netdev);
 
-       strcpy(drvinfo->driver, KBUILD_MODNAME);
-       strcpy(drvinfo->version, pch_driver_version);
-       strcpy(drvinfo->fw_version, "N/A");
-       strcpy(drvinfo->bus_info, pci_name(adapter->pdev));
+       strlcpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, pch_driver_version, sizeof(drvinfo->version));
+       strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
+               sizeof(drvinfo->bus_info));
        drvinfo->regdump_len = pch_gbe_get_regs_len(netdev);
 }
 
index 48406ca..964e9c0 100644 (file)
@@ -2109,10 +2109,11 @@ static int pch_gbe_change_mtu(struct net_device *netdev, int new_mtu)
  * Returns
  *     0:              HW state updated successfully
  */
-static int pch_gbe_set_features(struct net_device *netdev, u32 features)
+static int pch_gbe_set_features(struct net_device *netdev,
+       netdev_features_t features)
 {
        struct pch_gbe_adapter *adapter = netdev_priv(netdev);
-       u32 changed = features ^ netdev->features;
+       netdev_features_t changed = features ^ netdev->features;
 
        if (!(changed & NETIF_F_RXCSUM))
                return 0;
index 9c075ea..9cb5f91 100644 (file)
@@ -18,8 +18,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
  */
 
-#include <linux/module.h>      /* for __MODULE_STRING */
 #include "pch_gbe.h"
+#include <linux/module.h>      /* for __MODULE_STRING */
 
 #define OPTION_UNSET   -1
 #define OPTION_DISABLED 0
index e09ea83..8a37198 100644 (file)
@@ -83,14 +83,18 @@ netxen_nic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
        u32 fw_minor = 0;
        u32 fw_build = 0;
 
-       strncpy(drvinfo->driver, netxen_nic_driver_name, 32);
-       strncpy(drvinfo->version, NETXEN_NIC_LINUX_VERSIONID, 32);
+       strlcpy(drvinfo->driver, netxen_nic_driver_name,
+               sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, NETXEN_NIC_LINUX_VERSIONID,
+               sizeof(drvinfo->version));
        fw_major = NXRD32(adapter, NETXEN_FW_VERSION_MAJOR);
        fw_minor = NXRD32(adapter, NETXEN_FW_VERSION_MINOR);
        fw_build = NXRD32(adapter, NETXEN_FW_VERSION_SUB);
-       sprintf(drvinfo->fw_version, "%d.%d.%d", fw_major, fw_minor, fw_build);
+       snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
+               "%d.%d.%d", fw_major, fw_minor, fw_build);
 
-       strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
+       strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
+               sizeof(drvinfo->bus_info));
        drvinfo->regdump_len = NETXEN_NIC_REGS_LEN;
        drvinfo->eedump_len = netxen_nic_get_eeprom_len(dev);
 }
index 8cf3173..7dd9a4b 100644 (file)
@@ -544,7 +544,8 @@ static void netxen_set_multicast_list(struct net_device *dev)
        adapter->set_multi(dev);
 }
 
-static u32 netxen_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t netxen_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        if (!(features & NETIF_F_RXCSUM)) {
                netdev_info(dev, "disabling LRO as RXCSUM is off\n");
@@ -555,7 +556,8 @@ static u32 netxen_fix_features(struct net_device *dev, u32 features)
        return features;
 }
 
-static int netxen_set_features(struct net_device *dev, u32 features)
+static int netxen_set_features(struct net_device *dev,
+       netdev_features_t features)
 {
        struct netxen_adapter *adapter = netdev_priv(dev);
        int hw_lro;
index a4bdff4..7931531 100644 (file)
@@ -1735,10 +1735,11 @@ static void ql_get_drvinfo(struct net_device *ndev,
                           struct ethtool_drvinfo *drvinfo)
 {
        struct ql3_adapter *qdev = netdev_priv(ndev);
-       strncpy(drvinfo->driver, ql3xxx_driver_name, 32);
-       strncpy(drvinfo->version, ql3xxx_driver_version, 32);
-       strncpy(drvinfo->fw_version, "N/A", 32);
-       strncpy(drvinfo->bus_info, pci_name(qdev->pdev), 32);
+       strlcpy(drvinfo->driver, ql3xxx_driver_name, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, ql3xxx_driver_version,
+               sizeof(drvinfo->version));
+       strlcpy(drvinfo->bus_info, pci_name(qdev->pdev),
+               sizeof(drvinfo->bus_info));
        drvinfo->regdump_len = 0;
        drvinfo->eedump_len = 0;
 }
index 7ed53db..60976fc 100644 (file)
@@ -1466,8 +1466,9 @@ void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup);
 
 int qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu);
 int qlcnic_change_mtu(struct net_device *netdev, int new_mtu);
-u32 qlcnic_fix_features(struct net_device *netdev, u32 features);
-int qlcnic_set_features(struct net_device *netdev, u32 features);
+netdev_features_t qlcnic_fix_features(struct net_device *netdev,
+       netdev_features_t features);
+int qlcnic_set_features(struct net_device *netdev, netdev_features_t features);
 int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable);
 int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable);
 int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter);
index 8aa1c6e..cc228cf 100644 (file)
@@ -140,11 +140,14 @@ qlcnic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
        fw_major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR);
        fw_minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR);
        fw_build = QLCRD32(adapter, QLCNIC_FW_VERSION_SUB);
-       sprintf(drvinfo->fw_version, "%d.%d.%d", fw_major, fw_minor, fw_build);
-
-       strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
-       strlcpy(drvinfo->driver, qlcnic_driver_name, 32);
-       strlcpy(drvinfo->version, QLCNIC_LINUX_VERSIONID, 32);
+       snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
+               "%d.%d.%d", fw_major, fw_minor, fw_build);
+
+       strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
+               sizeof(drvinfo->bus_info));
+       strlcpy(drvinfo->driver, qlcnic_driver_name, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, QLCNIC_LINUX_VERSIONID,
+               sizeof(drvinfo->version));
 }
 
 static int
index bcb81e4..b528e52 100644 (file)
@@ -817,12 +817,13 @@ int qlcnic_change_mtu(struct net_device *netdev, int mtu)
 }
 
 
-u32 qlcnic_fix_features(struct net_device *netdev, u32 features)
+netdev_features_t qlcnic_fix_features(struct net_device *netdev,
+       netdev_features_t features)
 {
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
 
        if ((adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
-               u32 changed = features ^ netdev->features;
+               netdev_features_t changed = features ^ netdev->features;
                features ^= changed & (NETIF_F_ALL_CSUM | NETIF_F_RXCSUM);
        }
 
@@ -833,10 +834,10 @@ u32 qlcnic_fix_features(struct net_device *netdev, u32 features)
 }
 
 
-int qlcnic_set_features(struct net_device *netdev, u32 features)
+int qlcnic_set_features(struct net_device *netdev, netdev_features_t features)
 {
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
-       u32 changed = netdev->features ^ features;
+       netdev_features_t changed = netdev->features ^ features;
        int hw_lro = (features & NETIF_F_LRO) ? QLCNIC_LRO_ENABLED : 0;
 
        if (!(changed & NETIF_F_LRO))
index 0bd1638..823f845 100644 (file)
@@ -792,7 +792,7 @@ qlcnic_set_netdev_features(struct qlcnic_adapter *adapter,
                struct qlcnic_esw_func_cfg *esw_cfg)
 {
        struct net_device *netdev = adapter->netdev;
-       unsigned long features, vlan_features;
+       netdev_features_t features, vlan_features;
 
        features = (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM |
                        NETIF_F_IPV6_CSUM | NETIF_F_GRO);
index 9b67bfe..8e2c2a7 100644 (file)
@@ -366,13 +366,16 @@ static void ql_get_drvinfo(struct net_device *ndev,
                           struct ethtool_drvinfo *drvinfo)
 {
        struct ql_adapter *qdev = netdev_priv(ndev);
-       strncpy(drvinfo->driver, qlge_driver_name, 32);
-       strncpy(drvinfo->version, qlge_driver_version, 32);
-       snprintf(drvinfo->fw_version, 32, "v%d.%d.%d",
+       strlcpy(drvinfo->driver, qlge_driver_name, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, qlge_driver_version,
+               sizeof(drvinfo->version));
+       snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
+                "v%d.%d.%d",
                 (qdev->fw_rev_id & 0x00ff0000) >> 16,
                 (qdev->fw_rev_id & 0x0000ff00) >> 8,
                 (qdev->fw_rev_id & 0x000000ff));
-       strncpy(drvinfo->bus_info, pci_name(qdev->pdev), 32);
+       strlcpy(drvinfo->bus_info, pci_name(qdev->pdev),
+               sizeof(drvinfo->bus_info));
        drvinfo->n_stats = 0;
        drvinfo->testinfo_len = 0;
        if (!test_bit(QL_FRC_COREDUMP, &qdev->flags))
index c92afcd..1ce4e08 100644 (file)
@@ -2307,7 +2307,7 @@ static int ql_napi_poll_msix(struct napi_struct *napi, int budget)
        return work_done;
 }
 
-static void qlge_vlan_mode(struct net_device *ndev, u32 features)
+static void qlge_vlan_mode(struct net_device *ndev, netdev_features_t features)
 {
        struct ql_adapter *qdev = netdev_priv(ndev);
 
@@ -2323,7 +2323,8 @@ static void qlge_vlan_mode(struct net_device *ndev, u32 features)
        }
 }
 
-static u32 qlge_fix_features(struct net_device *ndev, u32 features)
+static netdev_features_t qlge_fix_features(struct net_device *ndev,
+       netdev_features_t features)
 {
        /*
         * Since there is no support for separate rx/tx vlan accel
@@ -2337,9 +2338,10 @@ static u32 qlge_fix_features(struct net_device *ndev, u32 features)
        return features;
 }
 
-static int qlge_set_features(struct net_device *ndev, u32 features)
+static int qlge_set_features(struct net_device *ndev,
+       netdev_features_t features)
 {
-       u32 changed = ndev->features ^ features;
+       netdev_features_t changed = ndev->features ^ features;
 
        if (changed & NETIF_F_HW_VLAN_RX)
                qlge_vlan_mode(ndev, features);
index 1fc01ca..4bf68cf 100644 (file)
@@ -940,7 +940,7 @@ static void r6040_multicast_list(struct net_device *dev)
        iowrite16(lp->mcr0, ioaddr + MCR0);
 
        /* Fill the MAC hash tables with their values */
-       if (lp->mcr0 && MCR0_HASH_EN) {
+       if (lp->mcr0 & MCR0_HASH_EN) {
                iowrite16(hash_table[0], ioaddr + MAR0);
                iowrite16(hash_table[1], ioaddr + MAR1);
                iowrite16(hash_table[2], ioaddr + MAR2);
index ee5da92..87cff10 100644 (file)
@@ -1319,9 +1319,9 @@ static void cp_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info
 {
        struct cp_private *cp = netdev_priv(dev);
 
-       strcpy (info->driver, DRV_NAME);
-       strcpy (info->version, DRV_VERSION);
-       strcpy (info->bus_info, pci_name(cp->pdev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(cp->pdev), sizeof(info->bus_info));
 }
 
 static void cp_get_ringparam(struct net_device *dev,
@@ -1392,7 +1392,7 @@ static void cp_set_msglevel(struct net_device *dev, u32 value)
        cp->msg_enable = value;
 }
 
-static int cp_set_features(struct net_device *dev, u32 features)
+static int cp_set_features(struct net_device *dev, netdev_features_t features)
 {
        struct cp_private *cp = netdev_priv(dev);
        unsigned long flags;
index 4d6b254..d9c7227 100644 (file)
@@ -2330,9 +2330,9 @@ static int rtl8139_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 static void rtl8139_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
        struct rtl8139_private *tp = netdev_priv(dev);
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, pci_name(tp->pci_dev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(tp->pci_dev), sizeof(info->bus_info));
        info->regdump_len = tp->regs_len;
 }
 
index 92b45f0..f7bc310 100644 (file)
@@ -69,9 +69,6 @@
    The RTL chips use a 64 element hash table based on the Ethernet CRC. */
 static const int multicast_filter_limit = 32;
 
-/* MAC address length */
-#define MAC_ADDR_LEN   6
-
 #define MAX_READ_REQUEST_SHIFT 12
 #define TX_DMA_BURST   6       /* Maximum PCI burst, '6' is 1024 */
 #define SafeMtu                0x1c20  /* ... actually life sucks beyond ~7k */
@@ -1292,7 +1289,7 @@ static void __rtl8169_check_link_status(struct net_device *dev,
                netif_carrier_off(dev);
                netif_info(tp, ifdown, dev, "link down\n");
                if (pm)
-                       pm_schedule_suspend(&tp->pci_dev->dev, 100);
+                       pm_schedule_suspend(&tp->pci_dev->dev, 5000);
        }
        spin_unlock_irqrestore(&tp->lock, flags);
 }
@@ -1404,12 +1401,12 @@ static void rtl8169_get_drvinfo(struct net_device *dev,
        struct rtl8169_private *tp = netdev_priv(dev);
        struct rtl_fw *rtl_fw = tp->rtl_fw;
 
-       strcpy(info->driver, MODULENAME);
-       strcpy(info->version, RTL8169_VERSION);
-       strcpy(info->bus_info, pci_name(tp->pci_dev));
+       strlcpy(info->driver, MODULENAME, sizeof(info->driver));
+       strlcpy(info->version, RTL8169_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(tp->pci_dev), sizeof(info->bus_info));
        BUILD_BUG_ON(sizeof(info->fw_version) < sizeof(rtl_fw->version));
-       strcpy(info->fw_version, IS_ERR_OR_NULL(rtl_fw) ? "N/A" :
-              rtl_fw->version);
+       strlcpy(info->fw_version, IS_ERR_OR_NULL(rtl_fw) ? "N/A" :
+              rtl_fw->version, sizeof(info->fw_version));
 }
 
 static int rtl8169_get_regs_len(struct net_device *dev)
@@ -1553,7 +1550,8 @@ static int rtl8169_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
        return ret;
 }
 
-static u32 rtl8169_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t rtl8169_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
 
@@ -1567,7 +1565,8 @@ static u32 rtl8169_fix_features(struct net_device *dev, u32 features)
        return features;
 }
 
-static int rtl8169_set_features(struct net_device *dev, u32 features)
+static int rtl8169_set_features(struct net_device *dev,
+       netdev_features_t features)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
        void __iomem *ioaddr = tp->mmio_addr;
@@ -4099,7 +4098,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        spin_lock_init(&tp->lock);
 
        /* Get MAC address */
-       for (i = 0; i < MAC_ADDR_LEN; i++)
+       for (i = 0; i < ETH_ALEN; i++)
                dev->dev_addr[i] = RTL_R8(MAC0 + i);
        memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
index d5731f1..14e134d 100644 (file)
@@ -1900,7 +1900,7 @@ static void efx_set_multicast_list(struct net_device *net_dev)
        /* Otherwise efx_start_port() will do this */
 }
 
-static int efx_set_features(struct net_device *net_dev, u32 data)
+static int efx_set_features(struct net_device *net_dev, netdev_features_t data)
 {
        struct efx_nic *efx = netdev_priv(net_dev);
 
index b8e251a..c49502b 100644 (file)
@@ -908,7 +908,7 @@ struct efx_nic_type {
        unsigned int phys_addr_channels;
        unsigned int tx_dc_base;
        unsigned int rx_dc_base;
-       u32 offload_features;
+       netdev_features_t offload_features;
 };
 
 /**************************************************************************
index 1b4658c..5b118cd 100644 (file)
@@ -47,8 +47,6 @@
 #define sis190_rx_skb                  netif_rx
 #define sis190_rx_quota(count, quota)  count
 
-#define MAC_ADDR_LEN           6
-
 #define NUM_TX_DESC            64      /* [8..1024] */
 #define NUM_RX_DESC            64      /* [8..8192] */
 #define TX_RING_BYTES          (NUM_TX_DESC * sizeof(struct TxDesc))
@@ -1601,7 +1599,7 @@ static int __devinit sis190_get_mac_addr_from_eeprom(struct pci_dev *pdev,
        }
 
        /* Get MAC address from EEPROM */
-       for (i = 0; i < MAC_ADDR_LEN / 2; i++) {
+       for (i = 0; i < ETH_ALEN / 2; i++) {
                u16 w = sis190_read_eeprom(ioaddr, EEPROMMACAddr + i);
 
                ((__le16 *)dev->dev_addr)[i] = cpu_to_le16(w);
@@ -1653,7 +1651,7 @@ static int __devinit sis190_get_mac_addr_from_apc(struct pci_dev *pdev,
        udelay(50);
        pci_read_config_byte(isa_bridge, 0x48, &reg);
 
-        for (i = 0; i < MAC_ADDR_LEN; i++) {
+        for (i = 0; i < ETH_ALEN; i++) {
                 outb(0x9 + i, 0x78);
                 dev->dev_addr[i] = inb(0x79);
         }
@@ -1692,7 +1690,7 @@ static inline void sis190_init_rxfilter(struct net_device *dev)
         */
        SIS_W16(RxMacControl, ctl & ~0x0f00);
 
-       for (i = 0; i < MAC_ADDR_LEN; i++)
+       for (i = 0; i < ETH_ALEN; i++)
                SIS_W8(RxMacAddr + i, dev->dev_addr[i]);
 
        SIS_W16(RxMacControl, ctl);
@@ -1760,9 +1758,10 @@ static void sis190_get_drvinfo(struct net_device *dev,
 {
        struct sis190_private *tp = netdev_priv(dev);
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, pci_name(tp->pci_dev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(tp->pci_dev),
+               sizeof(info->bus_info));
 }
 
 static int sis190_get_regs_len(struct net_device *dev)
index a184abc..c8efc70 100644 (file)
@@ -1991,9 +1991,10 @@ static void sis900_get_drvinfo(struct net_device *net_dev,
 {
        struct sis900_private *sis_priv = netdev_priv(net_dev);
 
-       strcpy (info->driver, SIS900_MODULE_NAME);
-       strcpy (info->version, SIS900_DRV_VERSION);
-       strcpy (info->bus_info, pci_name(sis_priv->pci_dev));
+       strlcpy(info->driver, SIS900_MODULE_NAME, sizeof(info->driver));
+       strlcpy(info->version, SIS900_DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(sis_priv->pci_dev),
+               sizeof(info->bus_info));
 }
 
 static u32 sis900_get_msglevel(struct net_device *net_dev)
index 0a5dfb8..2c077ce 100644 (file)
@@ -1414,9 +1414,9 @@ static void netdev_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *
 {
        struct epic_private *np = netdev_priv(dev);
 
-       strcpy (info->driver, DRV_NAME);
-       strcpy (info->version, DRV_VERSION);
-       strcpy (info->bus_info, pci_name(np->pci_dev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(np->pci_dev), sizeof(info->bus_info));
 }
 
 static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
index cbfa981..ada927a 100644 (file)
@@ -1909,8 +1909,8 @@ static int check_if_running(struct net_device *dev)
 
 static void smc_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
 }
 
 static int smc_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
index d2be42a..8843071 100644 (file)
@@ -1937,6 +1937,7 @@ static int __devinit smsc911x_init(struct net_device *dev)
 {
        struct smsc911x_data *pdata = netdev_priv(dev);
        unsigned int byte_test;
+       unsigned int to = 100;
 
        SMSC_TRACE(pdata, probe, "Driver Parameters:");
        SMSC_TRACE(pdata, probe, "LAN base: 0x%08lX",
@@ -1952,6 +1953,17 @@ static int __devinit smsc911x_init(struct net_device *dev)
                return -ENODEV;
        }
 
+       /*
+        * poll the READY bit in PMT_CTRL. Any other access to the device is
+        * forbidden while this bit isn't set. Try for 100ms
+        */
+       while (!(smsc911x_reg_read(pdata, PMT_CTRL) & PMT_CTRL_READY_) && --to)
+               udelay(1000);
+       if (to == 0) {
+               pr_err("Device not READY in 100ms aborting\n");
+               return -ENODEV;
+       }
+
        /* Check byte ordering */
        byte_test = smsc911x_reg_read(pdata, BYTE_TEST);
        SMSC_TRACE(pdata, probe, "BYTE_TEST: 0x%08X", byte_test);
index edb24b0..a9efbdf 100644 (file)
@@ -279,9 +279,10 @@ static void smsc9420_ethtool_get_drvinfo(struct net_device *netdev,
 {
        struct smsc9420_pdata *pd = netdev_priv(netdev);
 
-       strcpy(drvinfo->driver, DRV_NAME);
-       strcpy(drvinfo->bus_info, pci_name(pd->pdev));
-       strcpy(drvinfo->version, DRV_VERSION);
+       strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->bus_info, pci_name(pd->pdev),
+               sizeof(drvinfo->bus_info));
+       strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
 }
 
 static u32 smsc9420_ethtool_get_msglevel(struct net_device *netdev)
index da66ac5..4d5402a 100644 (file)
@@ -39,10 +39,11 @@ static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, u32 dma_tx,
        /* DMA SW reset */
        value |= DMA_BUS_MODE_SFT_RESET;
        writel(value, ioaddr + DMA_BUS_MODE);
-       limit = 15000;
+       limit = 10;
        while (limit--) {
                if (!(readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET))
                        break;
+               mdelay(10);
        }
        if (limit < 0)
                return -EBUSY;
index 627f656..bc17fd0 100644 (file)
@@ -41,10 +41,11 @@ static int dwmac100_dma_init(void __iomem *ioaddr, int pbl, u32 dma_tx,
        /* DMA SW reset */
        value |= DMA_BUS_MODE_SFT_RESET;
        writel(value, ioaddr + DMA_BUS_MODE);
-       limit = 15000;
+       limit = 10;
        while (limit--) {
                if (!(readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET))
                        break;
+               mdelay(10);
        }
        if (limit < 0)
                return -EBUSY;
index 9bafa6c..a140a8f 100644 (file)
@@ -72,7 +72,6 @@ struct stmmac_priv {
        spinlock_t lock;
        spinlock_t tx_lock;
        int wolopts;
-       int wolenabled;
        int wol_irq;
 #ifdef CONFIG_STMMAC_TIMER
        struct stmmac_timer *tm;
@@ -80,6 +79,7 @@ struct stmmac_priv {
        struct plat_stmmacenet_data *plat;
        struct stmmac_counters mmc;
        struct dma_features dma_cap;
+       int hw_cap_support;
 };
 
 extern int stmmac_mdio_unregister(struct net_device *ndev);
index e8eff09..ed83c4c 100644 (file)
@@ -185,9 +185,10 @@ static void stmmac_ethtool_getdrvinfo(struct net_device *dev,
        struct stmmac_priv *priv = netdev_priv(dev);
 
        if (priv->plat->has_gmac)
-               strcpy(info->driver, GMAC_ETHTOOL_NAME);
+               strlcpy(info->driver, GMAC_ETHTOOL_NAME, sizeof(info->driver));
        else
-               strcpy(info->driver, MAC100_ETHTOOL_NAME);
+               strlcpy(info->driver, MAC100_ETHTOOL_NAME,
+                       sizeof(info->driver));
 
        strcpy(info->version, DRV_MODULE_VERSION);
        info->fw_version[0] = '\0';
@@ -430,6 +431,12 @@ static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
        struct stmmac_priv *priv = netdev_priv(dev);
        u32 support = WAKE_MAGIC | WAKE_UCAST;
 
+       /* By default almost all GMAC devices support the WoL via
+        * magic frame but we can disable it if the HW capability
+        * register shows no support for pmt_magic_frame. */
+       if ((priv->hw_cap_support) && (!priv->dma_cap.pmt_magic_frame))
+               wol->wolopts &= ~WAKE_MAGIC;
+
        if (!device_can_wakeup(priv->device))
                return -EINVAL;
 
index 20546bb..de71859 100644 (file)
@@ -321,12 +321,10 @@ static int stmmac_init_phy(struct net_device *dev)
        }
 
        /* Stop Advertising 1000BASE Capability if interface is not GMII */
-       if ((interface) && ((interface == PHY_INTERFACE_MODE_MII) ||
-           (interface == PHY_INTERFACE_MODE_RMII))) {
-               phydev->supported &= (PHY_BASIC_FEATURES | SUPPORTED_Pause |
-                                     SUPPORTED_Asym_Pause);
-               phydev->advertising = phydev->supported;
-       }
+       if ((interface == PHY_INTERFACE_MODE_MII) ||
+           (interface == PHY_INTERFACE_MODE_RMII))
+               phydev->advertising &= ~(SUPPORTED_1000baseT_Half |
+                                        SUPPORTED_1000baseT_Full);
 
        /*
         * Broken HW is sometimes missing the pull-up resistor on the
@@ -807,8 +805,29 @@ static u32 stmmac_get_synopsys_id(struct stmmac_priv *priv)
        return 0;
 }
 
-/* New GMAC chips support a new register to indicate the
- * presence of the optional feature/functions.
+/**
+ * stmmac_selec_desc_mode
+ * @dev : device pointer
+ * Description: select the Enhanced/Alternate or Normal descriptors */
+static void stmmac_selec_desc_mode(struct stmmac_priv *priv)
+{
+       if (priv->plat->enh_desc) {
+               pr_info(" Enhanced/Alternate descriptors\n");
+               priv->hw->desc = &enh_desc_ops;
+       } else {
+               pr_info(" Normal descriptors\n");
+               priv->hw->desc = &ndesc_ops;
+       }
+}
+
+/**
+ * stmmac_get_hw_features
+ * @priv : private device pointer
+ * Description:
+ *  new GMAC chip generations have a new register to indicate the
+ *  presence of the optional feature/functions.
+ *  This can be also used to override the value passed through the
+ *  platform and necessary for old MAC10/100 and GMAC chips.
  */
 static int stmmac_get_hw_features(struct stmmac_priv *priv)
 {
@@ -829,7 +848,7 @@ static int stmmac_get_hw_features(struct stmmac_priv *priv)
                        (hw_cap & DMA_HW_FEAT_RWKSEL) >> 9;
                priv->dma_cap.pmt_magic_frame =
                        (hw_cap & DMA_HW_FEAT_MGKSEL) >> 10;
-               /*MMC*/
+               /* MMC */
                priv->dma_cap.rmon = (hw_cap & DMA_HW_FEAT_MMCSEL) >> 11;
                /* IEEE 1588-2002*/
                priv->dma_cap.time_stamp =
@@ -857,8 +876,7 @@ static int stmmac_get_hw_features(struct stmmac_priv *priv)
                priv->dma_cap.enh_desc =
                        (hw_cap & DMA_HW_FEAT_ENHDESSEL) >> 24;
 
-       } else
-               pr_debug("\tNo HW DMA feature register supported");
+       }
 
        return hw_cap;
 }
@@ -913,6 +931,44 @@ static int stmmac_open(struct net_device *dev)
                goto open_error;
        }
 
+       stmmac_get_synopsys_id(priv);
+
+       priv->hw_cap_support = stmmac_get_hw_features(priv);
+
+       if (priv->hw_cap_support) {
+               pr_info(" Support DMA HW capability register");
+
+               /* We can override some gmac/dma configuration fields: e.g.
+                * enh_desc, tx_coe (e.g. that are passed through the
+                * platform) with the values from the HW capability
+                * register (if supported).
+                */
+               priv->plat->enh_desc = priv->dma_cap.enh_desc;
+               priv->plat->tx_coe = priv->dma_cap.tx_coe;
+               priv->plat->pmt = priv->dma_cap.pmt_remote_wake_up;
+
+               /* By default disable wol on magic frame if not supported */
+               if (!priv->dma_cap.pmt_magic_frame)
+                       priv->wolopts &= ~WAKE_MAGIC;
+
+       } else
+               pr_info(" No HW DMA feature register supported");
+
+       /* Select the enhnaced/normal descriptor structures */
+       stmmac_selec_desc_mode(priv);
+
+       /* PMT module is not integrated in all the MAC devices. */
+       if (priv->plat->pmt) {
+               pr_info(" Remote wake-up capable\n");
+               device_set_wakeup_capable(priv->device, 1);
+       }
+
+       priv->rx_coe = priv->hw->mac->rx_coe(priv->ioaddr);
+       if (priv->rx_coe)
+               pr_info(" Checksum Offload Engine supported\n");
+       if (priv->plat->tx_coe)
+               pr_info(" Checksum insertion supported\n");
+
        /* Create and initialize the TX/RX descriptors chains. */
        priv->dma_tx_size = STMMAC_ALIGN(dma_txsize);
        priv->dma_rx_size = STMMAC_ALIGN(dma_rxsize);
@@ -935,15 +991,6 @@ static int stmmac_open(struct net_device *dev)
        /* Initialize the MAC Core */
        priv->hw->mac->core_init(priv->ioaddr);
 
-       stmmac_get_synopsys_id(priv);
-
-       stmmac_get_hw_features(priv);
-
-       priv->rx_coe = priv->hw->mac->rx_coe(priv->ioaddr);
-       if (priv->rx_coe)
-               pr_info("stmmac: Rx Checksum Offload Engine supported\n");
-       if (priv->plat->tx_coe)
-               pr_info("\tTX Checksum insertion supported\n");
        netdev_update_features(dev);
 
        /* Request the IRQ lines */
@@ -1419,7 +1466,8 @@ static int stmmac_change_mtu(struct net_device *dev, int new_mtu)
        return 0;
 }
 
-static u32 stmmac_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t stmmac_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        struct stmmac_priv *priv = netdev_priv(dev);
 
@@ -1489,9 +1537,7 @@ static int stmmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
        if (!priv->phydev)
                return -EINVAL;
 
-       spin_lock(&priv->lock);
        ret = phy_mii_ioctl(priv->phydev, rq, cmd);
-       spin_unlock(&priv->lock);
 
        return ret;
 }
@@ -1558,7 +1604,7 @@ static int stmmac_sysfs_dma_cap_read(struct seq_file *seq, void *v)
        struct net_device *dev = seq->private;
        struct stmmac_priv *priv = netdev_priv(dev);
 
-       if (!stmmac_get_hw_features(priv)) {
+       if (!priv->hw_cap_support) {
                seq_printf(seq, "DMA HW features not supported\n");
                return 0;
        }
@@ -1766,12 +1812,6 @@ static int stmmac_mac_device_setup(struct net_device *dev)
        if (!device)
                return -ENOMEM;
 
-       if (priv->plat->enh_desc) {
-               device->desc = &enh_desc_ops;
-               pr_info("\tEnhanced descriptor structure\n");
-       } else
-               device->desc = &ndesc_ops;
-
        priv->hw = device;
        priv->hw->ring = &ring_mode_ops;
 
@@ -1845,11 +1885,6 @@ static int stmmac_dvr_probe(struct platform_device *pdev)
 
        priv->ioaddr = addr;
 
-       /* PMT module is not integrated in all the MAC devices. */
-       if (plat_dat->pmt) {
-               pr_info("\tPMT module supported\n");
-               device_set_wakeup_capable(&pdev->dev, 1);
-       }
        /*
         * On some platforms e.g. SPEAr the wake up irq differs from the mac irq
         * The external wake up irq can be passed through the platform code
@@ -1862,7 +1897,6 @@ static int stmmac_dvr_probe(struct platform_device *pdev)
        if (priv->wol_irq == -ENXIO)
                priv->wol_irq = ndev->irq;
 
-
        platform_set_drvdata(pdev, ndev);
 
        /* Set the I/O base addr */
@@ -1875,7 +1909,7 @@ static int stmmac_dvr_probe(struct platform_device *pdev)
                        goto out_free_ndev;
        }
 
-       /* MAC HW revice detection */
+       /* MAC HW device detection */
        ret = stmmac_mac_device_setup(ndev);
        if (ret < 0)
                goto out_plat_exit;
@@ -1978,12 +2012,13 @@ static int stmmac_suspend(struct device *dev)
        if (!ndev || !netif_running(ndev))
                return 0;
 
+       if (priv->phydev)
+               phy_stop(priv->phydev);
+
        spin_lock(&priv->lock);
 
        netif_device_detach(ndev);
        netif_stop_queue(ndev);
-       if (priv->phydev)
-               phy_stop(priv->phydev);
 
 #ifdef CONFIG_STMMAC_TIMER
        priv->tm->timer_stop();
@@ -2041,12 +2076,13 @@ static int stmmac_resume(struct device *dev)
 #endif
        napi_enable(&priv->napi);
 
-       if (priv->phydev)
-               phy_start(priv->phydev);
-
        netif_start_queue(ndev);
 
        spin_unlock(&priv->lock);
+
+       if (priv->phydev)
+               phy_start(priv->phydev);
+
        return 0;
 }
 
index fd40988..f10665f 100644 (file)
@@ -4532,10 +4532,9 @@ static void cas_set_multicast(struct net_device *dev)
 static void cas_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
        struct cas *cp = netdev_priv(dev);
-       strncpy(info->driver, DRV_MODULE_NAME, ETHTOOL_BUSINFO_LEN);
-       strncpy(info->version, DRV_MODULE_VERSION, ETHTOOL_BUSINFO_LEN);
-       info->fw_version[0] = '\0';
-       strncpy(info->bus_info, pci_name(cp->pdev), ETHTOOL_BUSINFO_LEN);
+       strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(cp->pdev), sizeof(info->bus_info));
        info->regdump_len = cp->casreg_len < CAS_MAX_REGS ?
                cp->casreg_len : CAS_MAX_REGS;
        info->n_stats = CAS_NUM_STAT_KEYS;
index 73c7081..680b107 100644 (file)
@@ -1151,19 +1151,8 @@ static int link_status_mii(struct niu *np, int *link_up_p)
                supported |= SUPPORTED_1000baseT_Full;
        lp->supported = supported;
 
-       advertising = 0;
-       if (advert & ADVERTISE_10HALF)
-               advertising |= ADVERTISED_10baseT_Half;
-       if (advert & ADVERTISE_10FULL)
-               advertising |= ADVERTISED_10baseT_Full;
-       if (advert & ADVERTISE_100HALF)
-               advertising |= ADVERTISED_100baseT_Half;
-       if (advert & ADVERTISE_100FULL)
-               advertising |= ADVERTISED_100baseT_Full;
-       if (ctrl1000 & ADVERTISE_1000HALF)
-               advertising |= ADVERTISED_1000baseT_Half;
-       if (ctrl1000 & ADVERTISE_1000FULL)
-               advertising |= ADVERTISED_1000baseT_Full;
+       advertising = mii_adv_to_ethtool_adv_t(advert);
+       advertising |= mii_ctrl1000_to_ethtool_adv_t(ctrl1000);
 
        if (bmcr & BMCR_ANENABLE) {
                int neg, neg1000;
@@ -6823,12 +6812,13 @@ static void niu_get_drvinfo(struct net_device *dev,
        struct niu *np = netdev_priv(dev);
        struct niu_vpd *vpd = &np->vpd;
 
-       strcpy(info->driver, DRV_MODULE_NAME);
-       strcpy(info->version, DRV_MODULE_VERSION);
-       sprintf(info->fw_version, "%d.%d",
+       strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
+       snprintf(info->fw_version, sizeof(info->fw_version), "%d.%d",
                vpd->fcode_major, vpd->fcode_minor);
        if (np->parent->plat_type != PLAT_TYPE_NIU)
-               strcpy(info->bus_info, pci_name(np->pdev));
+               strlcpy(info->bus_info, pci_name(np->pdev),
+                       sizeof(info->bus_info));
 }
 
 static int niu_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
index ceab215..31441a8 100644 (file)
@@ -2517,9 +2517,9 @@ static void gem_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info
 {
        struct gem *gp = netdev_priv(dev);
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, pci_name(gp->pdev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(gp->pdev), sizeof(info->bus_info));
 }
 
 static int gem_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
index c517dac..eebd52f 100644 (file)
@@ -2457,11 +2457,11 @@ static void hme_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info
 {
        struct happy_meal *hp = netdev_priv(dev);
 
-       strcpy(info->driver, "sunhme");
-       strcpy(info->version, "2.02");
+       strlcpy(info->driver, "sunhme", sizeof(info->driver));
+       strlcpy(info->version, "2.02", sizeof(info->version));
        if (hp->happy_flags & HFLAG_PCI) {
                struct pci_dev *pdev = hp->happy_dev;
-               strcpy(info->bus_info, pci_name(pdev));
+               strlcpy(info->bus_info, pci_name(pdev), sizeof(info->bus_info));
        }
 #ifdef CONFIG_SBUS
        else {
@@ -2469,7 +2469,8 @@ static void hme_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info
                struct platform_device *op = hp->happy_dev;
                regs = of_get_property(op->dev.of_node, "regs", NULL);
                if (regs)
-                       sprintf(info->bus_info, "SBUS:%d",
+                       snprintf(info->bus_info, sizeof(info->bus_info),
+                               "SBUS:%d",
                                regs->which_io);
        }
 #endif
@@ -2637,7 +2638,7 @@ static int __devinit happy_meal_sbus_probe_one(struct platform_device *op, int i
        sbus_dp = op->dev.parent->of_node;
 
        /* We can match PCI devices too, do not accept those here. */
-       if (strcmp(sbus_dp->name, "sbus"))
+       if (strcmp(sbus_dp->name, "sbus") && strcmp(sbus_dp->name, "sbi"))
                return err;
 
        if (is_qfe) {
index f34dd99..5587ecd 100644 (file)
@@ -2009,9 +2009,9 @@ static void netdev_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *i
 {
        struct rhine_private *rp = netdev_priv(dev);
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, pci_name(rp->pdev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(rp->pdev), sizeof(info->bus_info));
 }
 
 static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
index 4535d7c..59bb5fd 100644 (file)
@@ -3270,9 +3270,9 @@ static int velocity_set_settings(struct net_device *dev,
 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));
+       strlcpy(info->driver, VELOCITY_NAME, sizeof(info->driver));
+       strlcpy(info->version, VELOCITY_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(vptr->pdev), sizeof(info->bus_info));
 }
 
 static void velocity_ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
index caf3659..1ade9e1 100644 (file)
@@ -114,6 +114,7 @@ void temac_indirect_out32(struct temac_local *lp, int reg, u32 value)
                return;
        temac_iow(lp, XTE_LSW0_OFFSET, value);
        temac_iow(lp, XTE_CTL0_OFFSET, CNTLREG_WRITE_ENABLE_MASK | reg);
+       temac_indirect_busywait(lp);
 }
 
 /**
@@ -203,6 +204,9 @@ static void temac_dma_bd_release(struct net_device *ndev)
        struct temac_local *lp = netdev_priv(ndev);
        int i;
 
+       /* Reset Local Link (DMA) */
+       lp->dma_out(lp, DMA_CONTROL_REG, DMA_CONTROL_RST);
+
        for (i = 0; i < RX_BD_NUM; i++) {
                if (!lp->rx_skb[i])
                        break;
@@ -860,6 +864,8 @@ static int temac_open(struct net_device *ndev)
                phy_start(lp->phy_dev);
        }
 
+       temac_device_reset(ndev);
+
        rc = request_irq(lp->tx_irq, ll_temac_tx_irq, 0, ndev->name, ndev);
        if (rc)
                goto err_tx_irq;
@@ -867,7 +873,6 @@ static int temac_open(struct net_device *ndev)
        if (rc)
                goto err_rx_irq;
 
-       temac_device_reset(ndev);
        return 0;
 
  err_rx_irq:
@@ -915,12 +920,26 @@ temac_poll_controller(struct net_device *ndev)
 }
 #endif
 
+static int temac_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
+{
+       struct temac_local *lp = netdev_priv(ndev);
+
+       if (!netif_running(ndev))
+               return -EINVAL;
+
+       if (!lp->phy_dev)
+               return -EINVAL;
+
+       return phy_mii_ioctl(lp->phy_dev, rq, cmd);
+}
+
 static const struct net_device_ops temac_netdev_ops = {
        .ndo_open = temac_open,
        .ndo_stop = temac_stop,
        .ndo_start_xmit = temac_start_xmit,
        .ndo_set_mac_address = netdev_set_mac_address,
        .ndo_validate_addr = eth_validate_addr,
+       .ndo_do_ioctl = temac_ioctl,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller = temac_poll_controller,
 #endif
index bbe8b7d..33979c3 100644 (file)
@@ -1411,7 +1411,7 @@ do_open(struct net_device *dev)
 static void netdev_get_drvinfo(struct net_device *dev,
                               struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, "xirc2ps_cs");
+       strlcpy(info->driver, "xirc2ps_cs", sizeof(info->driver));
        sprintf(info->bus_info, "PCMCIA 0x%lx", dev->base_addr);
 }
 
index 7393eb7..95eb34f 100644 (file)
@@ -36,4 +36,4 @@ config ROADRUNNER_LARGE_RINGS
          kernel code or by user space programs. Say Y here only if you have
          the memory.
 
-endif /* HIPPI */
+endif # HIPPI
index 46b5f5f..e05b645 100644 (file)
@@ -164,7 +164,7 @@ static const struct net_device_ops ifb_netdev_ops = {
        .ndo_validate_addr = eth_validate_addr,
 };
 
-#define IFB_FEATURES (NETIF_F_NO_CSUM | NETIF_F_SG  | NETIF_F_FRAGLIST | \
+#define IFB_FEATURES (NETIF_F_HW_CSUM | NETIF_F_SG  | NETIF_F_FRAGLIST | \
                      NETIF_F_TSO_ECN | NETIF_F_TSO | NETIF_F_TSO6      | \
                      NETIF_F_HIGHDMA | NETIF_F_HW_VLAN_TX)
 
index 4ce9e5f..b71998d 100644 (file)
@@ -169,7 +169,7 @@ static void loopback_setup(struct net_device *dev)
        dev->features           = NETIF_F_SG | NETIF_F_FRAGLIST
                | NETIF_F_ALL_TSO
                | NETIF_F_UFO
-               | NETIF_F_NO_CSUM
+               | NETIF_F_HW_CSUM
                | NETIF_F_RXCSUM
                | NETIF_F_HIGHDMA
                | NETIF_F_LLTX
index 1b7082d..7c88d13 100644 (file)
@@ -145,8 +145,8 @@ static void macvtap_put_queue(struct macvtap_queue *q)
        if (vlan) {
                int index = get_slot(vlan, q);
 
-               rcu_assign_pointer(vlan->taps[index], NULL);
-               rcu_assign_pointer(q->vlan, NULL);
+               RCU_INIT_POINTER(vlan->taps[index], NULL);
+               RCU_INIT_POINTER(q->vlan, NULL);
                sock_put(&q->sk);
                --vlan->numvtaps;
        }
@@ -223,8 +223,8 @@ static void macvtap_del_queues(struct net_device *dev)
                                              lockdep_is_held(&macvtap_lock));
                if (q) {
                        qlist[j++] = q;
-                       rcu_assign_pointer(vlan->taps[i], NULL);
-                       rcu_assign_pointer(q->vlan, NULL);
+                       RCU_INIT_POINTER(vlan->taps[i], NULL);
+                       RCU_INIT_POINTER(q->vlan, NULL);
                        vlan->numvtaps--;
                }
        }
index c62e781..c70c233 100644 (file)
 
 static u32 mii_get_an(struct mii_if_info *mii, u16 addr)
 {
-       u32 result = 0;
        int advert;
 
        advert = mii->mdio_read(mii->dev, mii->phy_id, addr);
-       if (advert & LPA_LPACK)
-               result |= ADVERTISED_Autoneg;
-       if (advert & ADVERTISE_10HALF)
-               result |= ADVERTISED_10baseT_Half;
-       if (advert & ADVERTISE_10FULL)
-               result |= ADVERTISED_10baseT_Full;
-       if (advert & ADVERTISE_100HALF)
-               result |= ADVERTISED_100baseT_Half;
-       if (advert & ADVERTISE_100FULL)
-               result |= ADVERTISED_100baseT_Full;
-       if (advert & ADVERTISE_PAUSE_CAP)
-               result |= ADVERTISED_Pause;
-       if (advert & ADVERTISE_PAUSE_ASYM)
-               result |= ADVERTISED_Asym_Pause;
-
-       return result;
+
+       return mii_lpa_to_ethtool_lpa_t(advert);
 }
 
 /**
@@ -104,19 +89,14 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
                ecmd->autoneg = AUTONEG_ENABLE;
 
                ecmd->advertising |= mii_get_an(mii, MII_ADVERTISE);
-               if (ctrl1000 & ADVERTISE_1000HALF)
-                       ecmd->advertising |= ADVERTISED_1000baseT_Half;
-               if (ctrl1000 & ADVERTISE_1000FULL)
-                       ecmd->advertising |= ADVERTISED_1000baseT_Full;
+               if (mii->supports_gmii)
+                       ecmd->advertising |=
+                                       mii_ctrl1000_to_ethtool_adv_t(ctrl1000);
 
                if (bmsr & BMSR_ANEGCOMPLETE) {
                        ecmd->lp_advertising = mii_get_an(mii, MII_LPA);
-                       if (stat1000 & LPA_1000HALF)
-                               ecmd->lp_advertising |=
-                                       ADVERTISED_1000baseT_Half;
-                       if (stat1000 & LPA_1000FULL)
-                               ecmd->lp_advertising |=
-                                       ADVERTISED_1000baseT_Full;
+                       ecmd->lp_advertising |=
+                                       mii_stat1000_to_ethtool_lpa_t(stat1000);
                } else {
                        ecmd->lp_advertising = 0;
                }
@@ -204,20 +184,11 @@ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
                        advert2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
                        tmp2 = advert2 & ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
                }
-               if (ecmd->advertising & ADVERTISED_10baseT_Half)
-                       tmp |= ADVERTISE_10HALF;
-               if (ecmd->advertising & ADVERTISED_10baseT_Full)
-                       tmp |= ADVERTISE_10FULL;
-               if (ecmd->advertising & ADVERTISED_100baseT_Half)
-                       tmp |= ADVERTISE_100HALF;
-               if (ecmd->advertising & ADVERTISED_100baseT_Full)
-                       tmp |= ADVERTISE_100FULL;
-               if (mii->supports_gmii) {
-                       if (ecmd->advertising & ADVERTISED_1000baseT_Half)
-                               tmp2 |= ADVERTISE_1000HALF;
-                       if (ecmd->advertising & ADVERTISED_1000baseT_Full)
-                               tmp2 |= ADVERTISE_1000FULL;
-               }
+               tmp |= ethtool_adv_to_mii_adv_t(ecmd->advertising);
+
+               if (mii->supports_gmii)
+                       tmp2 |=
+                             ethtool_adv_to_mii_ctrl1000_t(ecmd->advertising);
                if (advert != tmp) {
                        mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp);
                        mii->advertising = tmp;
index 6539189..daec9b0 100644 (file)
@@ -202,6 +202,14 @@ static int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val)
        return 0;
 }
 
+static int mdiobb_reset(struct mii_bus *bus)
+{
+       struct mdiobb_ctrl *ctrl = bus->priv;
+       if (ctrl->reset)
+               ctrl->reset(bus);
+       return 0;
+}
+
 struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl)
 {
        struct mii_bus *bus;
@@ -214,6 +222,7 @@ struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl)
 
        bus->read = mdiobb_read;
        bus->write = mdiobb_write;
+       bus->reset = mdiobb_reset;
        bus->priv = ctrl;
 
        return bus;
index 2843c90..89c5a3e 100644 (file)
@@ -95,6 +95,7 @@ static struct mii_bus * __devinit mdio_gpio_bus_init(struct device *dev,
                goto out;
 
        bitbang->ctrl.ops = &mdio_gpio_ops;
+       bitbang->ctrl.reset = pdata->reset;
        bitbang->mdc = pdata->mdc;
        bitbang->mdio = pdata->mdio;
 
index 83a5a5a..f320f46 100644 (file)
@@ -563,20 +563,9 @@ static int genphy_config_advert(struct phy_device *phydev)
        if (adv < 0)
                return adv;
 
-       adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP | 
+       adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP |
                 ADVERTISE_PAUSE_ASYM);
-       if (advertise & ADVERTISED_10baseT_Half)
-               adv |= ADVERTISE_10HALF;
-       if (advertise & ADVERTISED_10baseT_Full)
-               adv |= ADVERTISE_10FULL;
-       if (advertise & ADVERTISED_100baseT_Half)
-               adv |= ADVERTISE_100HALF;
-       if (advertise & ADVERTISED_100baseT_Full)
-               adv |= ADVERTISE_100FULL;
-       if (advertise & ADVERTISED_Pause)
-               adv |= ADVERTISE_PAUSE_CAP;
-       if (advertise & ADVERTISED_Asym_Pause)
-               adv |= ADVERTISE_PAUSE_ASYM;
+       adv |= ethtool_adv_to_mii_adv_t(advertise);
 
        if (adv != oldadv) {
                err = phy_write(phydev, MII_ADVERTISE, adv);
@@ -595,10 +584,7 @@ static int genphy_config_advert(struct phy_device *phydev)
                        return adv;
 
                adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
-               if (advertise & SUPPORTED_1000baseT_Half)
-                       adv |= ADVERTISE_1000HALF;
-               if (advertise & SUPPORTED_1000baseT_Full)
-                       adv |= ADVERTISE_1000FULL;
+               adv |= ethtool_adv_to_mii_ctrl1000_t(advertise);
 
                if (adv != oldadv) {
                        err = phy_write(phydev, MII_CTRL1000, adv);
index 89f829f..ede899c 100644 (file)
@@ -162,7 +162,7 @@ static void del_chan(struct pppox_sock *sock)
 {
        spin_lock(&chan_lock);
        clear_bit(sock->proto.pptp.src_addr.call_id, callid_bitmap);
-       rcu_assign_pointer(callid_sock[sock->proto.pptp.src_addr.call_id], NULL);
+       RCU_INIT_POINTER(callid_sock[sock->proto.pptp.src_addr.call_id], NULL);
        spin_unlock(&chan_lock);
        synchronize_rcu();
 }
diff --git a/drivers/net/team/Kconfig b/drivers/net/team/Kconfig
new file mode 100644 (file)
index 0000000..248a144
--- /dev/null
@@ -0,0 +1,43 @@
+menuconfig NET_TEAM
+       tristate "Ethernet team driver support (EXPERIMENTAL)"
+       depends on EXPERIMENTAL
+       ---help---
+         This allows one to create virtual interfaces that teams together
+         multiple ethernet devices.
+
+         Team devices can be added using the "ip" command from the
+         iproute2 package:
+
+         "ip link add link [ address MAC ] [ NAME ] type team"
+
+         To compile this driver as a module, choose M here: the module
+         will be called team.
+
+if NET_TEAM
+
+config NET_TEAM_MODE_ROUNDROBIN
+       tristate "Round-robin mode support"
+       depends on NET_TEAM
+       ---help---
+         Basic mode where port used for transmitting packets is selected in
+         round-robin fashion using packet counter.
+
+         All added ports are setup to have bond's mac address.
+
+         To compile this team mode as a module, choose M here: the module
+         will be called team_mode_roundrobin.
+
+config NET_TEAM_MODE_ACTIVEBACKUP
+       tristate "Active-backup mode support"
+       depends on NET_TEAM
+       ---help---
+         Only one port is active at a time and the rest of ports are used
+         for backup.
+
+         Mac addresses of ports are not modified. Userspace is responsible
+         to do so.
+
+         To compile this team mode as a module, choose M here: the module
+         will be called team_mode_activebackup.
+
+endif # NET_TEAM
diff --git a/drivers/net/team/Makefile b/drivers/net/team/Makefile
new file mode 100644 (file)
index 0000000..85f2028
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Makefile for the network team driver
+#
+
+obj-$(CONFIG_NET_TEAM) += team.o
+obj-$(CONFIG_NET_TEAM_MODE_ROUNDROBIN) += team_mode_roundrobin.o
+obj-$(CONFIG_NET_TEAM_MODE_ACTIVEBACKUP) += team_mode_activebackup.o
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
new file mode 100644 (file)
index 0000000..064155d
--- /dev/null
@@ -0,0 +1,1661 @@
+/*
+ * net/drivers/team/team.c - Network team device driver
+ * Copyright (c) 2011 Jiri Pirko <jpirko@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 <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/rcupdate.h>
+#include <linux/errno.h>
+#include <linux/ctype.h>
+#include <linux/notifier.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/socket.h>
+#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
+#include <net/rtnetlink.h>
+#include <net/genetlink.h>
+#include <net/netlink.h>
+#include <linux/if_team.h>
+
+#define DRV_NAME "team"
+
+
+/**********
+ * Helpers
+ **********/
+
+#define team_port_exists(dev) (dev->priv_flags & IFF_TEAM_PORT)
+
+static struct team_port *team_port_get_rcu(const struct net_device *dev)
+{
+       struct team_port *port = rcu_dereference(dev->rx_handler_data);
+
+       return team_port_exists(dev) ? port : NULL;
+}
+
+static struct team_port *team_port_get_rtnl(const struct net_device *dev)
+{
+       struct team_port *port = rtnl_dereference(dev->rx_handler_data);
+
+       return team_port_exists(dev) ? port : NULL;
+}
+
+/*
+ * Since the ability to change mac address for open port device is tested in
+ * team_port_add, this function can be called without control of return value
+ */
+static int __set_port_mac(struct net_device *port_dev,
+                         const unsigned char *dev_addr)
+{
+       struct sockaddr addr;
+
+       memcpy(addr.sa_data, dev_addr, ETH_ALEN);
+       addr.sa_family = ARPHRD_ETHER;
+       return dev_set_mac_address(port_dev, &addr);
+}
+
+int team_port_set_orig_mac(struct team_port *port)
+{
+       return __set_port_mac(port->dev, port->orig.dev_addr);
+}
+
+int team_port_set_team_mac(struct team_port *port)
+{
+       return __set_port_mac(port->dev, port->team->dev->dev_addr);
+}
+EXPORT_SYMBOL(team_port_set_team_mac);
+
+
+/*******************
+ * Options handling
+ *******************/
+
+struct team_option *__team_find_option(struct team *team, const char *opt_name)
+{
+       struct team_option *option;
+
+       list_for_each_entry(option, &team->option_list, list) {
+               if (strcmp(option->name, opt_name) == 0)
+                       return option;
+       }
+       return NULL;
+}
+
+int team_options_register(struct team *team,
+                         const struct team_option *option,
+                         size_t option_count)
+{
+       int i;
+       struct team_option **dst_opts;
+       int err;
+
+       dst_opts = kzalloc(sizeof(struct team_option *) * option_count,
+                          GFP_KERNEL);
+       if (!dst_opts)
+               return -ENOMEM;
+       for (i = 0; i < option_count; i++, option++) {
+               if (__team_find_option(team, option->name)) {
+                       err = -EEXIST;
+                       goto rollback;
+               }
+               dst_opts[i] = kmemdup(option, sizeof(*option), GFP_KERNEL);
+               if (!dst_opts[i]) {
+                       err = -ENOMEM;
+                       goto rollback;
+               }
+       }
+
+       for (i = 0; i < option_count; i++)
+               list_add_tail(&dst_opts[i]->list, &team->option_list);
+
+       kfree(dst_opts);
+       return 0;
+
+rollback:
+       for (i = 0; i < option_count; i++)
+               kfree(dst_opts[i]);
+
+       kfree(dst_opts);
+       return err;
+}
+
+EXPORT_SYMBOL(team_options_register);
+
+static void __team_options_change_check(struct team *team,
+                                       struct team_option *changed_option);
+
+static void __team_options_unregister(struct team *team,
+                                     const struct team_option *option,
+                                     size_t option_count)
+{
+       int i;
+
+       for (i = 0; i < option_count; i++, option++) {
+               struct team_option *del_opt;
+
+               del_opt = __team_find_option(team, option->name);
+               if (del_opt) {
+                       list_del(&del_opt->list);
+                       kfree(del_opt);
+               }
+       }
+}
+
+void team_options_unregister(struct team *team,
+                            const struct team_option *option,
+                            size_t option_count)
+{
+       __team_options_unregister(team, option, option_count);
+       __team_options_change_check(team, NULL);
+}
+EXPORT_SYMBOL(team_options_unregister);
+
+static int team_option_get(struct team *team, struct team_option *option,
+                          void *arg)
+{
+       return option->getter(team, arg);
+}
+
+static int team_option_set(struct team *team, struct team_option *option,
+                          void *arg)
+{
+       int err;
+
+       err = option->setter(team, arg);
+       if (err)
+               return err;
+
+       __team_options_change_check(team, option);
+       return err;
+}
+
+/****************
+ * Mode handling
+ ****************/
+
+static LIST_HEAD(mode_list);
+static DEFINE_SPINLOCK(mode_list_lock);
+
+static struct team_mode *__find_mode(const char *kind)
+{
+       struct team_mode *mode;
+
+       list_for_each_entry(mode, &mode_list, list) {
+               if (strcmp(mode->kind, kind) == 0)
+                       return mode;
+       }
+       return NULL;
+}
+
+static bool is_good_mode_name(const char *name)
+{
+       while (*name != '\0') {
+               if (!isalpha(*name) && !isdigit(*name) && *name != '_')
+                       return false;
+               name++;
+       }
+       return true;
+}
+
+int team_mode_register(struct team_mode *mode)
+{
+       int err = 0;
+
+       if (!is_good_mode_name(mode->kind) ||
+           mode->priv_size > TEAM_MODE_PRIV_SIZE)
+               return -EINVAL;
+       spin_lock(&mode_list_lock);
+       if (__find_mode(mode->kind)) {
+               err = -EEXIST;
+               goto unlock;
+       }
+       list_add_tail(&mode->list, &mode_list);
+unlock:
+       spin_unlock(&mode_list_lock);
+       return err;
+}
+EXPORT_SYMBOL(team_mode_register);
+
+int team_mode_unregister(struct team_mode *mode)
+{
+       spin_lock(&mode_list_lock);
+       list_del_init(&mode->list);
+       spin_unlock(&mode_list_lock);
+       return 0;
+}
+EXPORT_SYMBOL(team_mode_unregister);
+
+static struct team_mode *team_mode_get(const char *kind)
+{
+       struct team_mode *mode;
+
+       spin_lock(&mode_list_lock);
+       mode = __find_mode(kind);
+       if (!mode) {
+               spin_unlock(&mode_list_lock);
+               request_module("team-mode-%s", kind);
+               spin_lock(&mode_list_lock);
+               mode = __find_mode(kind);
+       }
+       if (mode)
+               if (!try_module_get(mode->owner))
+                       mode = NULL;
+
+       spin_unlock(&mode_list_lock);
+       return mode;
+}
+
+static void team_mode_put(const struct team_mode *mode)
+{
+       module_put(mode->owner);
+}
+
+static bool team_dummy_transmit(struct team *team, struct sk_buff *skb)
+{
+       dev_kfree_skb_any(skb);
+       return false;
+}
+
+rx_handler_result_t team_dummy_receive(struct team *team,
+                                      struct team_port *port,
+                                      struct sk_buff *skb)
+{
+       return RX_HANDLER_ANOTHER;
+}
+
+static void team_adjust_ops(struct team *team)
+{
+       /*
+        * To avoid checks in rx/tx skb paths, ensure here that non-null and
+        * correct ops are always set.
+        */
+
+       if (list_empty(&team->port_list) ||
+           !team->mode || !team->mode->ops->transmit)
+               team->ops.transmit = team_dummy_transmit;
+       else
+               team->ops.transmit = team->mode->ops->transmit;
+
+       if (list_empty(&team->port_list) ||
+           !team->mode || !team->mode->ops->receive)
+               team->ops.receive = team_dummy_receive;
+       else
+               team->ops.receive = team->mode->ops->receive;
+}
+
+/*
+ * We can benefit from the fact that it's ensured no port is present
+ * at the time of mode change. Therefore no packets are in fly so there's no
+ * need to set mode operations in any special way.
+ */
+static int __team_change_mode(struct team *team,
+                             const struct team_mode *new_mode)
+{
+       /* Check if mode was previously set and do cleanup if so */
+       if (team->mode) {
+               void (*exit_op)(struct team *team) = team->ops.exit;
+
+               /* Clear ops area so no callback is called any longer */
+               memset(&team->ops, 0, sizeof(struct team_mode_ops));
+               team_adjust_ops(team);
+
+               if (exit_op)
+                       exit_op(team);
+               team_mode_put(team->mode);
+               team->mode = NULL;
+               /* zero private data area */
+               memset(&team->mode_priv, 0,
+                      sizeof(struct team) - offsetof(struct team, mode_priv));
+       }
+
+       if (!new_mode)
+               return 0;
+
+       if (new_mode->ops->init) {
+               int err;
+
+               err = new_mode->ops->init(team);
+               if (err)
+                       return err;
+       }
+
+       team->mode = new_mode;
+       memcpy(&team->ops, new_mode->ops, sizeof(struct team_mode_ops));
+       team_adjust_ops(team);
+
+       return 0;
+}
+
+static int team_change_mode(struct team *team, const char *kind)
+{
+       struct team_mode *new_mode;
+       struct net_device *dev = team->dev;
+       int err;
+
+       if (!list_empty(&team->port_list)) {
+               netdev_err(dev, "No ports can be present during mode change\n");
+               return -EBUSY;
+       }
+
+       if (team->mode && strcmp(team->mode->kind, kind) == 0) {
+               netdev_err(dev, "Unable to change to the same mode the team is in\n");
+               return -EINVAL;
+       }
+
+       new_mode = team_mode_get(kind);
+       if (!new_mode) {
+               netdev_err(dev, "Mode \"%s\" not found\n", kind);
+               return -EINVAL;
+       }
+
+       err = __team_change_mode(team, new_mode);
+       if (err) {
+               netdev_err(dev, "Failed to change to mode \"%s\"\n", kind);
+               team_mode_put(new_mode);
+               return err;
+       }
+
+       netdev_info(dev, "Mode changed to \"%s\"\n", kind);
+       return 0;
+}
+
+
+/************************
+ * Rx path frame handler
+ ************************/
+
+/* note: already called with rcu_read_lock */
+static rx_handler_result_t team_handle_frame(struct sk_buff **pskb)
+{
+       struct sk_buff *skb = *pskb;
+       struct team_port *port;
+       struct team *team;
+       rx_handler_result_t res;
+
+       skb = skb_share_check(skb, GFP_ATOMIC);
+       if (!skb)
+               return RX_HANDLER_CONSUMED;
+
+       *pskb = skb;
+
+       port = team_port_get_rcu(skb->dev);
+       team = port->team;
+
+       res = team->ops.receive(team, port, skb);
+       if (res == RX_HANDLER_ANOTHER) {
+               struct team_pcpu_stats *pcpu_stats;
+
+               pcpu_stats = this_cpu_ptr(team->pcpu_stats);
+               u64_stats_update_begin(&pcpu_stats->syncp);
+               pcpu_stats->rx_packets++;
+               pcpu_stats->rx_bytes += skb->len;
+               if (skb->pkt_type == PACKET_MULTICAST)
+                       pcpu_stats->rx_multicast++;
+               u64_stats_update_end(&pcpu_stats->syncp);
+
+               skb->dev = team->dev;
+       } else {
+               this_cpu_inc(team->pcpu_stats->rx_dropped);
+       }
+
+       return res;
+}
+
+
+/****************
+ * Port handling
+ ****************/
+
+static bool team_port_find(const struct team *team,
+                          const struct team_port *port)
+{
+       struct team_port *cur;
+
+       list_for_each_entry(cur, &team->port_list, list)
+               if (cur == port)
+                       return true;
+       return false;
+}
+
+/*
+ * Add/delete port to the team port list. Write guarded by rtnl_lock.
+ * Takes care of correct port->index setup (might be racy).
+ */
+static void team_port_list_add_port(struct team *team,
+                                   struct team_port *port)
+{
+       port->index = team->port_count++;
+       hlist_add_head_rcu(&port->hlist,
+                          team_port_index_hash(team, port->index));
+       list_add_tail_rcu(&port->list, &team->port_list);
+}
+
+static void __reconstruct_port_hlist(struct team *team, int rm_index)
+{
+       int i;
+       struct team_port *port;
+
+       for (i = rm_index + 1; i < team->port_count; i++) {
+               port = team_get_port_by_index(team, i);
+               hlist_del_rcu(&port->hlist);
+               port->index--;
+               hlist_add_head_rcu(&port->hlist,
+                                  team_port_index_hash(team, port->index));
+       }
+}
+
+static void team_port_list_del_port(struct team *team,
+                                  struct team_port *port)
+{
+       int rm_index = port->index;
+
+       hlist_del_rcu(&port->hlist);
+       list_del_rcu(&port->list);
+       __reconstruct_port_hlist(team, rm_index);
+       team->port_count--;
+}
+
+#define TEAM_VLAN_FEATURES (NETIF_F_ALL_CSUM | NETIF_F_SG | \
+                           NETIF_F_FRAGLIST | NETIF_F_ALL_TSO | \
+                           NETIF_F_HIGHDMA | NETIF_F_LRO)
+
+static void __team_compute_features(struct team *team)
+{
+       struct team_port *port;
+       u32 vlan_features = TEAM_VLAN_FEATURES;
+       unsigned short max_hard_header_len = ETH_HLEN;
+
+       list_for_each_entry(port, &team->port_list, list) {
+               vlan_features = netdev_increment_features(vlan_features,
+                                       port->dev->vlan_features,
+                                       TEAM_VLAN_FEATURES);
+
+               if (port->dev->hard_header_len > max_hard_header_len)
+                       max_hard_header_len = port->dev->hard_header_len;
+       }
+
+       team->dev->vlan_features = vlan_features;
+       team->dev->hard_header_len = max_hard_header_len;
+
+       netdev_change_features(team->dev);
+}
+
+static void team_compute_features(struct team *team)
+{
+       mutex_lock(&team->lock);
+       __team_compute_features(team);
+       mutex_unlock(&team->lock);
+}
+
+static int team_port_enter(struct team *team, struct team_port *port)
+{
+       int err = 0;
+
+       dev_hold(team->dev);
+       port->dev->priv_flags |= IFF_TEAM_PORT;
+       if (team->ops.port_enter) {
+               err = team->ops.port_enter(team, port);
+               if (err) {
+                       netdev_err(team->dev, "Device %s failed to enter team mode\n",
+                                  port->dev->name);
+                       goto err_port_enter;
+               }
+       }
+
+       return 0;
+
+err_port_enter:
+       port->dev->priv_flags &= ~IFF_TEAM_PORT;
+       dev_put(team->dev);
+
+       return err;
+}
+
+static void team_port_leave(struct team *team, struct team_port *port)
+{
+       if (team->ops.port_leave)
+               team->ops.port_leave(team, port);
+       port->dev->priv_flags &= ~IFF_TEAM_PORT;
+       dev_put(team->dev);
+}
+
+static void __team_port_change_check(struct team_port *port, bool linkup);
+
+static int team_port_add(struct team *team, struct net_device *port_dev)
+{
+       struct net_device *dev = team->dev;
+       struct team_port *port;
+       char *portname = port_dev->name;
+       int err;
+
+       if (port_dev->flags & IFF_LOOPBACK ||
+           port_dev->type != ARPHRD_ETHER) {
+               netdev_err(dev, "Device %s is of an unsupported type\n",
+                          portname);
+               return -EINVAL;
+       }
+
+       if (team_port_exists(port_dev)) {
+               netdev_err(dev, "Device %s is already a port "
+                               "of a team device\n", portname);
+               return -EBUSY;
+       }
+
+       if (port_dev->flags & IFF_UP) {
+               netdev_err(dev, "Device %s is up. Set it down before adding it as a team port\n",
+                          portname);
+               return -EBUSY;
+       }
+
+       port = kzalloc(sizeof(struct team_port), GFP_KERNEL);
+       if (!port)
+               return -ENOMEM;
+
+       port->dev = port_dev;
+       port->team = team;
+
+       port->orig.mtu = port_dev->mtu;
+       err = dev_set_mtu(port_dev, dev->mtu);
+       if (err) {
+               netdev_dbg(dev, "Error %d calling dev_set_mtu\n", err);
+               goto err_set_mtu;
+       }
+
+       memcpy(port->orig.dev_addr, port_dev->dev_addr, ETH_ALEN);
+
+       err = team_port_enter(team, port);
+       if (err) {
+               netdev_err(dev, "Device %s failed to enter team mode\n",
+                          portname);
+               goto err_port_enter;
+       }
+
+       err = dev_open(port_dev);
+       if (err) {
+               netdev_dbg(dev, "Device %s opening failed\n",
+                          portname);
+               goto err_dev_open;
+       }
+
+       err = netdev_set_master(port_dev, dev);
+       if (err) {
+               netdev_err(dev, "Device %s failed to set master\n", portname);
+               goto err_set_master;
+       }
+
+       err = netdev_rx_handler_register(port_dev, team_handle_frame,
+                                        port);
+       if (err) {
+               netdev_err(dev, "Device %s failed to register rx_handler\n",
+                          portname);
+               goto err_handler_register;
+       }
+
+       team_port_list_add_port(team, port);
+       team_adjust_ops(team);
+       __team_compute_features(team);
+       __team_port_change_check(port, !!netif_carrier_ok(port_dev));
+
+       netdev_info(dev, "Port device %s added\n", portname);
+
+       return 0;
+
+err_handler_register:
+       netdev_set_master(port_dev, NULL);
+
+err_set_master:
+       dev_close(port_dev);
+
+err_dev_open:
+       team_port_leave(team, port);
+       team_port_set_orig_mac(port);
+
+err_port_enter:
+       dev_set_mtu(port_dev, port->orig.mtu);
+
+err_set_mtu:
+       kfree(port);
+
+       return err;
+}
+
+static int team_port_del(struct team *team, struct net_device *port_dev)
+{
+       struct net_device *dev = team->dev;
+       struct team_port *port;
+       char *portname = port_dev->name;
+
+       port = team_port_get_rtnl(port_dev);
+       if (!port || !team_port_find(team, port)) {
+               netdev_err(dev, "Device %s does not act as a port of this team\n",
+                          portname);
+               return -ENOENT;
+       }
+
+       __team_port_change_check(port, false);
+       team_port_list_del_port(team, port);
+       team_adjust_ops(team);
+       netdev_rx_handler_unregister(port_dev);
+       netdev_set_master(port_dev, NULL);
+       dev_close(port_dev);
+       team_port_leave(team, port);
+       team_port_set_orig_mac(port);
+       dev_set_mtu(port_dev, port->orig.mtu);
+       synchronize_rcu();
+       kfree(port);
+       netdev_info(dev, "Port device %s removed\n", portname);
+       __team_compute_features(team);
+
+       return 0;
+}
+
+
+/*****************
+ * Net device ops
+ *****************/
+
+static const char team_no_mode_kind[] = "*NOMODE*";
+
+static int team_mode_option_get(struct team *team, void *arg)
+{
+       const char **str = arg;
+
+       *str = team->mode ? team->mode->kind : team_no_mode_kind;
+       return 0;
+}
+
+static int team_mode_option_set(struct team *team, void *arg)
+{
+       const char **str = arg;
+
+       return team_change_mode(team, *str);
+}
+
+static const struct team_option team_options[] = {
+       {
+               .name = "mode",
+               .type = TEAM_OPTION_TYPE_STRING,
+               .getter = team_mode_option_get,
+               .setter = team_mode_option_set,
+       },
+};
+
+static int team_init(struct net_device *dev)
+{
+       struct team *team = netdev_priv(dev);
+       int i;
+       int err;
+
+       team->dev = dev;
+       mutex_init(&team->lock);
+
+       team->pcpu_stats = alloc_percpu(struct team_pcpu_stats);
+       if (!team->pcpu_stats)
+               return -ENOMEM;
+
+       for (i = 0; i < TEAM_PORT_HASHENTRIES; i++)
+               INIT_HLIST_HEAD(&team->port_hlist[i]);
+       INIT_LIST_HEAD(&team->port_list);
+
+       team_adjust_ops(team);
+
+       INIT_LIST_HEAD(&team->option_list);
+       err = team_options_register(team, team_options, ARRAY_SIZE(team_options));
+       if (err)
+               goto err_options_register;
+       netif_carrier_off(dev);
+
+       return 0;
+
+err_options_register:
+       free_percpu(team->pcpu_stats);
+
+       return err;
+}
+
+static void team_uninit(struct net_device *dev)
+{
+       struct team *team = netdev_priv(dev);
+       struct team_port *port;
+       struct team_port *tmp;
+
+       mutex_lock(&team->lock);
+       list_for_each_entry_safe(port, tmp, &team->port_list, list)
+               team_port_del(team, port->dev);
+
+       __team_change_mode(team, NULL); /* cleanup */
+       __team_options_unregister(team, team_options, ARRAY_SIZE(team_options));
+       mutex_unlock(&team->lock);
+}
+
+static void team_destructor(struct net_device *dev)
+{
+       struct team *team = netdev_priv(dev);
+
+       free_percpu(team->pcpu_stats);
+       free_netdev(dev);
+}
+
+static int team_open(struct net_device *dev)
+{
+       netif_carrier_on(dev);
+       return 0;
+}
+
+static int team_close(struct net_device *dev)
+{
+       netif_carrier_off(dev);
+       return 0;
+}
+
+/*
+ * note: already called with rcu_read_lock
+ */
+static netdev_tx_t team_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct team *team = netdev_priv(dev);
+       bool tx_success = false;
+       unsigned int len = skb->len;
+
+       tx_success = team->ops.transmit(team, skb);
+       if (tx_success) {
+               struct team_pcpu_stats *pcpu_stats;
+
+               pcpu_stats = this_cpu_ptr(team->pcpu_stats);
+               u64_stats_update_begin(&pcpu_stats->syncp);
+               pcpu_stats->tx_packets++;
+               pcpu_stats->tx_bytes += len;
+               u64_stats_update_end(&pcpu_stats->syncp);
+       } else {
+               this_cpu_inc(team->pcpu_stats->tx_dropped);
+       }
+
+       return NETDEV_TX_OK;
+}
+
+static void team_change_rx_flags(struct net_device *dev, int change)
+{
+       struct team *team = netdev_priv(dev);
+       struct team_port *port;
+       int inc;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(port, &team->port_list, list) {
+               if (change & IFF_PROMISC) {
+                       inc = dev->flags & IFF_PROMISC ? 1 : -1;
+                       dev_set_promiscuity(port->dev, inc);
+               }
+               if (change & IFF_ALLMULTI) {
+                       inc = dev->flags & IFF_ALLMULTI ? 1 : -1;
+                       dev_set_allmulti(port->dev, inc);
+               }
+       }
+       rcu_read_unlock();
+}
+
+static void team_set_rx_mode(struct net_device *dev)
+{
+       struct team *team = netdev_priv(dev);
+       struct team_port *port;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(port, &team->port_list, list) {
+               dev_uc_sync(port->dev, dev);
+               dev_mc_sync(port->dev, dev);
+       }
+       rcu_read_unlock();
+}
+
+static int team_set_mac_address(struct net_device *dev, void *p)
+{
+       struct team *team = netdev_priv(dev);
+       struct team_port *port;
+       struct sockaddr *addr = p;
+
+       memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
+       rcu_read_lock();
+       list_for_each_entry_rcu(port, &team->port_list, list)
+               if (team->ops.port_change_mac)
+                       team->ops.port_change_mac(team, port);
+       rcu_read_unlock();
+       return 0;
+}
+
+static int team_change_mtu(struct net_device *dev, int new_mtu)
+{
+       struct team *team = netdev_priv(dev);
+       struct team_port *port;
+       int err;
+
+       /*
+        * Alhough this is reader, it's guarded by team lock. It's not possible
+        * to traverse list in reverse under rcu_read_lock
+        */
+       mutex_lock(&team->lock);
+       list_for_each_entry(port, &team->port_list, list) {
+               err = dev_set_mtu(port->dev, new_mtu);
+               if (err) {
+                       netdev_err(dev, "Device %s failed to change mtu",
+                                  port->dev->name);
+                       goto unwind;
+               }
+       }
+       mutex_unlock(&team->lock);
+
+       dev->mtu = new_mtu;
+
+       return 0;
+
+unwind:
+       list_for_each_entry_continue_reverse(port, &team->port_list, list)
+               dev_set_mtu(port->dev, dev->mtu);
+       mutex_unlock(&team->lock);
+
+       return err;
+}
+
+static struct rtnl_link_stats64 *
+team_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
+{
+       struct team *team = netdev_priv(dev);
+       struct team_pcpu_stats *p;
+       u64 rx_packets, rx_bytes, rx_multicast, tx_packets, tx_bytes;
+       u32 rx_dropped = 0, tx_dropped = 0;
+       unsigned int start;
+       int i;
+
+       for_each_possible_cpu(i) {
+               p = per_cpu_ptr(team->pcpu_stats, i);
+               do {
+                       start = u64_stats_fetch_begin_bh(&p->syncp);
+                       rx_packets      = p->rx_packets;
+                       rx_bytes        = p->rx_bytes;
+                       rx_multicast    = p->rx_multicast;
+                       tx_packets      = p->tx_packets;
+                       tx_bytes        = p->tx_bytes;
+               } while (u64_stats_fetch_retry_bh(&p->syncp, start));
+
+               stats->rx_packets       += rx_packets;
+               stats->rx_bytes         += rx_bytes;
+               stats->multicast        += rx_multicast;
+               stats->tx_packets       += tx_packets;
+               stats->tx_bytes         += tx_bytes;
+               /*
+                * rx_dropped & tx_dropped are u32, updated
+                * without syncp protection.
+                */
+               rx_dropped      += p->rx_dropped;
+               tx_dropped      += p->tx_dropped;
+       }
+       stats->rx_dropped       = rx_dropped;
+       stats->tx_dropped       = tx_dropped;
+       return stats;
+}
+
+static void team_vlan_rx_add_vid(struct net_device *dev, uint16_t vid)
+{
+       struct team *team = netdev_priv(dev);
+       struct team_port *port;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(port, &team->port_list, list) {
+               const struct net_device_ops *ops = port->dev->netdev_ops;
+
+               if (ops->ndo_vlan_rx_add_vid)
+                       ops->ndo_vlan_rx_add_vid(port->dev, vid);
+       }
+       rcu_read_unlock();
+}
+
+static void team_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid)
+{
+       struct team *team = netdev_priv(dev);
+       struct team_port *port;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(port, &team->port_list, list) {
+               const struct net_device_ops *ops = port->dev->netdev_ops;
+
+               if (ops->ndo_vlan_rx_kill_vid)
+                       ops->ndo_vlan_rx_kill_vid(port->dev, vid);
+       }
+       rcu_read_unlock();
+}
+
+static int team_add_slave(struct net_device *dev, struct net_device *port_dev)
+{
+       struct team *team = netdev_priv(dev);
+       int err;
+
+       mutex_lock(&team->lock);
+       err = team_port_add(team, port_dev);
+       mutex_unlock(&team->lock);
+       return err;
+}
+
+static int team_del_slave(struct net_device *dev, struct net_device *port_dev)
+{
+       struct team *team = netdev_priv(dev);
+       int err;
+
+       mutex_lock(&team->lock);
+       err = team_port_del(team, port_dev);
+       mutex_unlock(&team->lock);
+       return err;
+}
+
+static netdev_features_t team_fix_features(struct net_device *dev,
+                                          netdev_features_t features)
+{
+       struct team_port *port;
+       struct team *team = netdev_priv(dev);
+       netdev_features_t mask;
+
+       mask = features;
+       features &= ~NETIF_F_ONE_FOR_ALL;
+       features |= NETIF_F_ALL_FOR_ALL;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(port, &team->port_list, list) {
+               features = netdev_increment_features(features,
+                                                    port->dev->features,
+                                                    mask);
+       }
+       rcu_read_unlock();
+       return features;
+}
+
+static const struct net_device_ops team_netdev_ops = {
+       .ndo_init               = team_init,
+       .ndo_uninit             = team_uninit,
+       .ndo_open               = team_open,
+       .ndo_stop               = team_close,
+       .ndo_start_xmit         = team_xmit,
+       .ndo_change_rx_flags    = team_change_rx_flags,
+       .ndo_set_rx_mode        = team_set_rx_mode,
+       .ndo_set_mac_address    = team_set_mac_address,
+       .ndo_change_mtu         = team_change_mtu,
+       .ndo_get_stats64        = team_get_stats64,
+       .ndo_vlan_rx_add_vid    = team_vlan_rx_add_vid,
+       .ndo_vlan_rx_kill_vid   = team_vlan_rx_kill_vid,
+       .ndo_add_slave          = team_add_slave,
+       .ndo_del_slave          = team_del_slave,
+       .ndo_fix_features       = team_fix_features,
+};
+
+
+/***********************
+ * rt netlink interface
+ ***********************/
+
+static void team_setup(struct net_device *dev)
+{
+       ether_setup(dev);
+
+       dev->netdev_ops = &team_netdev_ops;
+       dev->destructor = team_destructor;
+       dev->tx_queue_len = 0;
+       dev->flags |= IFF_MULTICAST;
+       dev->priv_flags &= ~(IFF_XMIT_DST_RELEASE | IFF_TX_SKB_SHARING);
+
+       /*
+        * Indicate we support unicast address filtering. That way core won't
+        * bring us to promisc mode in case a unicast addr is added.
+        * Let this up to underlay drivers.
+        */
+       dev->priv_flags |= IFF_UNICAST_FLT;
+
+       dev->features |= NETIF_F_LLTX;
+       dev->features |= NETIF_F_GRO;
+       dev->hw_features = NETIF_F_HW_VLAN_TX |
+                          NETIF_F_HW_VLAN_RX |
+                          NETIF_F_HW_VLAN_FILTER;
+
+       dev->features |= dev->hw_features;
+}
+
+static int team_newlink(struct net *src_net, struct net_device *dev,
+                       struct nlattr *tb[], struct nlattr *data[])
+{
+       int err;
+
+       if (tb[IFLA_ADDRESS] == NULL)
+               random_ether_addr(dev->dev_addr);
+
+       err = register_netdevice(dev);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+static int team_validate(struct nlattr *tb[], struct nlattr *data[])
+{
+       if (tb[IFLA_ADDRESS]) {
+               if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
+                       return -EINVAL;
+               if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
+                       return -EADDRNOTAVAIL;
+       }
+       return 0;
+}
+
+static struct rtnl_link_ops team_link_ops __read_mostly = {
+       .kind           = DRV_NAME,
+       .priv_size      = sizeof(struct team),
+       .setup          = team_setup,
+       .newlink        = team_newlink,
+       .validate       = team_validate,
+};
+
+
+/***********************************
+ * Generic netlink custom interface
+ ***********************************/
+
+static struct genl_family team_nl_family = {
+       .id             = GENL_ID_GENERATE,
+       .name           = TEAM_GENL_NAME,
+       .version        = TEAM_GENL_VERSION,
+       .maxattr        = TEAM_ATTR_MAX,
+       .netnsok        = true,
+};
+
+static const struct nla_policy team_nl_policy[TEAM_ATTR_MAX + 1] = {
+       [TEAM_ATTR_UNSPEC]                      = { .type = NLA_UNSPEC, },
+       [TEAM_ATTR_TEAM_IFINDEX]                = { .type = NLA_U32 },
+       [TEAM_ATTR_LIST_OPTION]                 = { .type = NLA_NESTED },
+       [TEAM_ATTR_LIST_PORT]                   = { .type = NLA_NESTED },
+};
+
+static const struct nla_policy
+team_nl_option_policy[TEAM_ATTR_OPTION_MAX + 1] = {
+       [TEAM_ATTR_OPTION_UNSPEC]               = { .type = NLA_UNSPEC, },
+       [TEAM_ATTR_OPTION_NAME] = {
+               .type = NLA_STRING,
+               .len = TEAM_STRING_MAX_LEN,
+       },
+       [TEAM_ATTR_OPTION_CHANGED]              = { .type = NLA_FLAG },
+       [TEAM_ATTR_OPTION_TYPE]                 = { .type = NLA_U8 },
+       [TEAM_ATTR_OPTION_DATA] = {
+               .type = NLA_BINARY,
+               .len = TEAM_STRING_MAX_LEN,
+       },
+};
+
+static int team_nl_cmd_noop(struct sk_buff *skb, struct genl_info *info)
+{
+       struct sk_buff *msg;
+       void *hdr;
+       int err;
+
+       msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
+       hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
+                         &team_nl_family, 0, TEAM_CMD_NOOP);
+       if (IS_ERR(hdr)) {
+               err = PTR_ERR(hdr);
+               goto err_msg_put;
+       }
+
+       genlmsg_end(msg, hdr);
+
+       return genlmsg_unicast(genl_info_net(info), msg, info->snd_pid);
+
+err_msg_put:
+       nlmsg_free(msg);
+
+       return err;
+}
+
+/*
+ * Netlink cmd functions should be locked by following two functions.
+ * Since dev gets held here, that ensures dev won't disappear in between.
+ */
+static struct team *team_nl_team_get(struct genl_info *info)
+{
+       struct net *net = genl_info_net(info);
+       int ifindex;
+       struct net_device *dev;
+       struct team *team;
+
+       if (!info->attrs[TEAM_ATTR_TEAM_IFINDEX])
+               return NULL;
+
+       ifindex = nla_get_u32(info->attrs[TEAM_ATTR_TEAM_IFINDEX]);
+       dev = dev_get_by_index(net, ifindex);
+       if (!dev || dev->netdev_ops != &team_netdev_ops) {
+               if (dev)
+                       dev_put(dev);
+               return NULL;
+       }
+
+       team = netdev_priv(dev);
+       mutex_lock(&team->lock);
+       return team;
+}
+
+static void team_nl_team_put(struct team *team)
+{
+       mutex_unlock(&team->lock);
+       dev_put(team->dev);
+}
+
+static int team_nl_send_generic(struct genl_info *info, struct team *team,
+                               int (*fill_func)(struct sk_buff *skb,
+                                                struct genl_info *info,
+                                                int flags, struct team *team))
+{
+       struct sk_buff *skb;
+       int err;
+
+       skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+       if (!skb)
+               return -ENOMEM;
+
+       err = fill_func(skb, info, NLM_F_ACK, team);
+       if (err < 0)
+               goto err_fill;
+
+       err = genlmsg_unicast(genl_info_net(info), skb, info->snd_pid);
+       return err;
+
+err_fill:
+       nlmsg_free(skb);
+       return err;
+}
+
+static int team_nl_fill_options_get_changed(struct sk_buff *skb,
+                                           u32 pid, u32 seq, int flags,
+                                           struct team *team,
+                                           struct team_option *changed_option)
+{
+       struct nlattr *option_list;
+       void *hdr;
+       struct team_option *option;
+
+       hdr = genlmsg_put(skb, pid, seq, &team_nl_family, flags,
+                         TEAM_CMD_OPTIONS_GET);
+       if (IS_ERR(hdr))
+               return PTR_ERR(hdr);
+
+       NLA_PUT_U32(skb, TEAM_ATTR_TEAM_IFINDEX, team->dev->ifindex);
+       option_list = nla_nest_start(skb, TEAM_ATTR_LIST_OPTION);
+       if (!option_list)
+               return -EMSGSIZE;
+
+       list_for_each_entry(option, &team->option_list, list) {
+               struct nlattr *option_item;
+               long arg;
+
+               option_item = nla_nest_start(skb, TEAM_ATTR_ITEM_OPTION);
+               if (!option_item)
+                       goto nla_put_failure;
+               NLA_PUT_STRING(skb, TEAM_ATTR_OPTION_NAME, option->name);
+               if (option == changed_option)
+                       NLA_PUT_FLAG(skb, TEAM_ATTR_OPTION_CHANGED);
+               switch (option->type) {
+               case TEAM_OPTION_TYPE_U32:
+                       NLA_PUT_U8(skb, TEAM_ATTR_OPTION_TYPE, NLA_U32);
+                       team_option_get(team, option, &arg);
+                       NLA_PUT_U32(skb, TEAM_ATTR_OPTION_DATA, arg);
+                       break;
+               case TEAM_OPTION_TYPE_STRING:
+                       NLA_PUT_U8(skb, TEAM_ATTR_OPTION_TYPE, NLA_STRING);
+                       team_option_get(team, option, &arg);
+                       NLA_PUT_STRING(skb, TEAM_ATTR_OPTION_DATA,
+                                      (char *) arg);
+                       break;
+               default:
+                       BUG();
+               }
+               nla_nest_end(skb, option_item);
+       }
+
+       nla_nest_end(skb, option_list);
+       return genlmsg_end(skb, hdr);
+
+nla_put_failure:
+       genlmsg_cancel(skb, hdr);
+       return -EMSGSIZE;
+}
+
+static int team_nl_fill_options_get(struct sk_buff *skb,
+                                   struct genl_info *info, int flags,
+                                   struct team *team)
+{
+       return team_nl_fill_options_get_changed(skb, info->snd_pid,
+                                               info->snd_seq, NLM_F_ACK,
+                                               team, NULL);
+}
+
+static int team_nl_cmd_options_get(struct sk_buff *skb, struct genl_info *info)
+{
+       struct team *team;
+       int err;
+
+       team = team_nl_team_get(info);
+       if (!team)
+               return -EINVAL;
+
+       err = team_nl_send_generic(info, team, team_nl_fill_options_get);
+
+       team_nl_team_put(team);
+
+       return err;
+}
+
+static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info)
+{
+       struct team *team;
+       int err = 0;
+       int i;
+       struct nlattr *nl_option;
+
+       team = team_nl_team_get(info);
+       if (!team)
+               return -EINVAL;
+
+       err = -EINVAL;
+       if (!info->attrs[TEAM_ATTR_LIST_OPTION]) {
+               err = -EINVAL;
+               goto team_put;
+       }
+
+       nla_for_each_nested(nl_option, info->attrs[TEAM_ATTR_LIST_OPTION], i) {
+               struct nlattr *mode_attrs[TEAM_ATTR_OPTION_MAX + 1];
+               enum team_option_type opt_type;
+               struct team_option *option;
+               char *opt_name;
+               bool opt_found = false;
+
+               if (nla_type(nl_option) != TEAM_ATTR_ITEM_OPTION) {
+                       err = -EINVAL;
+                       goto team_put;
+               }
+               err = nla_parse_nested(mode_attrs, TEAM_ATTR_OPTION_MAX,
+                                      nl_option, team_nl_option_policy);
+               if (err)
+                       goto team_put;
+               if (!mode_attrs[TEAM_ATTR_OPTION_NAME] ||
+                   !mode_attrs[TEAM_ATTR_OPTION_TYPE] ||
+                   !mode_attrs[TEAM_ATTR_OPTION_DATA]) {
+                       err = -EINVAL;
+                       goto team_put;
+               }
+               switch (nla_get_u8(mode_attrs[TEAM_ATTR_OPTION_TYPE])) {
+               case NLA_U32:
+                       opt_type = TEAM_OPTION_TYPE_U32;
+                       break;
+               case NLA_STRING:
+                       opt_type = TEAM_OPTION_TYPE_STRING;
+                       break;
+               default:
+                       goto team_put;
+               }
+
+               opt_name = nla_data(mode_attrs[TEAM_ATTR_OPTION_NAME]);
+               list_for_each_entry(option, &team->option_list, list) {
+                       long arg;
+                       struct nlattr *opt_data_attr;
+
+                       if (option->type != opt_type ||
+                           strcmp(option->name, opt_name))
+                               continue;
+                       opt_found = true;
+                       opt_data_attr = mode_attrs[TEAM_ATTR_OPTION_DATA];
+                       switch (opt_type) {
+                       case TEAM_OPTION_TYPE_U32:
+                               arg = nla_get_u32(opt_data_attr);
+                               break;
+                       case TEAM_OPTION_TYPE_STRING:
+                               arg = (long) nla_data(opt_data_attr);
+                               break;
+                       default:
+                               BUG();
+                       }
+                       err = team_option_set(team, option, &arg);
+                       if (err)
+                               goto team_put;
+               }
+               if (!opt_found) {
+                       err = -ENOENT;
+                       goto team_put;
+               }
+       }
+
+team_put:
+       team_nl_team_put(team);
+
+       return err;
+}
+
+static int team_nl_fill_port_list_get_changed(struct sk_buff *skb,
+                                             u32 pid, u32 seq, int flags,
+                                             struct team *team,
+                                             struct team_port *changed_port)
+{
+       struct nlattr *port_list;
+       void *hdr;
+       struct team_port *port;
+
+       hdr = genlmsg_put(skb, pid, seq, &team_nl_family, flags,
+                         TEAM_CMD_PORT_LIST_GET);
+       if (IS_ERR(hdr))
+               return PTR_ERR(hdr);
+
+       NLA_PUT_U32(skb, TEAM_ATTR_TEAM_IFINDEX, team->dev->ifindex);
+       port_list = nla_nest_start(skb, TEAM_ATTR_LIST_PORT);
+       if (!port_list)
+               return -EMSGSIZE;
+
+       list_for_each_entry(port, &team->port_list, list) {
+               struct nlattr *port_item;
+
+               port_item = nla_nest_start(skb, TEAM_ATTR_ITEM_PORT);
+               if (!port_item)
+                       goto nla_put_failure;
+               NLA_PUT_U32(skb, TEAM_ATTR_PORT_IFINDEX, port->dev->ifindex);
+               if (port == changed_port)
+                       NLA_PUT_FLAG(skb, TEAM_ATTR_PORT_CHANGED);
+               if (port->linkup)
+                       NLA_PUT_FLAG(skb, TEAM_ATTR_PORT_LINKUP);
+               NLA_PUT_U32(skb, TEAM_ATTR_PORT_SPEED, port->speed);
+               NLA_PUT_U8(skb, TEAM_ATTR_PORT_DUPLEX, port->duplex);
+               nla_nest_end(skb, port_item);
+       }
+
+       nla_nest_end(skb, port_list);
+       return genlmsg_end(skb, hdr);
+
+nla_put_failure:
+       genlmsg_cancel(skb, hdr);
+       return -EMSGSIZE;
+}
+
+static int team_nl_fill_port_list_get(struct sk_buff *skb,
+                                     struct genl_info *info, int flags,
+                                     struct team *team)
+{
+       return team_nl_fill_port_list_get_changed(skb, info->snd_pid,
+                                                 info->snd_seq, NLM_F_ACK,
+                                                 team, NULL);
+}
+
+static int team_nl_cmd_port_list_get(struct sk_buff *skb,
+                                    struct genl_info *info)
+{
+       struct team *team;
+       int err;
+
+       team = team_nl_team_get(info);
+       if (!team)
+               return -EINVAL;
+
+       err = team_nl_send_generic(info, team, team_nl_fill_port_list_get);
+
+       team_nl_team_put(team);
+
+       return err;
+}
+
+static struct genl_ops team_nl_ops[] = {
+       {
+               .cmd = TEAM_CMD_NOOP,
+               .doit = team_nl_cmd_noop,
+               .policy = team_nl_policy,
+       },
+       {
+               .cmd = TEAM_CMD_OPTIONS_SET,
+               .doit = team_nl_cmd_options_set,
+               .policy = team_nl_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = TEAM_CMD_OPTIONS_GET,
+               .doit = team_nl_cmd_options_get,
+               .policy = team_nl_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = TEAM_CMD_PORT_LIST_GET,
+               .doit = team_nl_cmd_port_list_get,
+               .policy = team_nl_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+};
+
+static struct genl_multicast_group team_change_event_mcgrp = {
+       .name = TEAM_GENL_CHANGE_EVENT_MC_GRP_NAME,
+};
+
+static int team_nl_send_event_options_get(struct team *team,
+                                         struct team_option *changed_option)
+{
+       struct sk_buff *skb;
+       int err;
+       struct net *net = dev_net(team->dev);
+
+       skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+       if (!skb)
+               return -ENOMEM;
+
+       err = team_nl_fill_options_get_changed(skb, 0, 0, 0, team,
+                                              changed_option);
+       if (err < 0)
+               goto err_fill;
+
+       err = genlmsg_multicast_netns(net, skb, 0, team_change_event_mcgrp.id,
+                                     GFP_KERNEL);
+       return err;
+
+err_fill:
+       nlmsg_free(skb);
+       return err;
+}
+
+static int team_nl_send_event_port_list_get(struct team_port *port)
+{
+       struct sk_buff *skb;
+       int err;
+       struct net *net = dev_net(port->team->dev);
+
+       skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+       if (!skb)
+               return -ENOMEM;
+
+       err = team_nl_fill_port_list_get_changed(skb, 0, 0, 0,
+                                                port->team, port);
+       if (err < 0)
+               goto err_fill;
+
+       err = genlmsg_multicast_netns(net, skb, 0, team_change_event_mcgrp.id,
+                                     GFP_KERNEL);
+       return err;
+
+err_fill:
+       nlmsg_free(skb);
+       return err;
+}
+
+static int team_nl_init(void)
+{
+       int err;
+
+       err = genl_register_family_with_ops(&team_nl_family, team_nl_ops,
+                                           ARRAY_SIZE(team_nl_ops));
+       if (err)
+               return err;
+
+       err = genl_register_mc_group(&team_nl_family, &team_change_event_mcgrp);
+       if (err)
+               goto err_change_event_grp_reg;
+
+       return 0;
+
+err_change_event_grp_reg:
+       genl_unregister_family(&team_nl_family);
+
+       return err;
+}
+
+static void team_nl_fini(void)
+{
+       genl_unregister_family(&team_nl_family);
+}
+
+
+/******************
+ * Change checkers
+ ******************/
+
+static void __team_options_change_check(struct team *team,
+                                       struct team_option *changed_option)
+{
+       int err;
+
+       err = team_nl_send_event_options_get(team, changed_option);
+       if (err)
+               netdev_warn(team->dev, "Failed to send options change via netlink\n");
+}
+
+/* rtnl lock is held */
+static void __team_port_change_check(struct team_port *port, bool linkup)
+{
+       int err;
+
+       if (port->linkup == linkup)
+               return;
+
+       port->linkup = linkup;
+       if (linkup) {
+               struct ethtool_cmd ecmd;
+
+               err = __ethtool_get_settings(port->dev, &ecmd);
+               if (!err) {
+                       port->speed = ethtool_cmd_speed(&ecmd);
+                       port->duplex = ecmd.duplex;
+                       goto send_event;
+               }
+       }
+       port->speed = 0;
+       port->duplex = 0;
+
+send_event:
+       err = team_nl_send_event_port_list_get(port);
+       if (err)
+               netdev_warn(port->team->dev, "Failed to send port change of device %s via netlink\n",
+                           port->dev->name);
+
+}
+
+static void team_port_change_check(struct team_port *port, bool linkup)
+{
+       struct team *team = port->team;
+
+       mutex_lock(&team->lock);
+       __team_port_change_check(port, linkup);
+       mutex_unlock(&team->lock);
+}
+
+/************************************
+ * Net device notifier event handler
+ ************************************/
+
+static int team_device_event(struct notifier_block *unused,
+                            unsigned long event, void *ptr)
+{
+       struct net_device *dev = (struct net_device *) ptr;
+       struct team_port *port;
+
+       port = team_port_get_rtnl(dev);
+       if (!port)
+               return NOTIFY_DONE;
+
+       switch (event) {
+       case NETDEV_UP:
+               if (netif_carrier_ok(dev))
+                       team_port_change_check(port, true);
+       case NETDEV_DOWN:
+               team_port_change_check(port, false);
+       case NETDEV_CHANGE:
+               if (netif_running(port->dev))
+                       team_port_change_check(port,
+                                              !!netif_carrier_ok(port->dev));
+               break;
+       case NETDEV_UNREGISTER:
+               team_del_slave(port->team->dev, dev);
+               break;
+       case NETDEV_FEAT_CHANGE:
+               team_compute_features(port->team);
+               break;
+       case NETDEV_CHANGEMTU:
+               /* Forbid to change mtu of underlaying device */
+               return NOTIFY_BAD;
+       case NETDEV_PRE_TYPE_CHANGE:
+               /* Forbid to change type of underlaying device */
+               return NOTIFY_BAD;
+       }
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block team_notifier_block __read_mostly = {
+       .notifier_call = team_device_event,
+};
+
+
+/***********************
+ * Module init and exit
+ ***********************/
+
+static int __init team_module_init(void)
+{
+       int err;
+
+       register_netdevice_notifier(&team_notifier_block);
+
+       err = rtnl_link_register(&team_link_ops);
+       if (err)
+               goto err_rtnl_reg;
+
+       err = team_nl_init();
+       if (err)
+               goto err_nl_init;
+
+       return 0;
+
+err_nl_init:
+       rtnl_link_unregister(&team_link_ops);
+
+err_rtnl_reg:
+       unregister_netdevice_notifier(&team_notifier_block);
+
+       return err;
+}
+
+static void __exit team_module_exit(void)
+{
+       team_nl_fini();
+       rtnl_link_unregister(&team_link_ops);
+       unregister_netdevice_notifier(&team_notifier_block);
+}
+
+module_init(team_module_init);
+module_exit(team_module_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Jiri Pirko <jpirko@redhat.com>");
+MODULE_DESCRIPTION("Ethernet team device driver");
+MODULE_ALIAS_RTNL_LINK(DRV_NAME);
diff --git a/drivers/net/team/team_mode_activebackup.c b/drivers/net/team/team_mode_activebackup.c
new file mode 100644 (file)
index 0000000..f4d960e
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * net/drivers/team/team_mode_activebackup.c - Active-backup mode for team
+ * Copyright (c) 2011 Jiri Pirko <jpirko@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 <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <net/rtnetlink.h>
+#include <linux/if_team.h>
+
+struct ab_priv {
+       struct team_port __rcu *active_port;
+};
+
+static struct ab_priv *ab_priv(struct team *team)
+{
+       return (struct ab_priv *) &team->mode_priv;
+}
+
+static rx_handler_result_t ab_receive(struct team *team, struct team_port *port,
+                                     struct sk_buff *skb) {
+       struct team_port *active_port;
+
+       active_port = rcu_dereference(ab_priv(team)->active_port);
+       if (active_port != port)
+               return RX_HANDLER_EXACT;
+       return RX_HANDLER_ANOTHER;
+}
+
+static bool ab_transmit(struct team *team, struct sk_buff *skb)
+{
+       struct team_port *active_port;
+
+       active_port = rcu_dereference(ab_priv(team)->active_port);
+       if (unlikely(!active_port))
+               goto drop;
+       skb->dev = active_port->dev;
+       if (dev_queue_xmit(skb))
+               return false;
+       return true;
+
+drop:
+       dev_kfree_skb_any(skb);
+       return false;
+}
+
+static void ab_port_leave(struct team *team, struct team_port *port)
+{
+       if (ab_priv(team)->active_port == port)
+               RCU_INIT_POINTER(ab_priv(team)->active_port, NULL);
+}
+
+static int ab_active_port_get(struct team *team, void *arg)
+{
+       u32 *ifindex = arg;
+
+       *ifindex = 0;
+       if (ab_priv(team)->active_port)
+               *ifindex = ab_priv(team)->active_port->dev->ifindex;
+       return 0;
+}
+
+static int ab_active_port_set(struct team *team, void *arg)
+{
+       u32 *ifindex = arg;
+       struct team_port *port;
+
+       list_for_each_entry_rcu(port, &team->port_list, list) {
+               if (port->dev->ifindex == *ifindex) {
+                       rcu_assign_pointer(ab_priv(team)->active_port, port);
+                       return 0;
+               }
+       }
+       return -ENOENT;
+}
+
+static const struct team_option ab_options[] = {
+       {
+               .name = "activeport",
+               .type = TEAM_OPTION_TYPE_U32,
+               .getter = ab_active_port_get,
+               .setter = ab_active_port_set,
+       },
+};
+
+int ab_init(struct team *team)
+{
+       return team_options_register(team, ab_options, ARRAY_SIZE(ab_options));
+}
+
+void ab_exit(struct team *team)
+{
+       team_options_unregister(team, ab_options, ARRAY_SIZE(ab_options));
+}
+
+static const struct team_mode_ops ab_mode_ops = {
+       .init                   = ab_init,
+       .exit                   = ab_exit,
+       .receive                = ab_receive,
+       .transmit               = ab_transmit,
+       .port_leave             = ab_port_leave,
+};
+
+static struct team_mode ab_mode = {
+       .kind           = "activebackup",
+       .owner          = THIS_MODULE,
+       .priv_size      = sizeof(struct ab_priv),
+       .ops            = &ab_mode_ops,
+};
+
+static int __init ab_init_module(void)
+{
+       return team_mode_register(&ab_mode);
+}
+
+static void __exit ab_cleanup_module(void)
+{
+       team_mode_unregister(&ab_mode);
+}
+
+module_init(ab_init_module);
+module_exit(ab_cleanup_module);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Jiri Pirko <jpirko@redhat.com>");
+MODULE_DESCRIPTION("Active-backup mode for team");
+MODULE_ALIAS("team-mode-activebackup");
diff --git a/drivers/net/team/team_mode_roundrobin.c b/drivers/net/team/team_mode_roundrobin.c
new file mode 100644 (file)
index 0000000..a0e8f80
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * net/drivers/team/team_mode_roundrobin.c - Round-robin mode for team
+ * Copyright (c) 2011 Jiri Pirko <jpirko@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 <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/if_team.h>
+
+struct rr_priv {
+       unsigned int sent_packets;
+};
+
+static struct rr_priv *rr_priv(struct team *team)
+{
+       return (struct rr_priv *) &team->mode_priv;
+}
+
+static struct team_port *__get_first_port_up(struct team *team,
+                                            struct team_port *port)
+{
+       struct team_port *cur;
+
+       if (port->linkup)
+               return port;
+       cur = port;
+       list_for_each_entry_continue_rcu(cur, &team->port_list, list)
+               if (cur->linkup)
+                       return cur;
+       list_for_each_entry_rcu(cur, &team->port_list, list) {
+               if (cur == port)
+                       break;
+               if (cur->linkup)
+                       return cur;
+       }
+       return NULL;
+}
+
+static bool rr_transmit(struct team *team, struct sk_buff *skb)
+{
+       struct team_port *port;
+       int port_index;
+
+       port_index = rr_priv(team)->sent_packets++ % team->port_count;
+       port = team_get_port_by_index_rcu(team, port_index);
+       port = __get_first_port_up(team, port);
+       if (unlikely(!port))
+               goto drop;
+       skb->dev = port->dev;
+       if (dev_queue_xmit(skb))
+               return false;
+       return true;
+
+drop:
+       dev_kfree_skb_any(skb);
+       return false;
+}
+
+static int rr_port_enter(struct team *team, struct team_port *port)
+{
+       return team_port_set_team_mac(port);
+}
+
+static void rr_port_change_mac(struct team *team, struct team_port *port)
+{
+       team_port_set_team_mac(port);
+}
+
+static const struct team_mode_ops rr_mode_ops = {
+       .transmit               = rr_transmit,
+       .port_enter             = rr_port_enter,
+       .port_change_mac        = rr_port_change_mac,
+};
+
+static struct team_mode rr_mode = {
+       .kind           = "roundrobin",
+       .owner          = THIS_MODULE,
+       .priv_size      = sizeof(struct rr_priv),
+       .ops            = &rr_mode_ops,
+};
+
+static int __init rr_init_module(void)
+{
+       return team_mode_register(&rr_mode);
+}
+
+static void __exit rr_cleanup_module(void)
+{
+       team_mode_unregister(&rr_mode);
+}
+
+module_init(rr_init_module);
+module_exit(rr_cleanup_module);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Jiri Pirko <jpirko@redhat.com>");
+MODULE_DESCRIPTION("Round-robin mode for team");
+MODULE_ALIAS("team-mode-roundrobin");
index 7bea9c6..93c5d72 100644 (file)
@@ -123,7 +123,7 @@ struct tun_struct {
        gid_t                   group;
 
        struct net_device       *dev;
-       u32                     set_features;
+       netdev_features_t       set_features;
 #define TUN_USER_FEATURES (NETIF_F_HW_CSUM|NETIF_F_TSO_ECN|NETIF_F_TSO| \
                          NETIF_F_TSO6|NETIF_F_UFO)
        struct fasync_struct    *fasync;
@@ -454,7 +454,8 @@ tun_net_change_mtu(struct net_device *dev, int new_mtu)
        return 0;
 }
 
-static u32 tun_net_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t tun_net_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        struct tun_struct *tun = netdev_priv(dev);
 
@@ -1196,7 +1197,7 @@ static int tun_get_iff(struct net *net, struct tun_struct *tun,
  * privs required. */
 static int set_offload(struct tun_struct *tun, unsigned long arg)
 {
-       u32 features = 0;
+       netdev_features_t features = 0;
 
        if (arg & TUN_F_CSUM) {
                features |= NETIF_F_HW_CSUM;
@@ -1589,16 +1590,15 @@ static void tun_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info
 {
        struct tun_struct *tun = netdev_priv(dev);
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->fw_version, "N/A");
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
 
        switch (tun->flags & TUN_TYPE_MASK) {
        case TUN_TUN_DEV:
-               strcpy(info->bus_info, "tun");
+               strlcpy(info->bus_info, "tun", sizeof(info->bus_info));
                break;
        case TUN_TAP_DEV:
-               strcpy(info->bus_info, "tap");
+               strlcpy(info->bus_info, "tap", sizeof(info->bus_info));
                break;
        }
 }
index e81e22e..e6fed4d 100644 (file)
@@ -36,7 +36,7 @@
 #include <linux/usb/usbnet.h>
 #include <linux/slab.h>
 
-#define DRIVER_VERSION "26-Sep-2011"
+#define DRIVER_VERSION "08-Nov-2011"
 #define DRIVER_NAME "asix"
 
 /* ASIX AX8817X based USB 2.0 Ethernet Devices */
 #define MARVELL_CTRL_TXDELAY   0x0002
 #define MARVELL_CTRL_RXDELAY   0x0080
 
-#define        PHY_MODE_RTL8211CL      0x0004
+#define        PHY_MODE_RTL8211CL      0x000C
 
 /* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */
 struct asix_data {
@@ -652,9 +652,17 @@ static u32 asix_get_phyid(struct usbnet *dev)
 {
        int phy_reg;
        u32 phy_id;
+       int i;
 
-       phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID1);
-       if (phy_reg < 0)
+       /* Poll for the rare case the FW or phy isn't ready yet.  */
+       for (i = 0; i < 100; i++) {
+               phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID1);
+               if (phy_reg != 0 && phy_reg != 0xFFFF)
+                       break;
+               mdelay(1);
+       }
+
+       if (phy_reg <= 0 || phy_reg == 0xFFFF)
                return 0;
 
        phy_id = (phy_reg & 0xffff) << 16;
@@ -1075,7 +1083,7 @@ static const struct net_device_ops ax88772_netdev_ops = {
 
 static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
 {
-       int ret;
+       int ret, embd_phy;
        struct asix_data *data = (struct asix_data *)&dev->data;
        u8 buf[ETH_ALEN];
        u32 phyid;
@@ -1100,16 +1108,36 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
        dev->mii.reg_num_mask = 0x1f;
        dev->mii.phy_id = asix_get_phy_addr(dev);
 
-       phyid = asix_get_phyid(dev);
-       dbg("PHYID=0x%08x", phyid);
-
        dev->net->netdev_ops = &ax88772_netdev_ops;
        dev->net->ethtool_ops = &ax88772_ethtool_ops;
 
-       ret = ax88772_reset(dev);
+       embd_phy = ((dev->mii.phy_id & 0x1f) == 0x10 ? 1 : 0);
+
+       /* Reset the PHY to normal operation mode */
+       ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL);
+       if (ret < 0) {
+               dbg("Select PHY #1 failed: %d", ret);
+               return ret;
+       }
+
+       ret = asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL);
+       if (ret < 0)
+               return ret;
+
+       msleep(150);
+
+       ret = asix_sw_reset(dev, AX_SWRESET_CLEAR);
        if (ret < 0)
                return ret;
 
+       msleep(150);
+
+       ret = asix_sw_reset(dev, embd_phy ? AX_SWRESET_IPRL : AX_SWRESET_PRTE);
+
+       /* Read PHYID register *AFTER* the PHY was reset properly */
+       phyid = asix_get_phyid(dev);
+       dbg("PHYID=0x%08x", phyid);
+
        /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */
        if (dev->driver_info->flags & FLAG_FRAMING_AX) {
                /* hard_mtu  is still the default - the device does not support
@@ -1220,6 +1248,7 @@ static int ax88178_reset(struct usbnet *dev)
        __le16 eeprom;
        u8 status;
        int gpio0 = 0;
+       u32 phyid;
 
        asix_read_cmd(dev, AX_CMD_READ_GPIOS, 0, 0, 1, &status);
        dbg("GPIO Status: 0x%04x", status);
@@ -1235,12 +1264,13 @@ static int ax88178_reset(struct usbnet *dev)
                data->ledmode = 0;
                gpio0 = 1;
        } else {
-               data->phymode = le16_to_cpu(eeprom) & 7;
+               data->phymode = le16_to_cpu(eeprom) & 0x7F;
                data->ledmode = le16_to_cpu(eeprom) >> 8;
                gpio0 = (le16_to_cpu(eeprom) & 0x80) ? 0 : 1;
        }
        dbg("GPIO0: %d, PhyMode: %d", gpio0, data->phymode);
 
+       /* Power up external GigaPHY through AX88178 GPIO pin */
        asix_write_gpio(dev, AX_GPIO_RSE | AX_GPIO_GPO_1 | AX_GPIO_GPO1EN, 40);
        if ((le16_to_cpu(eeprom) >> 8) != 1) {
                asix_write_gpio(dev, 0x003c, 30);
@@ -1252,6 +1282,13 @@ static int ax88178_reset(struct usbnet *dev)
                asix_write_gpio(dev, AX_GPIO_GPO1EN | AX_GPIO_GPO_1, 30);
        }
 
+       /* Read PHYID register *AFTER* powering up PHY */
+       phyid = asix_get_phyid(dev);
+       dbg("PHYID=0x%08x", phyid);
+
+       /* Set AX88178 to enable MII/GMII/RGMII interface for external PHY */
+       asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, 0, 0, 0, NULL);
+
        asix_sw_reset(dev, 0);
        msleep(150);
 
@@ -1396,7 +1433,6 @@ static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf)
 {
        int ret;
        u8 buf[ETH_ALEN];
-       u32 phyid;
        struct asix_data *data = (struct asix_data *)&dev->data;
 
        data->eeprom_len = AX88772_EEPROM_LEN;
@@ -1423,12 +1459,12 @@ static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf)
        dev->net->netdev_ops = &ax88178_netdev_ops;
        dev->net->ethtool_ops = &ax88178_ethtool_ops;
 
-       phyid = asix_get_phyid(dev);
-       dbg("PHYID=0x%08x", phyid);
+       /* Blink LEDS so users know driver saw dongle */
+       asix_sw_reset(dev, 0);
+       msleep(150);
 
-       ret = ax88178_reset(dev);
-       if (ret < 0)
-               return ret;
+       asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD);
+       msleep(150);
 
        /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */
        if (dev->driver_info->flags & FLAG_FRAMING_AX) {
index a60d006..331e440 100644 (file)
@@ -130,7 +130,7 @@ static int rx_submit(struct usbpn_dev *pnd, struct urb *req, gfp_t gfp_flags)
        struct page *page;
        int err;
 
-       page = __netdev_alloc_page(dev, gfp_flags);
+       page = alloc_page(gfp_flags);
        if (!page)
                return -ENOMEM;
 
@@ -140,7 +140,7 @@ static int rx_submit(struct usbpn_dev *pnd, struct urb *req, gfp_t gfp_flags)
        err = usb_submit_urb(req, gfp_flags);
        if (unlikely(err)) {
                dev_dbg(&dev->dev, "RX submit error (%d)\n", err);
-               netdev_free_page(dev, page);
+               put_page(page);
        }
        return err;
 }
@@ -208,9 +208,9 @@ static void rx_complete(struct urb *req)
        dev->stats.rx_errors++;
 resubmit:
        if (page)
-               netdev_free_page(dev, page);
+               put_page(page);
        if (req)
-               rx_submit(pnd, req, GFP_ATOMIC);
+               rx_submit(pnd, req, GFP_ATOMIC | __GFP_COLD);
 }
 
 static int usbpn_close(struct net_device *dev);
@@ -229,7 +229,7 @@ static int usbpn_open(struct net_device *dev)
        for (i = 0; i < rxq_size; i++) {
                struct urb *req = usb_alloc_urb(0, GFP_KERNEL);
 
-               if (!req || rx_submit(pnd, req, GFP_KERNEL)) {
+               if (!req || rx_submit(pnd, req, GFP_KERNEL | __GFP_COLD)) {
                        usbpn_close(dev);
                        return -ENOMEM;
                }
index c924ea2..99ed6eb 100644 (file)
@@ -567,7 +567,7 @@ static const struct usb_device_id   products [] = {
 {
        USB_DEVICE_AND_INTERFACE_INFO(0x1004, 0x61aa, USB_CLASS_COMM,
                        USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
-       .driver_info = (unsigned long)&wwan_info,
+       .driver_info = 0,
 },
 
 /*
index f06fb78..009dd0f 100644 (file)
@@ -465,12 +465,10 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)
        int temp;
        u8 iface_no;
 
-       ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
+       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
        if (ctx == NULL)
                return -ENODEV;
 
-       memset(ctx, 0, sizeof(*ctx));
-
        init_timer(&ctx->tx_timer);
        spin_lock_init(&ctx->mtx);
        ctx->netdev = dev->net;
index d43db32..9c26c63 100644 (file)
@@ -144,10 +144,11 @@ static int vl600_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
        }
 
        frame = (struct vl600_frame_hdr *) buf->data;
-       /* NOTE: Should check that frame->magic == 0x53544448?
-        * Otherwise if we receive garbage at the beginning of the frame
-        * we may end up allocating a huge buffer and saving all the
-        * future incoming data into it.  */
+       /* Yes, check that frame->magic == 0x53544448 (or 0x44544d48),
+        * otherwise we may run out of memory w/a bad packet */
+       if (ntohl(frame->magic) != 0x53544448 &&
+                       ntohl(frame->magic) != 0x44544d48)
+               goto error;
 
        if (buf->len < sizeof(*frame) ||
                        buf->len != le32_to_cpup(&frame->len)) {
@@ -296,6 +297,11 @@ encapsulate:
         * overwrite the remaining fields.
         */
        packet = (struct vl600_pkt_hdr *) skb->data;
+       /* The VL600 wants IPv6 packets to have an IPv4 ethertype
+        * Since this modem only supports IPv4 and IPv6, just set all
+        * frames to 0x0800 (ETH_P_IP)
+        */
+       packet->h_proto = htons(ETH_P_IP);
        memset(&packet->dummy, 0, sizeof(packet->dummy));
        packet->len = cpu_to_le32(orig_len);
 
@@ -308,21 +314,12 @@ encapsulate:
        if (skb->len < full_len) /* Pad */
                skb_put(skb, full_len - skb->len);
 
-       /* The VL600 wants IPv6 packets to have an IPv4 ethertype
-        * Check if this is an IPv6 packet, and set the ethertype
-        * to 0x800
-        */
-       if ((skb->data[sizeof(struct vl600_pkt_hdr *) + 0x22] & 0xf0) == 0x60) {
-               skb->data[sizeof(struct vl600_pkt_hdr *) + 0x20] = 0x08;
-               skb->data[sizeof(struct vl600_pkt_hdr *) + 0x21] = 0;
-       }
-
        return skb;
 }
 
 static const struct driver_info        vl600_info = {
        .description    = "LG VL600 modem",
-       .flags          = FLAG_ETHER | FLAG_RX_ASSEMBLE,
+       .flags          = FLAG_RX_ASSEMBLE | FLAG_WWAN,
        .bind           = vl600_bind,
        .unbind         = vl600_unbind,
        .status         = usbnet_cdc_status,
index 22a7cf9..7d62c39 100644 (file)
@@ -51,6 +51,7 @@
 #define USB_VENDOR_ID_SMSC             (0x0424)
 #define USB_PRODUCT_ID_LAN7500         (0x7500)
 #define USB_PRODUCT_ID_LAN7505         (0x7505)
+#define RXW_PADDING                    2
 
 #define check_warn(ret, fmt, args...) \
        ({ if (ret < 0) netdev_warn(dev->net, fmt, ##args); })
@@ -727,7 +728,8 @@ static int smsc75xx_change_mtu(struct net_device *netdev, int new_mtu)
 }
 
 /* Enable or disable Rx checksum offload engine */
-static int smsc75xx_set_features(struct net_device *netdev, u32 features)
+static int smsc75xx_set_features(struct net_device *netdev,
+       netdev_features_t features)
 {
        struct usbnet *dev = netdev_priv(netdev);
        struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
@@ -1088,13 +1090,13 @@ static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
 
                memcpy(&rx_cmd_b, skb->data, sizeof(rx_cmd_b));
                le32_to_cpus(&rx_cmd_b);
-               skb_pull(skb, 4 + NET_IP_ALIGN);
+               skb_pull(skb, 4 + RXW_PADDING);
 
                packet = skb->data;
 
                /* get the packet length */
-               size = (rx_cmd_a & RX_CMD_A_LEN) - NET_IP_ALIGN;
-               align_count = (4 - ((size + NET_IP_ALIGN) % 4)) % 4;
+               size = (rx_cmd_a & RX_CMD_A_LEN) - RXW_PADDING;
+               align_count = (4 - ((size + RXW_PADDING) % 4)) % 4;
 
                if (unlikely(rx_cmd_a & RX_CMD_A_RED)) {
                        netif_dbg(dev, rx_err, dev->net,
index eff6767..56f3894 100644 (file)
@@ -516,7 +516,8 @@ static void smsc95xx_status(struct usbnet *dev, struct urb *urb)
 }
 
 /* Enable or disable Tx & Rx checksum offload engines */
-static int smsc95xx_set_features(struct net_device *netdev, u32 features)
+static int smsc95xx_set_features(struct net_device *netdev,
+       netdev_features_t features)
 {
        struct usbnet *dev = netdev_priv(netdev);
        u32 read_buf;
index ef883e9..49f4667 100644 (file)
@@ -27,8 +27,8 @@
 
 struct veth_net_stats {
        u64                     rx_packets;
-       u64                     tx_packets;
        u64                     rx_bytes;
+       u64                     tx_packets;
        u64                     tx_bytes;
        u64                     rx_dropped;
        struct u64_stats_sync   syncp;
@@ -66,9 +66,8 @@ static int veth_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 
 static void veth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->fw_version, "N/A");
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
 }
 
 static void veth_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
@@ -271,7 +270,7 @@ static void veth_setup(struct net_device *dev)
        dev->features |= NETIF_F_LLTX;
        dev->destructor = veth_dev_free;
 
-       dev->hw_features = NETIF_F_NO_CSUM | NETIF_F_SG | NETIF_F_RXCSUM;
+       dev->hw_features = NETIF_F_HW_CSUM | NETIF_F_SG | NETIF_F_RXCSUM;
 }
 
 /*
index 6ee8410..4dc9d84 100644 (file)
@@ -39,6 +39,7 @@ module_param(gso, bool, 0444);
 #define GOOD_COPY_LEN  128
 
 #define VIRTNET_SEND_COMMAND_SG_MAX    2
+#define VIRTNET_DRIVER_VERSION "1.0.0"
 
 struct virtnet_stats {
        struct u64_stats_sync syncp;
@@ -889,7 +890,21 @@ static void virtnet_get_ringparam(struct net_device *dev,
 
 }
 
+
+static void virtnet_get_drvinfo(struct net_device *dev,
+                               struct ethtool_drvinfo *info)
+{
+       struct virtnet_info *vi = netdev_priv(dev);
+       struct virtio_device *vdev = vi->vdev;
+
+       strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
+       strlcpy(info->version, VIRTNET_DRIVER_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, virtio_bus_name(vdev), sizeof(info->bus_info));
+
+}
+
 static const struct ethtool_ops virtnet_ethtool_ops = {
+       .get_drvinfo = virtnet_get_drvinfo,
        .get_link = ethtool_op_get_link,
        .get_ringparam = virtnet_get_ringparam,
 };
index e662cbc..b492ee1 100644 (file)
@@ -202,14 +202,9 @@ vmxnet3_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
        struct vmxnet3_adapter *adapter = netdev_priv(netdev);
 
        strlcpy(drvinfo->driver, vmxnet3_driver_name, sizeof(drvinfo->driver));
-       drvinfo->driver[sizeof(drvinfo->driver) - 1] = '\0';
 
        strlcpy(drvinfo->version, VMXNET3_DRIVER_VERSION_REPORT,
                sizeof(drvinfo->version));
-       drvinfo->driver[sizeof(drvinfo->version) - 1] = '\0';
-
-       strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
-       drvinfo->fw_version[sizeof(drvinfo->fw_version) - 1] = '\0';
 
        strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
                ETHTOOL_BUSINFO_LEN);
@@ -262,11 +257,11 @@ vmxnet3_get_strings(struct net_device *netdev, u32 stringset, u8 *buf)
        }
 }
 
-int vmxnet3_set_features(struct net_device *netdev, u32 features)
+int vmxnet3_set_features(struct net_device *netdev, netdev_features_t features)
 {
        struct vmxnet3_adapter *adapter = netdev_priv(netdev);
        unsigned long flags;
-       u32 changed = features ^ netdev->features;
+       netdev_features_t changed = features ^ netdev->features;
 
        if (changed & (NETIF_F_RXCSUM | NETIF_F_LRO | NETIF_F_HW_VLAN_RX)) {
                if (features & NETIF_F_RXCSUM)
index b18eac1..ed54797 100644 (file)
@@ -401,7 +401,7 @@ void
 vmxnet3_rq_destroy_all(struct vmxnet3_adapter *adapter);
 
 int
-vmxnet3_set_features(struct net_device *netdev, u32 features);
+vmxnet3_set_features(struct net_device *netdev, netdev_features_t features);
 
 int
 vmxnet3_create_queues(struct vmxnet3_adapter *adapter,
index 0a304b0..c1c0678 100644 (file)
@@ -58,6 +58,6 @@ obj-$(CONFIG_WL12XX_PLATFORM_DATA)    += wl12xx/
 obj-$(CONFIG_IWM)      += iwmc3200wifi/
 
 obj-$(CONFIG_MWIFIEX)  += mwifiex/
-obj-$(CONFIG_BRCMFMAC) += brcm80211/
-obj-$(CONFIG_BRCMUMAC) += brcm80211/
-obj-$(CONFIG_BRCMSMAC) += brcm80211/
+
+obj-$(CONFIG_BRCMFMAC) += brcm80211/
+obj-$(CONFIG_BRCMSMAC) += brcm80211/
index 0f9ee46..4596c33 100644 (file)
@@ -239,6 +239,7 @@ enum ATH_DEBUG {
        ATH_DBG_BTCOEX          = 0x00002000,
        ATH_DBG_WMI             = 0x00004000,
        ATH_DBG_BSTUCK          = 0x00008000,
+       ATH_DBG_MCI             = 0x00010000,
        ATH_DBG_ANY             = 0xffffffff
 };
 
index f517eb8..5ac2bc2 100644 (file)
@@ -1734,7 +1734,8 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
                          struct ieee80211_channel *chan, bool offchan,
                          enum nl80211_channel_type channel_type,
                          bool channel_type_valid, unsigned int wait,
-                         const u8 *buf, size_t len, bool no_cck, u64 *cookie)
+                         const u8 *buf, size_t len, bool no_cck,
+                         bool dont_wait_for_ack, u64 *cookie)
 {
        struct ath6kl *ar = ath6kl_priv(dev);
        u32 id;
index c1d2366..81e0031 100644 (file)
@@ -1548,7 +1548,8 @@ static int ath6kl_init(struct net_device *dev)
        ar->conf_flags = ATH6KL_CONF_IGNORE_ERP_BARKER |
                         ATH6KL_CONF_ENABLE_11N | ATH6KL_CONF_ENABLE_TX_BURST;
 
-       ar->wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
+       ar->wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM |
+                                 WIPHY_FLAG_HAVE_AP_SME;
 
        status = ath6kl_target_config_wlan_params(ar);
        if (!status)
index d9c08c6..7b4c074 100644 (file)
@@ -25,6 +25,7 @@ config ATH9K
 
 config ATH9K_PCI
        bool "Atheros ath9k PCI/PCIe bus support"
+       default y
        depends on ATH9K && PCI
        ---help---
          This option enables the PCI bus support in ath9k.
index 36ed3c4..49d3f25 100644 (file)
@@ -4,6 +4,7 @@ ath9k-y +=      beacon.o \
                main.o \
                recv.o \
                xmit.o \
+               mci.o \
 
 ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o
 ath9k-$(CONFIG_ATH9K_PCI) += pci.o
index 3b262ba..a93bd63 100644 (file)
@@ -121,10 +121,8 @@ static const struct ar9300_eeprom ar9300_default = {
                 * if the register is per chain
                 */
                .noiseFloorThreshCh = {-1, 0, 0},
-               .ob = {1, 1, 1},/* 3 chain */
-               .db_stage2 = {1, 1, 1}, /* 3 chain  */
-               .db_stage3 = {0, 0, 0},
-               .db_stage4 = {0, 0, 0},
+               .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+               .quick_drop = 0,
                .xpaBiasLvl = 0,
                .txFrameToDataStart = 0x0e,
                .txFrameToPaOn = 0x0e,
@@ -144,7 +142,7 @@ static const struct ar9300_eeprom ar9300_default = {
         },
        .base_ext1 = {
                .ant_div_control = 0,
-               .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+               .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
        },
        .calFreqPier2G = {
                FREQ2FBIN(2412, 1),
@@ -323,10 +321,8 @@ static const struct ar9300_eeprom ar9300_default = {
                .spurChans = {0, 0, 0, 0, 0},
                /* noiseFloorThreshCh Check if the register is per chain */
                .noiseFloorThreshCh = {-1, 0, 0},
-               .ob = {3, 3, 3}, /* 3 chain */
-               .db_stage2 = {3, 3, 3}, /* 3 chain */
-               .db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */
-               .db_stage4 = {3, 3, 3},  /* don't exist for 2G */
+               .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+               .quick_drop = 0,
                .xpaBiasLvl = 0,
                .txFrameToDataStart = 0x0e,
                .txFrameToPaOn = 0x0e,
@@ -698,10 +694,8 @@ static const struct ar9300_eeprom ar9300_x113 = {
                 * if the register is per chain
                 */
                .noiseFloorThreshCh = {-1, 0, 0},
-               .ob = {1, 1, 1},/* 3 chain */
-               .db_stage2 = {1, 1, 1}, /* 3 chain  */
-               .db_stage3 = {0, 0, 0},
-               .db_stage4 = {0, 0, 0},
+               .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+               .quick_drop = 0,
                .xpaBiasLvl = 0,
                .txFrameToDataStart = 0x0e,
                .txFrameToPaOn = 0x0e,
@@ -721,7 +715,7 @@ static const struct ar9300_eeprom ar9300_x113 = {
         },
         .base_ext1 = {
                .ant_div_control = 0,
-               .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+               .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
         },
        .calFreqPier2G = {
                FREQ2FBIN(2412, 1),
@@ -900,10 +894,8 @@ static const struct ar9300_eeprom ar9300_x113 = {
                .spurChans = {FREQ2FBIN(5500, 0), 0, 0, 0, 0},
                /* noiseFloorThreshCh Check if the register is per chain */
                .noiseFloorThreshCh = {-1, 0, 0},
-               .ob = {3, 3, 3}, /* 3 chain */
-               .db_stage2 = {3, 3, 3}, /* 3 chain */
-               .db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */
-               .db_stage4 = {3, 3, 3},  /* don't exist for 2G */
+               .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+               .quick_drop = 0,
                .xpaBiasLvl = 0xf,
                .txFrameToDataStart = 0x0e,
                .txFrameToPaOn = 0x0e,
@@ -1276,10 +1268,8 @@ static const struct ar9300_eeprom ar9300_h112 = {
                 * if the register is per chain
                 */
                .noiseFloorThreshCh = {-1, 0, 0},
-               .ob = {1, 1, 1},/* 3 chain */
-               .db_stage2 = {1, 1, 1}, /* 3 chain  */
-               .db_stage3 = {0, 0, 0},
-               .db_stage4 = {0, 0, 0},
+               .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+               .quick_drop = 0,
                .xpaBiasLvl = 0,
                .txFrameToDataStart = 0x0e,
                .txFrameToPaOn = 0x0e,
@@ -1291,20 +1281,20 @@ static const struct ar9300_eeprom ar9300_h112 = {
                .txEndToRxOn = 0x2,
                .txFrameToXpaOn = 0xe,
                .thresh62 = 28,
-               .papdRateMaskHt20 = LE32(0x80c080),
-               .papdRateMaskHt40 = LE32(0x80c080),
+               .papdRateMaskHt20 = LE32(0x0c80c080),
+               .papdRateMaskHt40 = LE32(0x0080c080),
                .futureModal = {
                        0, 0, 0, 0, 0, 0, 0, 0,
                },
        },
        .base_ext1 = {
                .ant_div_control = 0,
-               .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+               .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
        },
        .calFreqPier2G = {
                FREQ2FBIN(2412, 1),
                FREQ2FBIN(2437, 1),
-               FREQ2FBIN(2472, 1),
+               FREQ2FBIN(2462, 1),
        },
        /* ar9300_cal_data_per_freq_op_loop 2g */
        .calPierData2G = {
@@ -1314,7 +1304,7 @@ static const struct ar9300_eeprom ar9300_h112 = {
        },
        .calTarget_freqbin_Cck = {
                FREQ2FBIN(2412, 1),
-               FREQ2FBIN(2484, 1),
+               FREQ2FBIN(2472, 1),
        },
        .calTarget_freqbin_2G = {
                FREQ2FBIN(2412, 1),
@@ -1478,10 +1468,8 @@ static const struct ar9300_eeprom ar9300_h112 = {
                .spurChans = {0, 0, 0, 0, 0},
                /* noiseFloorThreshCh Check if the register is per chain */
                .noiseFloorThreshCh = {-1, 0, 0},
-               .ob = {3, 3, 3}, /* 3 chain */
-               .db_stage2 = {3, 3, 3}, /* 3 chain */
-               .db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */
-               .db_stage4 = {3, 3, 3},  /* don't exist for 2G */
+               .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+               .quick_drop = 0,
                .xpaBiasLvl = 0,
                .txFrameToDataStart = 0x0e,
                .txFrameToPaOn = 0x0e,
@@ -1515,7 +1503,7 @@ static const struct ar9300_eeprom ar9300_h112 = {
                FREQ2FBIN(5500, 0),
                FREQ2FBIN(5600, 0),
                FREQ2FBIN(5700, 0),
-               FREQ2FBIN(5825, 0)
+               FREQ2FBIN(5785, 0)
        },
        .calPierData5G = {
                {
@@ -1854,10 +1842,8 @@ static const struct ar9300_eeprom ar9300_x112 = {
                 * if the register is per chain
                 */
                .noiseFloorThreshCh = {-1, 0, 0},
-               .ob = {1, 1, 1},/* 3 chain */
-               .db_stage2 = {1, 1, 1}, /* 3 chain  */
-               .db_stage3 = {0, 0, 0},
-               .db_stage4 = {0, 0, 0},
+               .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+               .quick_drop = 0,
                .xpaBiasLvl = 0,
                .txFrameToDataStart = 0x0e,
                .txFrameToPaOn = 0x0e,
@@ -1877,7 +1863,7 @@ static const struct ar9300_eeprom ar9300_x112 = {
        },
        .base_ext1 = {
                .ant_div_control = 0,
-               .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+               .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
        },
        .calFreqPier2G = {
                FREQ2FBIN(2412, 1),
@@ -2056,10 +2042,8 @@ static const struct ar9300_eeprom ar9300_x112 = {
                .spurChans = {0, 0, 0, 0, 0},
                /* noiseFloorThreshch check if the register is per chain */
                .noiseFloorThreshCh = {-1, 0, 0},
-               .ob = {3, 3, 3}, /* 3 chain */
-               .db_stage2 = {3, 3, 3}, /* 3 chain */
-               .db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */
-               .db_stage4 = {3, 3, 3},  /* don't exist for 2G */
+               .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+               .quick_drop = 0,
                .xpaBiasLvl = 0,
                .txFrameToDataStart = 0x0e,
                .txFrameToPaOn = 0x0e,
@@ -2431,10 +2415,8 @@ static const struct ar9300_eeprom ar9300_h116 = {
                 * if the register is per chain
                 */
                .noiseFloorThreshCh = {-1, 0, 0},
-               .ob = {1, 1, 1},/* 3 chain */
-               .db_stage2 = {1, 1, 1}, /* 3 chain  */
-               .db_stage3 = {0, 0, 0},
-               .db_stage4 = {0, 0, 0},
+               .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+               .quick_drop = 0,
                .xpaBiasLvl = 0,
                .txFrameToDataStart = 0x0e,
                .txFrameToPaOn = 0x0e,
@@ -2454,12 +2436,12 @@ static const struct ar9300_eeprom ar9300_h116 = {
         },
         .base_ext1 = {
                .ant_div_control = 0,
-               .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+               .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
         },
        .calFreqPier2G = {
                FREQ2FBIN(2412, 1),
                FREQ2FBIN(2437, 1),
-               FREQ2FBIN(2472, 1),
+               FREQ2FBIN(2462, 1),
         },
        /* ar9300_cal_data_per_freq_op_loop 2g */
        .calPierData2G = {
@@ -2633,10 +2615,8 @@ static const struct ar9300_eeprom ar9300_h116 = {
                .spurChans = {0, 0, 0, 0, 0},
                /* noiseFloorThreshCh Check if the register is per chain */
                .noiseFloorThreshCh = {-1, 0, 0},
-               .ob = {3, 3, 3}, /* 3 chain */
-               .db_stage2 = {3, 3, 3}, /* 3 chain */
-               .db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */
-               .db_stage4 = {3, 3, 3},  /* don't exist for 2G */
+               .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+               .quick_drop = 0,
                .xpaBiasLvl = 0,
                .txFrameToDataStart = 0x0e,
                .txFrameToPaOn = 0x0e,
@@ -2663,7 +2643,7 @@ static const struct ar9300_eeprom ar9300_h116 = {
                .xatten1MarginHigh = {0, 0, 0}
         },
        .calFreqPier5G = {
-               FREQ2FBIN(5180, 0),
+               FREQ2FBIN(5160, 0),
                FREQ2FBIN(5220, 0),
                FREQ2FBIN(5320, 0),
                FREQ2FBIN(5400, 0),
@@ -3023,6 +3003,8 @@ static u32 ath9k_hw_ar9300_get_eeprom(struct ath_hw *ah,
                return eep->modalHeader5G.antennaGain;
        case EEP_ANTENNA_GAIN_2G:
                return eep->modalHeader2G.antennaGain;
+       case EEP_QUICK_DROP:
+               return pBase->miscConfiguration & BIT(1);
        default:
                return 0;
        }
@@ -3428,25 +3410,14 @@ static u32 ar9003_dump_modal_eeprom(char *buf, u32 len, u32 size,
        PR_EEP("Chain0 NF Threshold", modal_hdr->noiseFloorThreshCh[0]);
        PR_EEP("Chain1 NF Threshold", modal_hdr->noiseFloorThreshCh[1]);
        PR_EEP("Chain2 NF Threshold", modal_hdr->noiseFloorThreshCh[2]);
+       PR_EEP("Quick Drop", modal_hdr->quick_drop);
+       PR_EEP("txEndToXpaOff", modal_hdr->txEndToXpaOff);
        PR_EEP("xPA Bias Level", modal_hdr->xpaBiasLvl);
        PR_EEP("txFrameToDataStart", modal_hdr->txFrameToDataStart);
        PR_EEP("txFrameToPaOn", modal_hdr->txFrameToPaOn);
        PR_EEP("txFrameToXpaOn", modal_hdr->txFrameToXpaOn);
        PR_EEP("txClip", modal_hdr->txClip);
        PR_EEP("ADC Desired size", modal_hdr->adcDesiredSize);
-       PR_EEP("Chain0 ob", modal_hdr->ob[0]);
-       PR_EEP("Chain1 ob", modal_hdr->ob[1]);
-       PR_EEP("Chain2 ob", modal_hdr->ob[2]);
-
-       PR_EEP("Chain0 db_stage2", modal_hdr->db_stage2[0]);
-       PR_EEP("Chain1 db_stage2", modal_hdr->db_stage2[1]);
-       PR_EEP("Chain2 db_stage2", modal_hdr->db_stage2[2]);
-       PR_EEP("Chain0 db_stage3", modal_hdr->db_stage3[0]);
-       PR_EEP("Chain1 db_stage3", modal_hdr->db_stage3[1]);
-       PR_EEP("Chain2 db_stage3", modal_hdr->db_stage3[2]);
-       PR_EEP("Chain0 db_stage4", modal_hdr->db_stage4[0]);
-       PR_EEP("Chain1 db_stage4", modal_hdr->db_stage4[1]);
-       PR_EEP("Chain2 db_stage4", modal_hdr->db_stage4[2]);
 
        return len;
 }
@@ -3503,6 +3474,7 @@ static u32 ath9k_hw_ar9003_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
        PR_EEP("Internal regulator", !!(pBase->featureEnable & BIT(4)));
        PR_EEP("Enable Paprd", !!(pBase->featureEnable & BIT(5)));
        PR_EEP("Driver Strength", !!(pBase->miscConfiguration & BIT(0)));
+       PR_EEP("Quick Drop", !!(pBase->miscConfiguration & BIT(1)));
        PR_EEP("Chain mask Reduce", (pBase->miscConfiguration >> 0x3) & 0x1);
        PR_EEP("Write enable Gpio", pBase->eepromWriteEnableGpio);
        PR_EEP("WLAN Disable Gpio", pBase->wlanDisableGpio);
@@ -3965,6 +3937,40 @@ static void ar9003_hw_apply_tuning_caps(struct ath_hw *ah)
        }
 }
 
+static void ar9003_hw_quick_drop_apply(struct ath_hw *ah, u16 freq)
+{
+       struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+       int quick_drop = ath9k_hw_ar9300_get_eeprom(ah, EEP_QUICK_DROP);
+       s32 t[3], f[3] = {5180, 5500, 5785};
+
+       if (!quick_drop)
+               return;
+
+       if (freq < 4000)
+               quick_drop = eep->modalHeader2G.quick_drop;
+       else {
+               t[0] = eep->base_ext1.quick_drop_low;
+               t[1] = eep->modalHeader5G.quick_drop;
+               t[2] = eep->base_ext1.quick_drop_high;
+               quick_drop = ar9003_hw_power_interpolate(freq, f, t, 3);
+       }
+       REG_RMW_FIELD(ah, AR_PHY_AGC, AR_PHY_AGC_QUICK_DROP, quick_drop);
+}
+
+static void ar9003_hw_txend_to_xpa_off_apply(struct ath_hw *ah, u16 freq)
+{
+       struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+       u32 value;
+
+       value = (freq < 4000) ? eep->modalHeader2G.txEndToXpaOff :
+                               eep->modalHeader5G.txEndToXpaOff;
+
+       REG_RMW_FIELD(ah, AR_PHY_XPA_TIMING_CTL,
+                     AR_PHY_XPA_TIMING_CTL_TX_END_XPAB_OFF, value);
+       REG_RMW_FIELD(ah, AR_PHY_XPA_TIMING_CTL,
+                     AR_PHY_XPA_TIMING_CTL_TX_END_XPAA_OFF, value);
+}
+
 static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah,
                                             struct ath9k_channel *chan)
 {
@@ -3972,10 +3978,12 @@ static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah,
        ar9003_hw_ant_ctrl_apply(ah, IS_CHAN_2GHZ(chan));
        ar9003_hw_drive_strength_apply(ah);
        ar9003_hw_atten_apply(ah, chan);
+       ar9003_hw_quick_drop_apply(ah, chan->channel);
        if (!AR_SREV_9330(ah) && !AR_SREV_9340(ah))
                ar9003_hw_internal_regulator_apply(ah);
        if (AR_SREV_9485(ah) || AR_SREV_9330(ah) || AR_SREV_9340(ah))
                ar9003_hw_apply_tuning_caps(ah);
+       ar9003_hw_txend_to_xpa_off_apply(ah, chan->channel);
 }
 
 static void ath9k_hw_ar9300_set_addac(struct ath_hw *ah,
@@ -5051,6 +5059,8 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah,
                        regulatory->max_power_level = targetPowerValT2[i];
        }
 
+       ath9k_hw_update_regulatory_maxpower(ah);
+
        if (test)
                return;
 
index 6335a86..bb223fe 100644 (file)
@@ -216,10 +216,8 @@ struct ar9300_modal_eep_header {
        u8 spurChans[AR_EEPROM_MODAL_SPURS];
        /* 3  Check if the register is per chain */
        int8_t noiseFloorThreshCh[AR9300_MAX_CHAINS];
-       u8 ob[AR9300_MAX_CHAINS];
-       u8 db_stage2[AR9300_MAX_CHAINS];
-       u8 db_stage3[AR9300_MAX_CHAINS];
-       u8 db_stage4[AR9300_MAX_CHAINS];
+       u8 reserved[11];
+       int8_t quick_drop;
        u8 xpaBiasLvl;
        u8 txFrameToDataStart;
        u8 txFrameToPaOn;
@@ -269,7 +267,9 @@ struct cal_ctl_data_5g {
 
 struct ar9300_BaseExtension_1 {
        u8 ant_div_control;
-       u8 future[13];
+       u8 future[11];
+       int8_t quick_drop_low;
+       int8_t quick_drop_high;
 } __packed;
 
 struct ar9300_BaseExtension_2 {
index 2330e7e..e41d269 100644 (file)
@@ -199,12 +199,14 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah,
                        synth_freq = chan->channel;
                }
        } else {
-               range = 10;
+               range = AR_SREV_9462(ah) ? 5 : 10;
                max_spur_cnts = 4;
                synth_freq = chan->channel;
        }
 
        for (i = 0; i < max_spur_cnts; i++) {
+               if (AR_SREV_9462(ah) && (i == 0 || i == 3))
+                       continue;
                negative = 0;
                if (AR_SREV_9485(ah) || AR_SREV_9340(ah) || AR_SREV_9330(ah))
                        cur_bb_spur = FBIN2FREQ(spur_fbin_ptr[i],
index 4114fe7..497d746 100644 (file)
 #define AR_PHY_DAG_CTRLCCK_RSSI_THR_S   10
 
 #define AR_PHY_RIFS_INIT_DELAY         0x3ff0000
+#define AR_PHY_AGC_QUICK_DROP       0x03c00000
+#define AR_PHY_AGC_QUICK_DROP_S     22
 #define AR_PHY_AGC_COARSE_LOW       0x00007F80
 #define AR_PHY_AGC_COARSE_LOW_S     7
 #define AR_PHY_AGC_COARSE_HIGH      0x003F8000
index 9c51b39..259a6f3 100644 (file)
@@ -43,16 +43,16 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011},
        {0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e},
-       {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
-       {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881},
+       {0x00009824, 0x5ac640de, 0x5ac640d0, 0x5ac640d0, 0x5ac640de},
+       {0x00009828, 0x0796be89, 0x0696b081, 0x0696b881, 0x0796be89},
        {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
        {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c},
        {0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4},
        {0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a0},
        {0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020},
        {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2},
-       {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e},
-       {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3039605e, 0x33795d5e},
+       {0x00009e10, 0x92c88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x92c84d2e},
+       {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3379605e, 0x33795d5e},
        {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
        {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
        {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
@@ -688,8 +688,8 @@ static const u32 ar9462_2p0_mac_postamble_emulation[][5] = {
 static const u32 ar9462_2p0_radio_postamble_sys3ant[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x000160ac, 0xa4646c08, 0xa4646c08, 0x24645808, 0x24645808},
-       {0x00016140, 0x10804008, 0x10804008, 0x90804008, 0x90804008},
-       {0x00016540, 0x10804008, 0x10804008, 0x90804008, 0x90804008},
+       {0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
+       {0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
 };
 
 static const u32 ar9462_2p0_baseband_postamble_emulation[][5] = {
@@ -717,8 +717,8 @@ static const u32 ar9462_2p0_baseband_postamble_emulation[][5] = {
 static const u32 ar9462_2p0_radio_postamble_sys2ant[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x000160ac, 0xa4646c08, 0xa4646c08, 0x24645808, 0x24645808},
-       {0x00016140, 0x10804008, 0x10804008, 0x90804008, 0x90804008},
-       {0x00016540, 0x10804008, 0x10804008, 0x90804008, 0x90804008},
+       {0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
+       {0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
 };
 
 static const u32 ar9462_common_wo_xlna_rx_gain_table_2p0[][2] = {
@@ -1059,7 +1059,7 @@ static const u32 ar9462_modes_low_ob_db_tx_gain_table_2p0[][5] = {
 
 static const u32 ar9462_2p0_soc_postamble[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-       {0x00007010, 0x00002233, 0x00002233, 0x00002233, 0x00002233},
+       {0x00007010, 0x00000033, 0x00000033, 0x00000033, 0x00000033},
 };
 
 static const u32 ar9462_2p0_baseband_core[][2] = {
@@ -1257,8 +1257,8 @@ static const u32 ar9462_modes_high_ob_db_tx_gain_table_2p0[][5] = {
        {0x0000a540, 0x48025e6c, 0x48025e6c, 0x38001660, 0x38001660},
        {0x0000a544, 0x4e025e8e, 0x4e025e8e, 0x3b001861, 0x3b001861},
        {0x0000a548, 0x53025eb2, 0x53025eb2, 0x3e001a81, 0x3e001a81},
-       {0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83},
-       {0x0000a550, 0x5f025ef6, 0x5f025ef6, 0x44001c84, 0x44001c84},
+       {0x0000a54c, 0x59025eb6, 0x59025eb6, 0x42001a83, 0x42001a83},
+       {0x0000a550, 0x5d025ef6, 0x5d025ef6, 0x44001c84, 0x44001c84},
        {0x0000a554, 0x62025f56, 0x62025f56, 0x48001ce3, 0x48001ce3},
        {0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5},
        {0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9},
@@ -1850,8 +1850,8 @@ static const u32 ar9462_modes_green_ob_db_tx_gain_table_2p0[][5] = {
        {0x0000a540, 0x48025e6c, 0x48025e6c, 0x38001660, 0x38001660},
        {0x0000a544, 0x4e025e8e, 0x4e025e8e, 0x3b001861, 0x3b001861},
        {0x0000a548, 0x53025eb2, 0x53025eb2, 0x3e001a81, 0x3e001a81},
-       {0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83},
-       {0x0000a550, 0x5f025ef6, 0x5f025ef6, 0x44001c84, 0x44001c84},
+       {0x0000a54c, 0x59025eb6, 0x59025eb6, 0x42001a83, 0x42001a83},
+       {0x0000a550, 0x5d025ef6, 0x5d025ef6, 0x44001c84, 0x44001c84},
        {0x0000a554, 0x62025f56, 0x62025f56, 0x48001ce3, 0x48001ce3},
        {0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5},
        {0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9},
index 1c269f5..93b45b4 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "debug.h"
 #include "common.h"
+#include "mci.h"
 
 /*
  * Header for the ath9k.ko driver core *only* -- hw code nor any other driver
@@ -252,6 +253,7 @@ struct ath_node {
 #ifdef CONFIG_ATH9K_DEBUGFS
        struct list_head list; /* for sc->nodes */
        struct ieee80211_sta *sta; /* station struct we're part of */
+       struct ieee80211_vif *vif; /* interface with which we're associated */
 #endif
        struct ath_atx_tid tid[WME_NUM_TID];
        struct ath_atx_ac ac[WME_NUM_AC];
@@ -443,7 +445,9 @@ struct ath_btcoex {
        u32 btcoex_no_stomp; /* in usec */
        u32 btcoex_period; /* in usec */
        u32 btscan_no_stomp; /* in usec */
+       u32 duty_cycle;
        struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */
+       struct ath_mci_profile mci;
 };
 
 int ath_init_btcoex_timer(struct ath_softc *sc);
index 2741203..6fb719d 100644 (file)
@@ -709,24 +709,29 @@ static ssize_t read_file_stations(struct file *file, char __user *user_buf,
 
        len += snprintf(buf + len, size - len,
                        "Stations:\n"
-                       " tid: addr sched paused buf_q-empty an ac\n"
+                       " tid: addr sched paused buf_q-empty an ac baw\n"
                        " ac: addr sched tid_q-empty txq\n");
 
        spin_lock(&sc->nodes_lock);
        list_for_each_entry(an, &sc->nodes, list) {
+               unsigned short ma = an->maxampdu;
+               if (ma == 0)
+                       ma = 65535; /* see ath_lookup_rate */
                len += snprintf(buf + len, size - len,
-                               "%pM\n", an->sta->addr);
+                               "iface: %pM  sta: %pM max-ampdu: %hu mpdu-density: %uus\n",
+                               an->vif->addr, an->sta->addr, ma,
+                               (unsigned int)(an->mpdudensity));
                if (len >= size)
                        goto done;
 
                for (q = 0; q < WME_NUM_TID; q++) {
                        struct ath_atx_tid *tid = &(an->tid[q]);
                        len += snprintf(buf + len, size - len,
-                                       " tid: %p %s %s %i %p %p\n",
+                                       " tid: %p %s %s %i %p %p %hu\n",
                                        tid, tid->sched ? "sched" : "idle",
                                        tid->paused ? "paused" : "running",
                                        skb_queue_empty(&tid->buf_q),
-                                       tid->an, tid->ac);
+                                       tid->an, tid->ac, tid->baw_size);
                        if (len >= size)
                                goto done;
                }
index 49abd34..5ff7ab9 100644 (file)
@@ -249,7 +249,8 @@ enum eeprom_param {
        EEP_ANT_DIV_CTL1,
        EEP_CHAIN_MASK_REDUCE,
        EEP_ANTENNA_GAIN_2G,
-       EEP_ANTENNA_GAIN_5G
+       EEP_ANTENNA_GAIN_5G,
+       EEP_QUICK_DROP
 };
 
 enum ar5416_rates {
index 655576c..2c279dc 100644 (file)
@@ -189,8 +189,8 @@ static void ath_btcoex_period_timer(unsigned long data)
        bool is_btscan;
 
        ath9k_ps_wakeup(sc);
-       ath_detect_bt_priority(sc);
-
+       if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI))
+               ath_detect_bt_priority(sc);
        is_btscan = sc->sc_flags & SC_OP_BT_SCAN;
 
        spin_lock_bh(&btcoex->btcoex_lock);
@@ -212,8 +212,9 @@ static void ath_btcoex_period_timer(unsigned long data)
        }
 
        ath9k_ps_restore(sc);
+       timer_period = btcoex->btcoex_period / 1000;
        mod_timer(&btcoex->period_timer, jiffies +
-                                 msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD));
+                                 msecs_to_jiffies(timer_period));
 }
 
 /*
index 2f91acc..662ab7e 100644 (file)
@@ -2335,7 +2335,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
                        ah->enabled_cals |= TX_IQ_ON_AGC_CAL;
        }
        if (AR_SREV_9462(ah))
-               pCap->hw_caps |= ATH9K_HW_CAP_RTT;
+               pCap->hw_caps |= ATH9K_HW_CAP_RTT | ATH9K_HW_CAP_MCI;
 
        return 0;
 }
@@ -2583,7 +2583,7 @@ void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test)
        struct ath9k_channel *chan = ah->curchan;
        struct ieee80211_channel *channel = chan->chan;
 
-       reg->power_limit = min_t(int, limit, MAX_RATE_POWER);
+       reg->power_limit = min_t(u32, limit, MAX_RATE_POWER);
        if (test)
                channel->max_power = MAX_RATE_POWER / 2;
 
index f389b3c..33e8f2f 100644 (file)
@@ -203,6 +203,7 @@ enum ath9k_hw_caps {
        ATH9K_HW_CAP_5GHZ                       = BIT(14),
        ATH9K_HW_CAP_APM                        = BIT(15),
        ATH9K_HW_CAP_RTT                        = BIT(16),
+       ATH9K_HW_CAP_MCI                        = BIT(17),
 };
 
 struct ath9k_hw_capabilities {
@@ -419,6 +420,16 @@ enum ath9k_rx_qtype {
        ATH9K_RX_QUEUE_MAX,
 };
 
+enum ath_mci_gpm_coex_profile_type {
+       MCI_GPM_COEX_PROFILE_UNKNOWN,
+       MCI_GPM_COEX_PROFILE_RFCOMM,
+       MCI_GPM_COEX_PROFILE_A2DP,
+       MCI_GPM_COEX_PROFILE_HID,
+       MCI_GPM_COEX_PROFILE_BNEP,
+       MCI_GPM_COEX_PROFILE_VOICE,
+       MCI_GPM_COEX_PROFILE_MAX
+};
+
 struct ath9k_beacon_state {
        u32 bs_nexttbtt;
        u32 bs_nextdtim;
index d4c909f..e046de9 100644 (file)
@@ -424,6 +424,8 @@ static int ath9k_init_btcoex(struct ath_softc *sc)
                txq = sc->tx.txq_map[WME_AC_BE];
                ath9k_hw_init_btcoex_hw(sc->sc_ah, txq->axq_qnum);
                sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
+               sc->btcoex.duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE;
+               INIT_LIST_HEAD(&sc->btcoex.mci.info);
                break;
        default:
                WARN_ON(1);
@@ -695,6 +697,7 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
                hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
 
        hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
+       hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
 
        hw->queues = 4;
        hw->max_rates = 4;
index 93fbe6f..e43c41c 100644 (file)
@@ -630,7 +630,8 @@ set_timer:
        }
 }
 
-static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
+static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta,
+                           struct ieee80211_vif *vif)
 {
        struct ath_node *an;
        an = (struct ath_node *)sta->drv_priv;
@@ -640,6 +641,7 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
        list_add(&an->list, &sc->nodes);
        spin_unlock(&sc->nodes_lock);
        an->sta = sta;
+       an->vif = vif;
 #endif
        if (sc->sc_flags & SC_OP_TXAGGR) {
                ath_tx_node_init(sc, an);
@@ -1133,8 +1135,9 @@ static int ath9k_start(struct ieee80211_hw *hw)
 
        if ((ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE) &&
            !ah->btcoex_hw.enabled) {
-               ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
-                                          AR_STOMP_LOW_WLAN_WGHT);
+               if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI))
+                       ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
+                                                  AR_STOMP_LOW_WLAN_WGHT);
                ath9k_hw_btcoex_enable(ah);
 
                if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
@@ -1237,6 +1240,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
                ath9k_hw_btcoex_disable(ah);
                if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
                        ath9k_btcoex_timer_pause(sc);
+               ath_mci_flush_profile(&sc->btcoex.mci);
        }
 
        spin_lock_bh(&sc->sc_pcu_lock);
@@ -1798,7 +1802,7 @@ static int ath9k_sta_add(struct ieee80211_hw *hw,
        struct ath_node *an = (struct ath_node *) sta->drv_priv;
        struct ieee80211_key_conf ps_key = { };
 
-       ath_node_attach(sc, sta);
+       ath_node_attach(sc, sta, vif);
 
        if (vif->type != NL80211_IFTYPE_AP &&
            vif->type != NL80211_IFTYPE_AP_VLAN)
diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c
new file mode 100644 (file)
index 0000000..0fbb141
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "ath9k.h"
+#include "mci.h"
+
+u8 ath_mci_duty_cycle[] = { 0, 50, 60, 70, 80, 85, 90, 95, 98 };
+
+static struct ath_mci_profile_info*
+ath_mci_find_profile(struct ath_mci_profile *mci,
+                    struct ath_mci_profile_info *info)
+{
+       struct ath_mci_profile_info *entry;
+
+       list_for_each_entry(entry, &mci->info, list) {
+               if (entry->conn_handle == info->conn_handle)
+                       break;
+       }
+       return entry;
+}
+
+static bool ath_mci_add_profile(struct ath_common *common,
+                               struct ath_mci_profile *mci,
+                               struct ath_mci_profile_info *info)
+{
+       struct ath_mci_profile_info *entry;
+
+       if ((mci->num_sco == ATH_MCI_MAX_SCO_PROFILE) &&
+           (info->type == MCI_GPM_COEX_PROFILE_VOICE)) {
+               ath_dbg(common, ATH_DBG_MCI,
+                       "Too many SCO profile, failed to add new profile\n");
+               return false;
+       }
+
+       if (((NUM_PROF(mci) - mci->num_sco) == ATH_MCI_MAX_ACL_PROFILE) &&
+           (info->type != MCI_GPM_COEX_PROFILE_VOICE)) {
+               ath_dbg(common, ATH_DBG_MCI,
+                       "Too many ACL profile, failed to add new profile\n");
+               return false;
+       }
+
+       entry = ath_mci_find_profile(mci, info);
+
+       if (entry)
+               memcpy(entry, info, 10);
+       else {
+               entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+               if (!entry)
+                       return false;
+
+               memcpy(entry, info, 10);
+               INC_PROF(mci, info);
+               list_add_tail(&info->list, &mci->info);
+       }
+       return true;
+}
+
+static void ath_mci_del_profile(struct ath_common *common,
+                               struct ath_mci_profile *mci,
+                               struct ath_mci_profile_info *info)
+{
+       struct ath_mci_profile_info *entry;
+
+       entry = ath_mci_find_profile(mci, info);
+
+       if (!entry) {
+               ath_dbg(common, ATH_DBG_MCI,
+                       "Profile to be deleted not found\n");
+               return;
+       }
+       DEC_PROF(mci, entry);
+       list_del(&entry->list);
+       kfree(entry);
+}
+
+void ath_mci_flush_profile(struct ath_mci_profile *mci)
+{
+       struct ath_mci_profile_info *info, *tinfo;
+
+       list_for_each_entry_safe(info, tinfo, &mci->info, list) {
+               list_del(&info->list);
+               DEC_PROF(mci, info);
+               kfree(info);
+       }
+       mci->aggr_limit = 0;
+}
+
+static void ath_mci_adjust_aggr_limit(struct ath_btcoex *btcoex)
+{
+       struct ath_mci_profile *mci = &btcoex->mci;
+       u32 wlan_airtime = btcoex->btcoex_period *
+                               (100 - btcoex->duty_cycle) / 100;
+
+       /*
+        * Scale: wlan_airtime is in ms, aggr_limit is in 0.25 ms.
+        * When wlan_airtime is less than 4ms, aggregation limit has to be
+        * adjusted half of wlan_airtime to ensure that the aggregation can fit
+        * without collision with BT traffic.
+        */
+       if ((wlan_airtime <= 4) &&
+           (!mci->aggr_limit || (mci->aggr_limit > (2 * wlan_airtime))))
+               mci->aggr_limit = 2 * wlan_airtime;
+}
+
+static void ath_mci_update_scheme(struct ath_softc *sc)
+{
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct ath_btcoex *btcoex = &sc->btcoex;
+       struct ath_mci_profile *mci = &btcoex->mci;
+       struct ath_mci_profile_info *info;
+       u32 num_profile = NUM_PROF(mci);
+
+       if (num_profile == 1) {
+               info = list_first_entry(&mci->info,
+                                       struct ath_mci_profile_info,
+                                       list);
+               if (mci->num_sco && info->T == 12) {
+                       mci->aggr_limit = 8;
+                       ath_dbg(common, ATH_DBG_MCI,
+                               "Single SCO, aggregation limit 2 ms\n");
+               } else if ((info->type == MCI_GPM_COEX_PROFILE_BNEP) &&
+                          !info->master) {
+                       btcoex->btcoex_period = 60;
+                       ath_dbg(common, ATH_DBG_MCI,
+                               "Single slave PAN/FTP, bt period 60 ms\n");
+               } else if ((info->type == MCI_GPM_COEX_PROFILE_HID) &&
+                        (info->T > 0 && info->T < 50) &&
+                        (info->A > 1 || info->W > 1)) {
+                       btcoex->duty_cycle = 30;
+                       mci->aggr_limit = 8;
+                       ath_dbg(common, ATH_DBG_MCI,
+                               "Multiple attempt/timeout single HID "
+                               "aggregation limit 2 ms dutycycle 30%%\n");
+               }
+       } else if ((num_profile == 2) && (mci->num_hid == 2)) {
+               btcoex->duty_cycle = 30;
+               mci->aggr_limit = 8;
+               ath_dbg(common, ATH_DBG_MCI,
+                       "Two HIDs aggregation limit 2 ms dutycycle 30%%\n");
+       } else if (num_profile > 3) {
+               mci->aggr_limit = 6;
+               ath_dbg(common, ATH_DBG_MCI,
+                       "Three or more profiles aggregation limit 1.5 ms\n");
+       }
+
+       if (IS_CHAN_2GHZ(sc->sc_ah->curchan)) {
+               if (IS_CHAN_HT(sc->sc_ah->curchan))
+                       ath_mci_adjust_aggr_limit(btcoex);
+               else
+                       btcoex->btcoex_period >>= 1;
+       }
+
+       ath9k_hw_btcoex_disable(sc->sc_ah);
+       ath9k_btcoex_timer_pause(sc);
+
+       if (IS_CHAN_5GHZ(sc->sc_ah->curchan))
+               return;
+
+       btcoex->duty_cycle += (mci->num_bdr ? ATH_MCI_MAX_DUTY_CYCLE : 0);
+       if (btcoex->duty_cycle > ATH_MCI_MAX_DUTY_CYCLE)
+               btcoex->duty_cycle = ATH_MCI_MAX_DUTY_CYCLE;
+
+       btcoex->btcoex_period *= 1000;
+       btcoex->btcoex_no_stomp =  btcoex->btcoex_period *
+                                       (100 - btcoex->duty_cycle) / 100;
+
+       ath9k_hw_btcoex_enable(sc->sc_ah);
+       ath9k_btcoex_timer_resume(sc);
+}
+
+void ath_mci_process_profile(struct ath_softc *sc,
+                            struct ath_mci_profile_info *info)
+{
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct ath_btcoex *btcoex = &sc->btcoex;
+       struct ath_mci_profile *mci = &btcoex->mci;
+
+       if (info->start) {
+               if (!ath_mci_add_profile(common, mci, info))
+                       return;
+       } else
+               ath_mci_del_profile(common, mci, info);
+
+       btcoex->btcoex_period = ATH_MCI_DEF_BT_PERIOD;
+       mci->aggr_limit = mci->num_sco ? 6 : 0;
+       if (NUM_PROF(mci)) {
+               btcoex->bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
+               btcoex->duty_cycle = ath_mci_duty_cycle[NUM_PROF(mci)];
+       } else {
+               btcoex->bt_stomp_type = mci->num_mgmt ? ATH_BTCOEX_STOMP_ALL :
+                                                       ATH_BTCOEX_STOMP_LOW;
+               btcoex->duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE;
+       }
+
+       ath_mci_update_scheme(sc);
+}
+
+void ath_mci_process_status(struct ath_softc *sc,
+                           struct ath_mci_profile_status *status)
+{
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct ath_btcoex *btcoex = &sc->btcoex;
+       struct ath_mci_profile *mci = &btcoex->mci;
+       struct ath_mci_profile_info info;
+       int i = 0, old_num_mgmt = mci->num_mgmt;
+
+       /* Link status type are not handled */
+       if (status->is_link) {
+               ath_dbg(common, ATH_DBG_MCI,
+                       "Skip link type status update\n");
+               return;
+       }
+
+       memset(&info, 0, sizeof(struct ath_mci_profile_info));
+
+       info.conn_handle = status->conn_handle;
+       if (ath_mci_find_profile(mci, &info)) {
+               ath_dbg(common, ATH_DBG_MCI,
+                       "Skip non link state update for existing profile %d\n",
+                       status->conn_handle);
+               return;
+       }
+       if (status->conn_handle >= ATH_MCI_MAX_PROFILE) {
+               ath_dbg(common, ATH_DBG_MCI,
+                       "Ignore too many non-link update\n");
+               return;
+       }
+       if (status->is_critical)
+               __set_bit(status->conn_handle, mci->status);
+       else
+               __clear_bit(status->conn_handle, mci->status);
+
+       mci->num_mgmt = 0;
+       do {
+               if (test_bit(i, mci->status))
+                       mci->num_mgmt++;
+       } while (++i < ATH_MCI_MAX_PROFILE);
+
+       if (old_num_mgmt != mci->num_mgmt)
+               ath_mci_update_scheme(sc);
+}
diff --git a/drivers/net/wireless/ath/ath9k/mci.h b/drivers/net/wireless/ath/ath9k/mci.h
new file mode 100644 (file)
index 0000000..9590c61
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MCI_H
+#define MCI_H
+
+#define ATH_MCI_DEF_BT_PERIOD          40
+#define ATH_MCI_BDR_DUTY_CYCLE         20
+#define ATH_MCI_MAX_DUTY_CYCLE         90
+
+#define ATH_MCI_DEF_AGGR_LIMIT         6 /* in 0.24 ms */
+#define ATH_MCI_MAX_ACL_PROFILE                7
+#define ATH_MCI_MAX_SCO_PROFILE                1
+#define ATH_MCI_MAX_PROFILE            (ATH_MCI_MAX_ACL_PROFILE +\
+                                        ATH_MCI_MAX_SCO_PROFILE)
+
+#define INC_PROF(_mci, _info) do {              \
+               switch (_info->type) {           \
+               case MCI_GPM_COEX_PROFILE_RFCOMM:\
+                       _mci->num_other_acl++;   \
+                       break;                   \
+               case MCI_GPM_COEX_PROFILE_A2DP:  \
+                       _mci->num_a2dp++;        \
+                       if (!_info->edr)         \
+                               _mci->num_bdr++; \
+                       break;                   \
+               case MCI_GPM_COEX_PROFILE_HID:   \
+                       _mci->num_hid++;         \
+                       break;                   \
+               case MCI_GPM_COEX_PROFILE_BNEP:  \
+                       _mci->num_pan++;         \
+                       break;                   \
+               case MCI_GPM_COEX_PROFILE_VOICE: \
+                       _mci->num_sco++;         \
+                       break;                   \
+               default:                         \
+                       break;                   \
+               }                                \
+       } while (0)
+
+#define DEC_PROF(_mci, _info) do {              \
+               switch (_info->type) {           \
+               case MCI_GPM_COEX_PROFILE_RFCOMM:\
+                       _mci->num_other_acl--;   \
+                       break;                   \
+               case MCI_GPM_COEX_PROFILE_A2DP:  \
+                       _mci->num_a2dp--;        \
+                       if (!_info->edr)         \
+                               _mci->num_bdr--; \
+                       break;                   \
+               case MCI_GPM_COEX_PROFILE_HID:   \
+                       _mci->num_hid--;         \
+                       break;                   \
+               case MCI_GPM_COEX_PROFILE_BNEP:  \
+                       _mci->num_pan--;         \
+                       break;                   \
+               case MCI_GPM_COEX_PROFILE_VOICE: \
+                       _mci->num_sco--;         \
+                       break;                   \
+               default:                         \
+                       break;                   \
+               }                                \
+       } while (0)
+
+#define NUM_PROF(_mci) (_mci->num_other_acl + _mci->num_a2dp + \
+                        _mci->num_hid + _mci->num_pan + _mci->num_sco)
+
+struct ath_mci_profile_info {
+       u8 type;
+       u8 conn_handle;
+       bool start;
+       bool master;
+       bool edr;
+       u8 voice_type;
+       u16 T;          /* Voice: Tvoice, HID: Tsniff,        in slots */
+       u8 W;           /* Voice: Wvoice, HID: Sniff timeout, in slots */
+       u8 A;           /*                HID: Sniff attempt, in slots */
+       struct list_head list;
+};
+
+struct ath_mci_profile_status {
+       bool is_critical;
+       bool is_link;
+       u8 conn_handle;
+};
+
+struct ath_mci_profile {
+       struct list_head info;
+       DECLARE_BITMAP(status, ATH_MCI_MAX_PROFILE);
+       u16 aggr_limit;
+       u8 num_mgmt;
+       u8 num_sco;
+       u8 num_a2dp;
+       u8 num_hid;
+       u8 num_pan;
+       u8 num_other_acl;
+       u8 num_bdr;
+};
+
+void ath_mci_flush_profile(struct ath_mci_profile *mci);
+void ath_mci_process_profile(struct ath_softc *sc,
+                            struct ath_mci_profile_info *info);
+void ath_mci_process_status(struct ath_softc *sc,
+                           struct ath_mci_profile_status *status);
+#endif
index 03b0a65..55d077e 100644 (file)
@@ -601,6 +601,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
        struct sk_buff *skb;
        struct ieee80211_tx_info *tx_info;
        struct ieee80211_tx_rate *rates;
+       struct ath_mci_profile *mci = &sc->btcoex.mci;
        u32 max_4ms_framelen, frmlen;
        u16 aggr_limit, legacy = 0;
        int i;
@@ -645,7 +646,9 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
        if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy)
                return 0;
 
-       if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED)
+       if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI) && mci->aggr_limit)
+               aggr_limit = (max_4ms_framelen * mci->aggr_limit) >> 4;
+       else if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED)
                aggr_limit = min((max_4ms_framelen * 3) / 8,
                                 (u32)ATH_AMPDU_LIMIT_MAX);
        else
index f06e069..5518592 100644 (file)
@@ -446,7 +446,7 @@ static void carl9170_op_stop(struct ieee80211_hw *hw)
 
        mutex_lock(&ar->mutex);
        if (IS_ACCEPTING_CMD(ar)) {
-               rcu_assign_pointer(ar->beacon_iter, NULL);
+               RCU_INIT_POINTER(ar->beacon_iter, NULL);
 
                carl9170_led_set_state(ar, 0);
 
@@ -678,7 +678,7 @@ unlock:
                vif_priv->active = false;
                bitmap_release_region(&ar->vif_bitmap, vif_id, 0);
                ar->vifs--;
-               rcu_assign_pointer(ar->vif_priv[vif_id].vif, NULL);
+               RCU_INIT_POINTER(ar->vif_priv[vif_id].vif, NULL);
                list_del_rcu(&vif_priv->list);
                mutex_unlock(&ar->mutex);
                synchronize_rcu();
@@ -716,7 +716,7 @@ static void carl9170_op_remove_interface(struct ieee80211_hw *hw,
        WARN_ON(vif_priv->enable_beacon);
        vif_priv->enable_beacon = false;
        list_del_rcu(&vif_priv->list);
-       rcu_assign_pointer(ar->vif_priv[id].vif, NULL);
+       RCU_INIT_POINTER(ar->vif_priv[id].vif, NULL);
 
        if (vif == main_vif) {
                rcu_read_unlock();
@@ -1258,7 +1258,7 @@ static int carl9170_op_sta_add(struct ieee80211_hw *hw,
                }
 
                for (i = 0; i < CARL9170_NUM_TID; i++)
-                       rcu_assign_pointer(sta_info->agg[i], NULL);
+                       RCU_INIT_POINTER(sta_info->agg[i], NULL);
 
                sta_info->ampdu_max_len = 1 << (3 + sta->ht_cap.ampdu_factor);
                sta_info->ht_sta = true;
@@ -1285,7 +1285,7 @@ static int carl9170_op_sta_remove(struct ieee80211_hw *hw,
                        struct carl9170_sta_tid *tid_info;
 
                        tid_info = rcu_dereference(sta_info->agg[i]);
-                       rcu_assign_pointer(sta_info->agg[i], NULL);
+                       RCU_INIT_POINTER(sta_info->agg[i], NULL);
 
                        if (!tid_info)
                                continue;
@@ -1398,7 +1398,7 @@ static int carl9170_op_ampdu_action(struct ieee80211_hw *hw,
                        spin_unlock_bh(&ar->tx_ampdu_list_lock);
                }
 
-               rcu_assign_pointer(sta_info->agg[tid], NULL);
+               RCU_INIT_POINTER(sta_info->agg[tid], NULL);
                rcu_read_unlock();
 
                ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
index 85fa9cc..65ecb5b 100644 (file)
@@ -254,6 +254,8 @@ ath_reg_apply_active_scan_flags(struct wiphy *wiphy,
        int r;
 
        sband = wiphy->bands[IEEE80211_BAND_2GHZ];
+       if (!sband)
+               return;
 
        /*
         * If no country IE has been received always enable active scan
index 58ea0e5..5f77cbe 100644 (file)
@@ -175,6 +175,7 @@ void b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp,
        }
 }
 
+/* TODO: verify if needed for SSLPN or LCN  */
 static u16 b43_generate_tx_phy_ctl1(struct b43_wldev *dev, u8 bitrate)
 {
        const struct b43_phy *phy = &dev->phy;
@@ -256,6 +257,9 @@ int b43_generate_txhdr(struct b43_wldev *dev,
        unsigned int plcp_fragment_len;
        u32 mac_ctl = 0;
        u16 phy_ctl = 0;
+       bool fill_phy_ctl1 = (phy->type == B43_PHYTYPE_LP ||
+                             phy->type == B43_PHYTYPE_N ||
+                             phy->type == B43_PHYTYPE_HT);
        u8 extra_ft = 0;
        struct ieee80211_rate *txrate;
        struct ieee80211_tx_rate *rates;
@@ -531,7 +535,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
                        extra_ft |= B43_TXH_EFT_RTSFB_CCK;
 
                if (rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS &&
-                   phy->type == B43_PHYTYPE_N) {
+                   fill_phy_ctl1) {
                        txhdr->phy_ctl1_rts = cpu_to_le16(
                                b43_generate_tx_phy_ctl1(dev, rts_rate));
                        txhdr->phy_ctl1_rts_fb = cpu_to_le16(
@@ -552,7 +556,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
                break;
        }
 
-       if (phy->type == B43_PHYTYPE_N) {
+       if (fill_phy_ctl1) {
                txhdr->phy_ctl1 =
                        cpu_to_le16(b43_generate_tx_phy_ctl1(dev, rate));
                txhdr->phy_ctl1_fb =
@@ -736,7 +740,14 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
 
        /* Link quality statistics */
        switch (chanstat & B43_RX_CHAN_PHYTYPE) {
+       case B43_PHYTYPE_HT:
+               /* TODO: is max the right choice? */
+               status.signal = max_t(__s8,
+                       max(rxhdr->phy_ht_power0, rxhdr->phy_ht_power1),
+                       rxhdr->phy_ht_power2);
+               break;
        case B43_PHYTYPE_N:
+               /* Broadcom has code for min and avg, but always uses max */
                if (rxhdr->power0 == 16 || rxhdr->power0 == 32)
                        status.signal = max(rxhdr->power1, rxhdr->power2);
                else
index 16c514d..98d9074 100644 (file)
@@ -249,6 +249,12 @@ struct b43_rxhdr_fw4 {
                } __packed;
        } __packed;
        union {
+               /* HT-PHY */
+               struct {
+                       PAD_BYTES(1);
+                       __s8 phy_ht_power0;
+               } __packed;
+
                /* RSSI for N-PHYs */
                struct {
                        __s8 power2;
@@ -257,7 +263,15 @@ struct b43_rxhdr_fw4 {
 
                __le16 phy_status2;     /* PHY RX Status 2 */
        } __packed;
-       __le16 phy_status3;     /* PHY RX Status 3 */
+       union {
+               /* HT-PHY */
+               struct {
+                       __s8 phy_ht_power1;
+                       __s8 phy_ht_power2;
+               } __packed;
+
+               __le16 phy_status3;     /* PHY RX Status 3 */
+       } __packed;
        union {
                /* Tested with 598.314, 644.1001 and 666.2 */
                struct {
index b44e309..d58aa1b 100644 (file)
@@ -26,7 +26,8 @@ DHDOFILES = \
        dhd_sdio.o      \
        dhd_linux.o \
        bcmsdh.o \
-       bcmsdh_sdmmc.o
+       bcmsdh_sdmmc.o \
+       sdio_chip.o
 
 obj-$(CONFIG_BRCMFMAC) += brcmfmac.o
 brcmfmac-objs += $(DHDOFILES)
index d7d3afd..cecb5e5 100644 (file)
 #define _bcmchip_h_
 
 /* bcm4329 */
-/* SDIO device core, ID 0x829 */
-#define BCM4329_CORE_BUS_BASE          0x18011000
-/* internal memory core, ID 0x80e */
-#define BCM4329_CORE_SOCRAM_BASE       0x18003000
-/* ARM Cortex M3 core, ID 0x82a */
-#define BCM4329_CORE_ARM_BASE          0x18002000
-#define BCM4329_RAMSIZE                        0x48000
 /* firmware name */
 #define BCM4329_FW_NAME                        "brcm/bcm4329-fullmac-4.bin"
 #define BCM4329_NV_NAME                        "brcm/bcm4329-fullmac-4.txt"
index 4645766..6da519e 100644 (file)
@@ -87,7 +87,7 @@
 #define TOE_TX_CSUM_OL         0x00000001
 #define TOE_RX_CSUM_OL         0x00000002
 
-#define        BRCMF_BSS_INFO_VERSION  108 /* current ver of brcmf_bss_info struct */
+#define        BRCMF_BSS_INFO_VERSION  108 /* curr ver of brcmf_bss_info_le struct */
 
 /* size of brcmf_scan_params not including variable length array */
 #define BRCMF_SCAN_PARAMS_FIXED_SIZE 64
 
 /* For supporting multiple interfaces */
 #define BRCMF_MAX_IFS  16
-#define BRCMF_DEL_IF   -0xe
-#define BRCMF_BAD_IF   -0xf
 
 #define DOT11_BSSTYPE_ANY                      2
 #define DOT11_MAX_DEFAULT_KEYS 4
@@ -365,7 +363,7 @@ struct brcmf_pkt_filter_enable_le {
  * Applications MUST CHECK ie_offset field and length field to access IEs and
  * next bss_info structure in a vector (in struct brcmf_scan_results)
  */
-struct brcmf_bss_info {
+struct brcmf_bss_info_le {
        __le32 version;         /* version field */
        __le32 length;          /* byte length of data in this record,
                                 * starting at version and including IEs
@@ -466,14 +464,13 @@ struct brcmf_scan_results {
        u32 buflen;
        u32 version;
        u32 count;
-       struct brcmf_bss_info bss_info[1];
+       struct brcmf_bss_info_le bss_info_le[];
 };
 
 struct brcmf_scan_results_le {
        __le32 buflen;
        __le32 version;
        __le32 count;
-       struct brcmf_bss_info bss_info[1];
 };
 
 /* used for association with a specific BSSID and chanspec list */
@@ -493,10 +490,6 @@ struct brcmf_join_params {
        struct brcmf_assoc_params_le params_le;
 };
 
-/* size of brcmf_scan_results not including variable length array */
-#define BRCMF_SCAN_RESULTS_FIXED_SIZE \
-       (sizeof(struct brcmf_scan_results) - sizeof(struct brcmf_bss_info))
-
 /* incremental scan results struct */
 struct brcmf_iscan_results {
        union {
@@ -511,7 +504,7 @@ struct brcmf_iscan_results {
 
 /* size of brcmf_iscan_results not including variable length array */
 #define BRCMF_ISCAN_RESULTS_FIXED_SIZE \
-       (BRCMF_SCAN_RESULTS_FIXED_SIZE + \
+       (sizeof(struct brcmf_scan_results) + \
         offsetof(struct brcmf_iscan_results, results))
 
 struct brcmf_wsec_key {
@@ -734,8 +727,7 @@ extern int brcmf_c_host_event(struct brcmf_info *drvr_priv, int *idx,
 extern void brcmf_c_init(void);
 
 extern int brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx,
-                       struct net_device *ndev, char *name, u8 *mac_addr,
-                       u32 flags, u8 bssidx);
+                       char *name, u8 *mac_addr);
 extern void brcmf_del_if(struct brcmf_info *drvr_priv, int ifidx);
 
 /* Send packet to dongle via data channel */
index 8918261..40928e5 100644 (file)
@@ -488,10 +488,9 @@ brcmf_c_host_event(struct brcmf_info *drvr_priv, int *ifidx, void *pktdata,
 
                if (ifevent->ifidx > 0 && ifevent->ifidx < BRCMF_MAX_IFS) {
                        if (ifevent->action == BRCMF_E_IF_ADD)
-                               brcmf_add_if(drvr_priv, ifevent->ifidx, NULL,
+                               brcmf_add_if(drvr_priv, ifevent->ifidx,
                                             event->ifname,
-                                            pvt_data->eth.h_dest,
-                                            ifevent->flags, ifevent->bssidx);
+                                            pvt_data->eth.h_dest);
                        else
                                brcmf_del_if(drvr_priv, ifevent->ifidx);
                } else {
index 4acbac5..719fd93 100644 (file)
@@ -58,7 +58,6 @@ struct brcmf_if {
        struct net_device *ndev;
        struct net_device_stats stats;
        int idx;                /* iface idx in dongle */
-       int state;              /* interface state */
        u8 mac_addr[ETH_ALEN];  /* assigned MAC address */
 };
 
@@ -80,20 +79,6 @@ struct brcmf_info {
 /* Error bits */
 module_param(brcmf_msg_level, int, 0);
 
-
-static int brcmf_net2idx(struct brcmf_info *drvr_priv, struct net_device *ndev)
-{
-       int i = 0;
-
-       while (i < BRCMF_MAX_IFS) {
-               if (drvr_priv->iflist[i] && drvr_priv->iflist[i]->ndev == ndev)
-                       return i;
-               i++;
-       }
-
-       return BRCMF_BAD_IF;
-}
-
 int brcmf_ifname2idx(struct brcmf_info *drvr_priv, char *name)
 {
        int i = BRCMF_MAX_IFS;
@@ -285,14 +270,9 @@ _brcmf_set_mac_address(struct work_struct *work)
 
 static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr)
 {
-       struct brcmf_info *drvr_priv = *(struct brcmf_info **)
-                                       netdev_priv(ndev);
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_info *drvr_priv = ifp->info;
        struct sockaddr *sa = (struct sockaddr *)addr;
-       int ifidx;
-
-       ifidx = brcmf_net2idx(drvr_priv, ndev);
-       if (ifidx == BRCMF_BAD_IF)
-               return -1;
 
        memcpy(&drvr_priv->macvalue, sa->sa_data, ETH_ALEN);
        schedule_work(&drvr_priv->setmacaddr_work);
@@ -301,13 +281,8 @@ static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr)
 
 static void brcmf_netdev_set_multicast_list(struct net_device *ndev)
 {
-       struct brcmf_info *drvr_priv = *(struct brcmf_info **)
-                                       netdev_priv(ndev);
-       int ifidx;
-
-       ifidx = brcmf_net2idx(drvr_priv, ndev);
-       if (ifidx == BRCMF_BAD_IF)
-               return;
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_info *drvr_priv = ifp->info;
 
        schedule_work(&drvr_priv->multicast_work);
 }
@@ -341,9 +316,8 @@ int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx, struct sk_buff *pktbuf)
 static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 {
        int ret;
-       struct brcmf_info *drvr_priv = *(struct brcmf_info **)
-                                       netdev_priv(ndev);
-       int ifidx;
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_info *drvr_priv = ifp->info;
 
        brcmf_dbg(TRACE, "Enter\n");
 
@@ -355,9 +329,8 @@ static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                return -ENODEV;
        }
 
-       ifidx = brcmf_net2idx(drvr_priv, ndev);
-       if (ifidx == BRCMF_BAD_IF) {
-               brcmf_dbg(ERROR, "bad ifidx %d\n", ifidx);
+       if (!drvr_priv->iflist[ifp->idx]) {
+               brcmf_dbg(ERROR, "bad ifidx %d\n", ifp->idx);
                netif_stop_queue(ndev);
                return -ENODEV;
        }
@@ -367,20 +340,20 @@ static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                struct sk_buff *skb2;
 
                brcmf_dbg(INFO, "%s: insufficient headroom\n",
-                         brcmf_ifname(&drvr_priv->pub, ifidx));
+                         brcmf_ifname(&drvr_priv->pub, ifp->idx));
                drvr_priv->pub.tx_realloc++;
                skb2 = skb_realloc_headroom(skb, drvr_priv->pub.hdrlen);
                dev_kfree_skb(skb);
                skb = skb2;
                if (skb == NULL) {
                        brcmf_dbg(ERROR, "%s: skb_realloc_headroom failed\n",
-                                 brcmf_ifname(&drvr_priv->pub, ifidx));
+                                 brcmf_ifname(&drvr_priv->pub, ifp->idx));
                        ret = -ENOMEM;
                        goto done;
                }
        }
 
-       ret = brcmf_sendpkt(&drvr_priv->pub, ifidx, skb);
+       ret = brcmf_sendpkt(&drvr_priv->pub, ifp->idx, skb);
 
 done:
        if (ret)
@@ -482,12 +455,10 @@ void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx, struct sk_buff *skb,
                                          skb_mac_header(skb),
                                          &event, &data);
 
-               if (drvr_priv->iflist[ifidx] &&
-                   !drvr_priv->iflist[ifidx]->state)
+               if (drvr_priv->iflist[ifidx]) {
                        ifp = drvr_priv->iflist[ifidx];
-
-               if (ifp->ndev)
                        ifp->ndev->last_rx = jiffies;
+               }
 
                drvr->dstats.rx_bytes += skb->len;
                drvr->rx_packets++;     /* Local count */
@@ -524,19 +495,11 @@ void brcmf_txcomplete(struct brcmf_pub *drvr, struct sk_buff *txp, bool success)
 
 static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev)
 {
-       struct brcmf_info *drvr_priv = *(struct brcmf_info **)
-                                       netdev_priv(ndev);
-       struct brcmf_if *ifp;
-       int ifidx;
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_info *drvr_priv = ifp->info;
 
        brcmf_dbg(TRACE, "Enter\n");
 
-       ifidx = brcmf_net2idx(drvr_priv, ndev);
-       if (ifidx == BRCMF_BAD_IF)
-               return NULL;
-
-       ifp = drvr_priv->iflist[ifidx];
-
        if (drvr_priv->pub.up)
                /* Use the protocol to get dongle stats */
                brcmf_proto_dstats(&drvr_priv->pub);
@@ -637,8 +600,8 @@ static int brcmf_toe_set(struct brcmf_info *drvr_priv, int ifidx, u32 toe_ol)
 static void brcmf_ethtool_get_drvinfo(struct net_device *ndev,
                                    struct ethtool_drvinfo *info)
 {
-       struct brcmf_info *drvr_priv = *(struct brcmf_info **)
-                                       netdev_priv(ndev);
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_info *drvr_priv = ifp->info;
 
        sprintf(info->driver, KBUILD_MODNAME);
        sprintf(info->version, "%lu", drvr_priv->pub.drv_version);
@@ -765,14 +728,12 @@ static int brcmf_ethtool(struct brcmf_info *drvr_priv, void __user *uaddr)
 static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr,
                                    int cmd)
 {
-       struct brcmf_info *drvr_priv = *(struct brcmf_info **)
-                                       netdev_priv(ndev);
-       int ifidx;
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_info *drvr_priv = ifp->info;
 
-       ifidx = brcmf_net2idx(drvr_priv, ndev);
-       brcmf_dbg(TRACE, "ifidx %d, cmd 0x%04x\n", ifidx, cmd);
+       brcmf_dbg(TRACE, "ifidx %d, cmd 0x%04x\n", ifp->idx, cmd);
 
-       if (ifidx == BRCMF_BAD_IF)
+       if (!drvr_priv->iflist[ifp->idx])
                return -1;
 
        if (cmd == SIOCETHTOOL)
@@ -788,17 +749,14 @@ s32 brcmf_exec_dcmd(struct net_device *ndev, u32 cmd, void *arg, u32 len)
        s32 err = 0;
        int buflen = 0;
        bool is_set_key_cmd;
-       struct brcmf_info *drvr_priv = *(struct brcmf_info **)
-                                       netdev_priv(ndev);
-       int ifidx;
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_info *drvr_priv = ifp->info;
 
        memset(&dcmd, 0, sizeof(dcmd));
        dcmd.cmd = cmd;
        dcmd.buf = arg;
        dcmd.len = len;
 
-       ifidx = brcmf_net2idx(drvr_priv, ndev);
-
        if (dcmd.buf != NULL)
                buflen = min_t(uint, dcmd.len, BRCMF_DCMD_MAXLEN);
 
@@ -826,7 +784,7 @@ s32 brcmf_exec_dcmd(struct net_device *ndev, u32 cmd, void *arg, u32 len)
        if (is_set_key_cmd)
                brcmf_netdev_wait_pend8021x(ndev);
 
-       err = brcmf_proto_dcmd(&drvr_priv->pub, ifidx, &dcmd, buflen);
+       err = brcmf_proto_dcmd(&drvr_priv->pub, ifp->idx, &dcmd, buflen);
 
 done:
        if (err > 0)
@@ -837,7 +795,8 @@ done:
 
 static int brcmf_netdev_stop(struct net_device *ndev)
 {
-       struct brcmf_pub *drvr = *(struct brcmf_pub **) netdev_priv(ndev);
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_pub *drvr = &ifp->info->pub;
 
        brcmf_dbg(TRACE, "Enter\n");
        brcmf_cfg80211_down(drvr->config);
@@ -853,16 +812,14 @@ static int brcmf_netdev_stop(struct net_device *ndev)
 
 static int brcmf_netdev_open(struct net_device *ndev)
 {
-       struct brcmf_info *drvr_priv = *(struct brcmf_info **)
-                                       netdev_priv(ndev);
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_info *drvr_priv = ifp->info;
        u32 toe_ol;
-       int ifidx = brcmf_net2idx(drvr_priv, ndev);
        s32 ret = 0;
 
-       brcmf_dbg(TRACE, "ifidx %d\n", ifidx);
-
-       if (ifidx == 0) {       /* do it only for primary eth0 */
+       brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx);
 
+       if (ifp->idx == 0) {    /* do it only for primary eth0 */
                /* try to bring up bus */
                ret = brcmf_bus_start(&drvr_priv->pub);
                if (ret != 0) {
@@ -874,12 +831,12 @@ static int brcmf_netdev_open(struct net_device *ndev)
                memcpy(ndev->dev_addr, drvr_priv->pub.mac, ETH_ALEN);
 
                /* Get current TOE mode from dongle */
-               if (brcmf_toe_get(drvr_priv, ifidx, &toe_ol) >= 0
+               if (brcmf_toe_get(drvr_priv, ifp->idx, &toe_ol) >= 0
                    && (toe_ol & TOE_TX_CSUM_OL) != 0)
-                       drvr_priv->iflist[ifidx]->ndev->features |=
+                       drvr_priv->iflist[ifp->idx]->ndev->features |=
                                NETIF_F_IP_CSUM;
                else
-                       drvr_priv->iflist[ifidx]->ndev->features &=
+                       drvr_priv->iflist[ifp->idx]->ndev->features &=
                                ~NETIF_F_IP_CSUM;
        }
        /* Allow transmit calls */
@@ -893,75 +850,62 @@ static int brcmf_netdev_open(struct net_device *ndev)
        return ret;
 }
 
+static const struct net_device_ops brcmf_netdev_ops_pri = {
+       .ndo_open = brcmf_netdev_open,
+       .ndo_stop = brcmf_netdev_stop,
+       .ndo_get_stats = brcmf_netdev_get_stats,
+       .ndo_do_ioctl = brcmf_netdev_ioctl_entry,
+       .ndo_start_xmit = brcmf_netdev_start_xmit,
+       .ndo_set_mac_address = brcmf_netdev_set_mac_address,
+       .ndo_set_rx_mode = brcmf_netdev_set_multicast_list
+};
+
 int
-brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx, struct net_device *ndev,
-            char *name, u8 *mac_addr, u32 flags, u8 bssidx)
+brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx, char *name, u8 *mac_addr)
 {
        struct brcmf_if *ifp;
-       int ret = 0, err = 0;
+       struct net_device *ndev;
 
-       brcmf_dbg(TRACE, "idx %d, handle->%p\n", ifidx, ndev);
+       brcmf_dbg(TRACE, "idx %d\n", ifidx);
 
        ifp = drvr_priv->iflist[ifidx];
-       if (!ifp) {
-               ifp = kmalloc(sizeof(struct brcmf_if), GFP_ATOMIC);
-               if (!ifp)
-                       return -ENOMEM;
+       /*
+        * Delete the existing interface before overwriting it
+        * in case we missed the BRCMF_E_IF_DEL event.
+        */
+       if (ifp) {
+               brcmf_dbg(ERROR, "ERROR: netdev:%s already exists, try free & unregister\n",
+                         ifp->ndev->name);
+               netif_stop_queue(ifp->ndev);
+               unregister_netdev(ifp->ndev);
+               free_netdev(ifp->ndev);
+               drvr_priv->iflist[ifidx] = NULL;
+       }
+
+       /* Allocate netdev, including space for private structure */
+       ndev = alloc_netdev(sizeof(struct brcmf_if), name, ether_setup);
+       if (!ndev) {
+               brcmf_dbg(ERROR, "OOM - alloc_netdev\n");
+               return -ENOMEM;
        }
 
-       memset(ifp, 0, sizeof(struct brcmf_if));
+       ifp = netdev_priv(ndev);
+       ifp->ndev = ndev;
        ifp->info = drvr_priv;
        drvr_priv->iflist[ifidx] = ifp;
+       ifp->idx = ifidx;
        if (mac_addr != NULL)
                memcpy(&ifp->mac_addr, mac_addr, ETH_ALEN);
 
-       if (ndev == NULL) {
-               ifp->state = BRCMF_E_IF_ADD;
-               ifp->idx = ifidx;
-               /*
-                * Delete the existing interface before overwriting it
-                * in case we missed the BRCMF_E_IF_DEL event.
-                */
-               if (ifp->ndev != NULL) {
-                       brcmf_dbg(ERROR, "ERROR: netdev:%s already exists, try free & unregister\n",
-                                 ifp->ndev->name);
-                       netif_stop_queue(ifp->ndev);
-                       unregister_netdev(ifp->ndev);
-                       free_netdev(ifp->ndev);
-               }
-
-               /* Allocate netdev, including space for private structure */
-               ifp->ndev = alloc_netdev(sizeof(drvr_priv), "wlan%d",
-                                        ether_setup);
-               if (!ifp->ndev) {
-                       brcmf_dbg(ERROR, "OOM - alloc_netdev\n");
-                       ret = -ENOMEM;
-               }
-
-               if (ret == 0) {
-                       memcpy(netdev_priv(ifp->ndev), &drvr_priv,
-                              sizeof(drvr_priv));
-                       err = brcmf_net_attach(&drvr_priv->pub, ifp->idx);
-                       if (err != 0) {
-                               brcmf_dbg(ERROR, "brcmf_net_attach failed, err %d\n",
-                                         err);
-                               ret = -EOPNOTSUPP;
-                       } else {
-                               brcmf_dbg(TRACE, " ==== pid:%x, net_device for if:%s created ===\n",
-                                         current->pid, ifp->ndev->name);
-                               ifp->state = 0;
-                       }
-               }
-
-               if (ret < 0) {
-                       if (ifp->ndev)
-                               free_netdev(ifp->ndev);
+       if (brcmf_net_attach(&drvr_priv->pub, ifp->idx)) {
+               brcmf_dbg(ERROR, "brcmf_net_attach failed");
+               free_netdev(ifp->ndev);
+               drvr_priv->iflist[ifidx] = NULL;
+               return -EOPNOTSUPP;
+       }
 
-                       drvr_priv->iflist[ifp->idx] = NULL;
-                       kfree(ifp);
-               }
-       } else
-               ifp->ndev = ndev;
+       brcmf_dbg(TRACE, " ==== pid:%x, net_device for if:%s created ===\n",
+                 current->pid, ifp->ndev->name);
 
        return 0;
 }
@@ -977,47 +921,36 @@ void brcmf_del_if(struct brcmf_info *drvr_priv, int ifidx)
                brcmf_dbg(ERROR, "Null interface\n");
                return;
        }
+       if (ifp->ndev) {
+               if (ifidx == 0) {
+                       if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
+                               rtnl_lock();
+                               brcmf_netdev_stop(ifp->ndev);
+                               rtnl_unlock();
+                       }
+               } else {
+                       netif_stop_queue(ifp->ndev);
+               }
 
-       ifp->state = BRCMF_E_IF_DEL;
-       ifp->idx = ifidx;
-       if (ifp->ndev != NULL) {
-               netif_stop_queue(ifp->ndev);
                unregister_netdev(ifp->ndev);
-               free_netdev(ifp->ndev);
                drvr_priv->iflist[ifidx] = NULL;
-               kfree(ifp);
+               if (ifidx == 0)
+                       brcmf_cfg80211_detach(drvr_priv->pub.config);
+               free_netdev(ifp->ndev);
        }
 }
 
 struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, uint bus_hdrlen)
 {
        struct brcmf_info *drvr_priv = NULL;
-       struct net_device *ndev;
 
        brcmf_dbg(TRACE, "Enter\n");
 
-       /* Allocate netdev, including space for private structure */
-       ndev = alloc_netdev(sizeof(drvr_priv), "wlan%d", ether_setup);
-       if (!ndev) {
-               brcmf_dbg(ERROR, "OOM - alloc_netdev\n");
-               goto fail;
-       }
-
        /* Allocate primary brcmf_info */
        drvr_priv = kzalloc(sizeof(struct brcmf_info), GFP_ATOMIC);
        if (!drvr_priv)
                goto fail;
 
-       /*
-        * Save the brcmf_info into the priv
-        */
-       memcpy(netdev_priv(ndev), &drvr_priv, sizeof(drvr_priv));
-
-       if (brcmf_add_if(drvr_priv, 0, ndev, ndev->name, NULL, 0, 0) ==
-           BRCMF_BAD_IF)
-               goto fail;
-
-       ndev->netdev_ops = NULL;
        mutex_init(&drvr_priv->proto_block);
 
        /* Link to info module */
@@ -1033,29 +966,12 @@ struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, uint bus_hdrlen)
                goto fail;
        }
 
-       /* Attach and link in the cfg80211 */
-       drvr_priv->pub.config =
-                       brcmf_cfg80211_attach(ndev,
-                                             brcmf_bus_get_device(bus),
-                                             &drvr_priv->pub);
-       if (drvr_priv->pub.config == NULL) {
-               brcmf_dbg(ERROR, "wl_cfg80211_attach failed\n");
-               goto fail;
-       }
-
        INIT_WORK(&drvr_priv->setmacaddr_work, _brcmf_set_mac_address);
        INIT_WORK(&drvr_priv->multicast_work, _brcmf_set_multicast_list);
 
-       /*
-        * Save the brcmf_info into the priv
-        */
-       memcpy(netdev_priv(ndev), &drvr_priv, sizeof(drvr_priv));
-
        return &drvr_priv->pub;
 
 fail:
-       if (ndev)
-               free_netdev(ndev);
        if (drvr_priv)
                brcmf_detach(&drvr_priv->pub);
 
@@ -1123,16 +1039,6 @@ int brcmf_bus_start(struct brcmf_pub *drvr)
        return 0;
 }
 
-static struct net_device_ops brcmf_netdev_ops_pri = {
-       .ndo_open = brcmf_netdev_open,
-       .ndo_stop = brcmf_netdev_stop,
-       .ndo_get_stats = brcmf_netdev_get_stats,
-       .ndo_do_ioctl = brcmf_netdev_ioctl_entry,
-       .ndo_start_xmit = brcmf_netdev_start_xmit,
-       .ndo_set_mac_address = brcmf_netdev_set_mac_address,
-       .ndo_set_rx_mode = brcmf_netdev_set_multicast_list
-};
-
 int brcmf_net_attach(struct brcmf_pub *drvr, int ifidx)
 {
        struct brcmf_info *drvr_priv = drvr->info;
@@ -1169,6 +1075,18 @@ int brcmf_net_attach(struct brcmf_pub *drvr, int ifidx)
 
        memcpy(ndev->dev_addr, temp_addr, ETH_ALEN);
 
+       /* attach to cfg80211 for primary interface */
+       if (!ifidx) {
+               drvr->config =
+                       brcmf_cfg80211_attach(ndev,
+                                             brcmf_bus_get_device(drvr->bus),
+                                             drvr);
+               if (drvr->config == NULL) {
+                       brcmf_dbg(ERROR, "wl_cfg80211_attach failed\n");
+                       goto fail;
+               }
+       }
+
        if (register_netdev(ndev) != 0) {
                brcmf_dbg(ERROR, "couldn't register the net device\n");
                goto fail;
@@ -1210,21 +1128,13 @@ void brcmf_detach(struct brcmf_pub *drvr)
        if (drvr) {
                drvr_priv = drvr->info;
                if (drvr_priv) {
-                       struct brcmf_if *ifp;
                        int i;
 
-                       for (i = 1; i < BRCMF_MAX_IFS; i++)
+                       /* make sure primary interface removed last */
+                       for (i = BRCMF_MAX_IFS-1; i > -1; i--)
                                if (drvr_priv->iflist[i])
                                        brcmf_del_if(drvr_priv, i);
 
-                       ifp = drvr_priv->iflist[0];
-                       if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
-                               rtnl_lock();
-                               brcmf_netdev_stop(ifp->ndev);
-                               rtnl_unlock();
-                               unregister_netdev(ifp->ndev);
-                       }
-
                        cancel_work_sync(&drvr_priv->setmacaddr_work);
                        cancel_work_sync(&drvr_priv->multicast_work);
 
@@ -1233,10 +1143,6 @@ void brcmf_detach(struct brcmf_pub *drvr)
                        if (drvr->prot)
                                brcmf_proto_detach(drvr);
 
-                       brcmf_cfg80211_detach(drvr->config);
-
-                       free_netdev(ifp->ndev);
-                       kfree(ifp);
                        kfree(drvr_priv);
                }
        }
@@ -1302,7 +1208,8 @@ static int brcmf_get_pend_8021x_cnt(struct brcmf_info *drvr_priv)
 
 int brcmf_netdev_wait_pend8021x(struct net_device *ndev)
 {
-       struct brcmf_info *drvr_priv = *(struct brcmf_info **)netdev_priv(ndev);
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_info *drvr_priv = ifp->info;
        int timeout = 10 * HZ / 1000;
        int ntimes = MAX_WAIT_FOR_8021X_TX;
        int pend = brcmf_get_pend_8021x_cnt(drvr_priv);
index 313b8bf..22913af 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/semaphore.h>
 #include <linux/firmware.h>
 #include <linux/module.h>
+#include <linux/bcma/bcma.h>
 #include <asm/unaligned.h>
 #include <defs.h>
 #include <brcmu_wifi.h>
@@ -35,6 +36,7 @@
 #include <brcm_hw_ids.h>
 #include <soc.h>
 #include "sdio_host.h"
+#include "sdio_chip.h"
 
 #define DCMD_RESP_TIMEOUT  2000        /* In milli second */
 
@@ -134,33 +136,6 @@ struct rte_console {
 /*   Force no backplane reset */
 #define SBSDIO_DEVCTL_RST_NOBPRESET    0x20
 
-/* SBSDIO_FUNC1_CHIPCLKCSR */
-
-/* Force ALP request to backplane */
-#define SBSDIO_FORCE_ALP               0x01
-/* Force HT request to backplane */
-#define SBSDIO_FORCE_HT                        0x02
-/* Force ILP request to backplane */
-#define SBSDIO_FORCE_ILP               0x04
-/* Make ALP ready (power up xtal) */
-#define SBSDIO_ALP_AVAIL_REQ           0x08
-/* Make HT ready (power up PLL) */
-#define SBSDIO_HT_AVAIL_REQ            0x10
-/* Squelch clock requests from HW */
-#define SBSDIO_FORCE_HW_CLKREQ_OFF     0x20
-/* Status: ALP is ready */
-#define SBSDIO_ALP_AVAIL               0x40
-/* Status: HT is ready */
-#define SBSDIO_HT_AVAIL                        0x80
-
-#define SBSDIO_AVBITS          (SBSDIO_HT_AVAIL | SBSDIO_ALP_AVAIL)
-#define SBSDIO_ALPAV(regval)   ((regval) & SBSDIO_AVBITS)
-#define SBSDIO_HTAV(regval)    (((regval) & SBSDIO_AVBITS) == SBSDIO_AVBITS)
-#define SBSDIO_ALPONLY(regval) (SBSDIO_ALPAV(regval) && !SBSDIO_HTAV(regval))
-
-#define SBSDIO_CLKAV(regval, alponly) \
-       (SBSDIO_ALPAV(regval) && (alponly ? 1 : SBSDIO_HTAV(regval)))
-
 /* direct(mapped) cis space */
 
 /* MAPPED common CIS address */
@@ -335,50 +310,6 @@ struct rte_console {
 /* Flags for SDH calls */
 #define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
 
-/* sbimstate */
-#define        SBIM_IBE                0x20000 /* inbanderror */
-#define        SBIM_TO                 0x40000 /* timeout */
-#define        SBIM_BY                 0x01800000      /* busy (sonics >= 2.3) */
-#define        SBIM_RJ                 0x02000000      /* reject (sonics >= 2.3) */
-
-/* sbtmstatelow */
-
-/* reset */
-#define        SBTML_RESET             0x0001
-/* reject field */
-#define        SBTML_REJ_MASK          0x0006
-/* reject */
-#define        SBTML_REJ               0x0002
-/* temporary reject, for error recovery */
-#define        SBTML_TMPREJ            0x0004
-
-/* Shift to locate the SI control flags in sbtml */
-#define        SBTML_SICF_SHIFT        16
-
-/* sbtmstatehigh */
-#define        SBTMH_SERR              0x0001  /* serror */
-#define        SBTMH_INT               0x0002  /* interrupt */
-#define        SBTMH_BUSY              0x0004  /* busy */
-#define        SBTMH_TO                0x0020  /* timeout (sonics >= 2.3) */
-
-/* Shift to locate the SI status flags in sbtmh */
-#define        SBTMH_SISF_SHIFT        16
-
-/* sbidlow */
-#define        SBIDL_INIT              0x80    /* initiator */
-
-/* sbidhigh */
-#define        SBIDH_RC_MASK           0x000f  /* revision code */
-#define        SBIDH_RCE_MASK          0x7000  /* revision code extension field */
-#define        SBIDH_RCE_SHIFT         8
-#define        SBCOREREV(sbidh) \
-       ((((sbidh) & SBIDH_RCE_MASK) >> SBIDH_RCE_SHIFT) | \
-         ((sbidh) & SBIDH_RC_MASK))
-#define        SBIDH_CC_MASK           0x8ff0  /* core code */
-#define        SBIDH_CC_SHIFT          4
-#define        SBIDH_VC_MASK           0xffff0000      /* vendor code */
-#define        SBIDH_VC_SHIFT          16
-
 /*
  * Conversion of 802.1D priority to precedence level
  */
@@ -388,17 +319,6 @@ static uint prio2prec(u32 prio)
               (prio^2) : prio;
 }
 
-/*
- * Core reg address translation.
- * Both macro's returns a 32 bits byte address on the backplane bus.
- */
-#define CORE_CC_REG(base, field) \
-               (base + offsetof(struct chipcregs, field))
-#define CORE_BUS_REG(base, field) \
-               (base + offsetof(struct sdpcmd_regs, field))
-#define CORE_SB(base, field) \
-               (base + SBCONFIGOFF + offsetof(struct sbconfig, field))
-
 /* core registers */
 struct sdpcmd_regs {
        u32 corecontrol;                /* 0x00, rev8 */
@@ -524,21 +444,6 @@ struct sdpcm_shared_le {
 
 
 /* misc chip info needed by some of the routines */
-struct chip_info {
-       u32 chip;
-       u32 chiprev;
-       u32 cccorebase;
-       u32 ccrev;
-       u32 cccaps;
-       u32 buscorebase; /* 32 bits backplane bus address */
-       u32 buscorerev;
-       u32 buscoretype;
-       u32 ramcorebase;
-       u32 armcorebase;
-       u32 pmurev;
-       u32 ramsize;
-};
-
 /* Private data for SDIO bus interaction */
 struct brcmf_bus {
        struct brcmf_pub *drvr;
@@ -574,7 +479,7 @@ struct brcmf_bus {
        uint txminmax;
 
        struct sk_buff *glomd;  /* Packet containing glomming descriptor */
-       struct sk_buff *glom;   /* Packet chain for glommed superframe */
+       struct sk_buff_head glom; /* Packet list for glommed superframe */
        uint glomerr;           /* Glom packet read errors */
 
        u8 *rxbuf;              /* Buffer for receiving control packets */
@@ -663,46 +568,6 @@ struct brcmf_bus {
        u32 fw_ptr;
 };
 
-struct sbconfig {
-       u32 PAD[2];
-       u32 sbipsflag;  /* initiator port ocp slave flag */
-       u32 PAD[3];
-       u32 sbtpsflag;  /* target port ocp slave flag */
-       u32 PAD[11];
-       u32 sbtmerrloga;        /* (sonics >= 2.3) */
-       u32 PAD;
-       u32 sbtmerrlog; /* (sonics >= 2.3) */
-       u32 PAD[3];
-       u32 sbadmatch3; /* address match3 */
-       u32 PAD;
-       u32 sbadmatch2; /* address match2 */
-       u32 PAD;
-       u32 sbadmatch1; /* address match1 */
-       u32 PAD[7];
-       u32 sbimstate;  /* initiator agent state */
-       u32 sbintvec;   /* interrupt mask */
-       u32 sbtmstatelow;       /* target state */
-       u32 sbtmstatehigh;      /* target state */
-       u32 sbbwa0;             /* bandwidth allocation table0 */
-       u32 PAD;
-       u32 sbimconfiglow;      /* initiator configuration */
-       u32 sbimconfighigh;     /* initiator configuration */
-       u32 sbadmatch0; /* address match0 */
-       u32 PAD;
-       u32 sbtmconfiglow;      /* target configuration */
-       u32 sbtmconfighigh;     /* target configuration */
-       u32 sbbconfig;  /* broadcast configuration */
-       u32 PAD;
-       u32 sbbstate;   /* broadcast state */
-       u32 PAD[3];
-       u32 sbactcnfg;  /* activate configuration */
-       u32 PAD[3];
-       u32 sbflagst;   /* current sbflags */
-       u32 PAD[3];
-       u32 sbidlow;            /* identification */
-       u32 sbidhigh;   /* identification */
-};
-
 /* clkstate */
 #define CLK_NONE       0
 #define CLK_SDONLY     1
@@ -750,10 +615,12 @@ static bool data_ok(struct brcmf_bus *bus)
 static void
 r_sdreg32(struct brcmf_bus *bus, u32 *regvar, u32 reg_offset, u32 *retryvar)
 {
+       u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
        *retryvar = 0;
        do {
                *regvar = brcmf_sdcard_reg_read(bus->sdiodev,
-                               bus->ci->buscorebase + reg_offset, sizeof(u32));
+                               bus->ci->c_inf[idx].base + reg_offset,
+                               sizeof(u32));
        } while (brcmf_sdcard_regfail(bus->sdiodev) &&
                 (++(*retryvar) <= retry_limit));
        if (*retryvar) {
@@ -768,10 +635,11 @@ r_sdreg32(struct brcmf_bus *bus, u32 *regvar, u32 reg_offset, u32 *retryvar)
 static void
 w_sdreg32(struct brcmf_bus *bus, u32 regval, u32 reg_offset, u32 *retryvar)
 {
+       u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
        *retryvar = 0;
        do {
                brcmf_sdcard_reg_write(bus->sdiodev,
-                                      bus->ci->buscorebase + reg_offset,
+                                      bus->ci->c_inf[idx].base + reg_offset,
                                       sizeof(u32), regval);
        } while (brcmf_sdcard_regfail(bus->sdiodev) &&
                 (++(*retryvar) <= retry_limit));
@@ -812,10 +680,6 @@ static int brcmf_sdbrcm_htclk(struct brcmf_bus *bus, bool on, bool pendok)
                clkreq =
                    bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;
 
-               if ((bus->ci->chip == BCM4329_CHIP_ID)
-                   && (bus->ci->chiprev == 0))
-                       clkreq |= SBSDIO_FORCE_ALP;
-
                brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
                                       SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
                if (err) {
@@ -823,14 +687,6 @@ static int brcmf_sdbrcm_htclk(struct brcmf_bus *bus, bool on, bool pendok)
                        return -EBADE;
                }
 
-               if (pendok && ((bus->ci->buscoretype == PCMCIA_CORE_ID)
-                              && (bus->ci->buscorerev == 9))) {
-                       u32 dummy, retries;
-                       r_sdreg32(bus, &dummy,
-                                 offsetof(struct sdpcmd_regs, clockctlstatus),
-                                 &retries);
-               }
-
                /* Check current status */
                clkctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
                                               SBSDIO_FUNC1_CHIPCLKCSR, &err);
@@ -1034,11 +890,9 @@ static int brcmf_sdbrcm_bussleep(struct brcmf_bus *bus, bool sleep)
                        SBSDIO_FORCE_HW_CLKREQ_OFF, NULL);
 
                /* Isolate the bus */
-               if (bus->ci->chip != BCM4329_CHIP_ID) {
-                       brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
-                               SBSDIO_DEVICE_CTL,
-                               SBSDIO_DEVCTL_PADS_ISO, NULL);
-               }
+               brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+                       SBSDIO_DEVICE_CTL,
+                       SBSDIO_DEVCTL_PADS_ISO, NULL);
 
                /* Change state */
                bus->sleeping = true;
@@ -1049,13 +903,6 @@ static int brcmf_sdbrcm_bussleep(struct brcmf_bus *bus, bool sleep)
                brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
                        SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
 
-               /* Force pad isolation off if possible
-                        (in case power never toggled) */
-               if ((bus->ci->buscoretype == PCMCIA_CORE_ID)
-                   && (bus->ci->buscorerev >= 10))
-                       brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
-                               SBSDIO_DEVICE_CTL, 0, NULL);
-
                /* Make sure the controller has the bus up */
                brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
 
@@ -1222,6 +1069,51 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_bus *bus, bool abort, bool rtx)
                bus->drvr->busstate = BRCMF_BUS_DOWN;
 }
 
+/* copy a buffer into a pkt buffer chain */
+static uint brcmf_sdbrcm_glom_from_buf(struct brcmf_bus *bus, uint len)
+{
+       uint n, ret = 0;
+       struct sk_buff *p;
+       u8 *buf;
+
+       buf = bus->dataptr;
+
+       /* copy the data */
+       skb_queue_walk(&bus->glom, p) {
+               n = min_t(uint, p->len, len);
+               memcpy(p->data, buf, n);
+               buf += n;
+               len -= n;
+               ret += n;
+               if (!len)
+                       break;
+       }
+
+       return ret;
+}
+
+/* return total length of buffer chain */
+static uint brcmf_sdbrcm_glom_len(struct brcmf_bus *bus)
+{
+       struct sk_buff *p;
+       uint total;
+
+       total = 0;
+       skb_queue_walk(&bus->glom, p)
+               total += p->len;
+       return total;
+}
+
+static void brcmf_sdbrcm_free_glom(struct brcmf_bus *bus)
+{
+       struct sk_buff *cur, *next;
+
+       skb_queue_walk_safe(&bus->glom, cur, next) {
+               skb_unlink(cur, &bus->glom);
+               brcmu_pkt_buf_free_skb(cur);
+       }
+}
+
 static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
 {
        u16 dlen, totlen;
@@ -1240,7 +1132,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
        /* If packets, issue read(s) and send up packet chain */
        /* Return sequence numbers consumed? */
 
-       brcmf_dbg(TRACE, "start: glomd %p glom %p\n", bus->glomd, bus->glom);
+       brcmf_dbg(TRACE, "start: glomd %p glom %p\n",
+                 bus->glomd, skb_peek(&bus->glom));
 
        /* If there's a descriptor, generate the packet chain */
        if (bus->glomd) {
@@ -1287,12 +1180,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
                                          num, sublen);
                                break;
                        }
-                       if (!pfirst) {
-                               pfirst = plast = pnext;
-                       } else {
-                               plast->next = pnext;
-                               plast = pnext;
-                       }
+                       skb_queue_tail(&bus->glom, pnext);
 
                        /* Adhere to start alignment requirements */
                        pkt_align(pnext, sublen, BRCMF_SDALIGN);
@@ -1308,12 +1196,9 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
                                brcmf_dbg(GLOM, "glomdesc mismatch: nextlen %d glomdesc %d rxseq %d\n",
                                          bus->nextlen, totlen, rxseq);
                        }
-                       bus->glom = pfirst;
                        pfirst = pnext = NULL;
                } else {
-                       if (pfirst)
-                               brcmu_pkt_buf_free_skb(pfirst);
-                       bus->glom = NULL;
+                       brcmf_sdbrcm_free_glom(bus);
                        num = 0;
                }
 
@@ -1325,18 +1210,18 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
 
        /* Ok -- either we just generated a packet chain,
                 or had one from before */
-       if (bus->glom) {
+       if (!skb_queue_empty(&bus->glom)) {
                if (BRCMF_GLOM_ON()) {
                        brcmf_dbg(GLOM, "try superframe read, packet chain:\n");
-                       for (pnext = bus->glom; pnext; pnext = pnext->next) {
+                       skb_queue_walk(&bus->glom, pnext) {
                                brcmf_dbg(GLOM, "    %p: %p len 0x%04x (%d)\n",
                                          pnext, (u8 *) (pnext->data),
                                          pnext->len, pnext->len);
                        }
                }
 
-               pfirst = bus->glom;
-               dlen = (u16) brcmu_pkttotlen(pfirst);
+               pfirst = skb_peek(&bus->glom);
+               dlen = (u16) brcmf_sdbrcm_glom_len(bus);
 
                /* Do an SDIO read for the superframe.  Configurable iovar to
                 * read directly into the chained packet, or allocate a large
@@ -1354,8 +1239,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
                                        SDIO_FUNC_2,
                                        F2SYNC, bus->dataptr, dlen,
                                        NULL);
-                       sublen = (u16) brcmu_pktfrombuf(pfirst, 0, dlen,
-                                               bus->dataptr);
+                       sublen = (u16) brcmf_sdbrcm_glom_from_buf(bus, dlen);
                        if (sublen != dlen) {
                                brcmf_dbg(ERROR, "FAILED TO COPY, dlen %d sublen %d\n",
                                          dlen, sublen);
@@ -1380,9 +1264,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
                        } else {
                                bus->glomerr = 0;
                                brcmf_sdbrcm_rxfail(bus, true, false);
-                               brcmu_pkt_buf_free_skb(bus->glom);
                                bus->rxglomfail++;
-                               bus->glom = NULL;
+                               brcmf_sdbrcm_free_glom(bus);
                        }
                        return 0;
                }
@@ -1503,9 +1386,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
                        } else {
                                bus->glomerr = 0;
                                brcmf_sdbrcm_rxfail(bus, true, false);
-                               brcmu_pkt_buf_free_skb(bus->glom);
                                bus->rxglomfail++;
-                               bus->glom = NULL;
+                               brcmf_sdbrcm_free_glom(bus);
                        }
                        bus->nextlen = 0;
                        return 0;
@@ -1513,7 +1395,6 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
 
                /* Basic SD framing looks ok - process each packet (header) */
                save_pfirst = pfirst;
-               bus->glom = NULL;
                plast = NULL;
 
                for (num = 0; pfirst; rxseq++, pfirst = pnext) {
@@ -1850,10 +1731,10 @@ brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished)
             rxseq++, rxleft--) {
 
                /* Handle glomming separately */
-               if (bus->glom || bus->glomd) {
+               if (bus->glomd || !skb_queue_empty(&bus->glom)) {
                        u8 cnt;
                        brcmf_dbg(GLOM, "calling rxglom: glomd %p, glom %p\n",
-                                 bus->glomd, bus->glom);
+                                 bus->glomd, skb_peek(&bus->glom));
                        cnt = brcmf_sdbrcm_rxglom(bus, rxseq);
                        brcmf_dbg(GLOM, "rxglom returned %d\n", cnt);
                        rxseq += cnt - 1;
@@ -3210,135 +3091,11 @@ static int brcmf_sdbrcm_write_vars(struct brcmf_bus *bus)
        return bcmerror;
 }
 
-static void
-brcmf_sdbrcm_chip_disablecore(struct brcmf_sdio_dev *sdiodev, u32 corebase)
-{
-       u32 regdata;
-
-       regdata = brcmf_sdcard_reg_read(sdiodev,
-               CORE_SB(corebase, sbtmstatelow), 4);
-       if (regdata & SBTML_RESET)
-               return;
-
-       regdata = brcmf_sdcard_reg_read(sdiodev,
-               CORE_SB(corebase, sbtmstatelow), 4);
-       if ((regdata & (SICF_CLOCK_EN << SBTML_SICF_SHIFT)) != 0) {
-               /*
-                * set target reject and spin until busy is clear
-                * (preserve core-specific bits)
-                */
-               regdata = brcmf_sdcard_reg_read(sdiodev,
-                       CORE_SB(corebase, sbtmstatelow), 4);
-               brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow),
-                                      4, regdata | SBTML_REJ);
-
-               regdata = brcmf_sdcard_reg_read(sdiodev,
-                       CORE_SB(corebase, sbtmstatelow), 4);
-               udelay(1);
-               SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
-                       CORE_SB(corebase, sbtmstatehigh), 4) &
-                       SBTMH_BUSY), 100000);
-
-               regdata = brcmf_sdcard_reg_read(sdiodev,
-                       CORE_SB(corebase, sbtmstatehigh), 4);
-               if (regdata & SBTMH_BUSY)
-                       brcmf_dbg(ERROR, "ARM core still busy\n");
-
-               regdata = brcmf_sdcard_reg_read(sdiodev,
-                       CORE_SB(corebase, sbidlow), 4);
-               if (regdata & SBIDL_INIT) {
-                       regdata = brcmf_sdcard_reg_read(sdiodev,
-                               CORE_SB(corebase, sbimstate), 4) |
-                               SBIM_RJ;
-                       brcmf_sdcard_reg_write(sdiodev,
-                               CORE_SB(corebase, sbimstate), 4,
-                               regdata);
-                       regdata = brcmf_sdcard_reg_read(sdiodev,
-                               CORE_SB(corebase, sbimstate), 4);
-                       udelay(1);
-                       SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
-                               CORE_SB(corebase, sbimstate), 4) &
-                               SBIM_BY), 100000);
-               }
-
-               /* set reset and reject while enabling the clocks */
-               brcmf_sdcard_reg_write(sdiodev,
-                       CORE_SB(corebase, sbtmstatelow), 4,
-                       (((SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) |
-                       SBTML_REJ | SBTML_RESET));
-               regdata = brcmf_sdcard_reg_read(sdiodev,
-                       CORE_SB(corebase, sbtmstatelow), 4);
-               udelay(10);
-
-               /* clear the initiator reject bit */
-               regdata = brcmf_sdcard_reg_read(sdiodev,
-                       CORE_SB(corebase, sbidlow), 4);
-               if (regdata & SBIDL_INIT) {
-                       regdata = brcmf_sdcard_reg_read(sdiodev,
-                               CORE_SB(corebase, sbimstate), 4) &
-                               ~SBIM_RJ;
-                       brcmf_sdcard_reg_write(sdiodev,
-                               CORE_SB(corebase, sbimstate), 4,
-                               regdata);
-               }
-       }
-
-       /* leave reset and reject asserted */
-       brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4,
-               (SBTML_REJ | SBTML_RESET));
-       udelay(1);
-}
-
-static void
-brcmf_sdbrcm_chip_resetcore(struct brcmf_sdio_dev *sdiodev, u32 corebase)
-{
-       u32 regdata;
-
-       /*
-        * Must do the disable sequence first to work for
-        * arbitrary current core state.
-        */
-       brcmf_sdbrcm_chip_disablecore(sdiodev, corebase);
-
-       /*
-        * Now do the initialization sequence.
-        * set reset while enabling the clock and
-        * forcing them on throughout the core
-        */
-       brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4,
-               ((SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) |
-               SBTML_RESET);
-       udelay(1);
-
-       regdata = brcmf_sdcard_reg_read(sdiodev,
-                                       CORE_SB(corebase, sbtmstatehigh), 4);
-       if (regdata & SBTMH_SERR)
-               brcmf_sdcard_reg_write(sdiodev,
-                                      CORE_SB(corebase, sbtmstatehigh), 4, 0);
-
-       regdata = brcmf_sdcard_reg_read(sdiodev,
-                                       CORE_SB(corebase, sbimstate), 4);
-       if (regdata & (SBIM_IBE | SBIM_TO))
-               brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbimstate), 4,
-                       regdata & ~(SBIM_IBE | SBIM_TO));
-
-       /* clear reset and allow it to propagate throughout the core */
-       brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4,
-               (SICF_FGC << SBTML_SICF_SHIFT) |
-               (SICF_CLOCK_EN << SBTML_SICF_SHIFT));
-       udelay(1);
-
-       /* leave clock enabled */
-       brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4,
-               (SICF_CLOCK_EN << SBTML_SICF_SHIFT));
-       udelay(1);
-}
-
 static int brcmf_sdbrcm_download_state(struct brcmf_bus *bus, bool enter)
 {
        uint retries;
-       u32 regdata;
        int bcmerror = 0;
+       struct chip_info *ci = bus->ci;
 
        /* To enter download state, disable ARM and reset SOCRAM.
         * To exit download state, simply reset ARM (default is RAM boot).
@@ -3346,10 +3103,9 @@ static int brcmf_sdbrcm_download_state(struct brcmf_bus *bus, bool enter)
        if (enter) {
                bus->alp_only = true;
 
-               brcmf_sdbrcm_chip_disablecore(bus->sdiodev,
-                                             bus->ci->armcorebase);
+               ci->coredisable(bus->sdiodev, ci, BCMA_CORE_ARM_CM3);
 
-               brcmf_sdbrcm_chip_resetcore(bus->sdiodev, bus->ci->ramcorebase);
+               ci->resetcore(bus->sdiodev, ci, BCMA_CORE_INTERNAL_MEM);
 
                /* Clear the top bit of memory */
                if (bus->ramsize) {
@@ -3358,11 +3114,7 @@ static int brcmf_sdbrcm_download_state(struct brcmf_bus *bus, bool enter)
                                         (u8 *)&zeros, 4);
                }
        } else {
-               regdata = brcmf_sdcard_reg_read(bus->sdiodev,
-                       CORE_SB(bus->ci->ramcorebase, sbtmstatelow), 4);
-               regdata &= (SBTML_RESET | SBTML_REJ_MASK |
-                       (SICF_CLOCK_EN << SBTML_SICF_SHIFT));
-               if ((SICF_CLOCK_EN << SBTML_SICF_SHIFT) != regdata) {
+               if (!ci->iscoreup(bus->sdiodev, ci, BCMA_CORE_INTERNAL_MEM)) {
                        brcmf_dbg(ERROR, "SOCRAM core is down after reset?\n");
                        bcmerror = -EBADE;
                        goto fail;
@@ -3377,7 +3129,7 @@ static int brcmf_sdbrcm_download_state(struct brcmf_bus *bus, bool enter)
                w_sdreg32(bus, 0xFFFFFFFF,
                          offsetof(struct sdpcmd_regs, intstatus), &retries);
 
-               brcmf_sdbrcm_chip_resetcore(bus->sdiodev, bus->ci->armcorebase);
+               ci->resetcore(bus->sdiodev, ci, BCMA_CORE_ARM_CM3);
 
                /* Allow HT Clock now that the ARM is running. */
                bus->alp_only = false;
@@ -3661,11 +3413,7 @@ void brcmf_sdbrcm_bus_stop(struct brcmf_bus *bus)
        /* Clear any held glomming stuff */
        if (bus->glomd)
                brcmu_pkt_buf_free_skb(bus->glomd);
-
-       if (bus->glom)
-               brcmu_pkt_buf_free_skb(bus->glom);
-
-       bus->glom = bus->glomd = NULL;
+       brcmf_sdbrcm_free_glom(bus);
 
        /* Clear rx control and wake any waiters */
        bus->rxlen = 0;
@@ -3950,269 +3698,6 @@ fail:
        return false;
 }
 
-/* SDIO Pad drive strength to select value mappings */
-struct sdiod_drive_str {
-       u8 strength;    /* Pad Drive Strength in mA */
-       u8 sel;         /* Chip-specific select value */
-};
-
-/* SDIO Drive Strength to sel value table for PMU Rev 1 */
-static const struct sdiod_drive_str sdiod_drive_strength_tab1[] = {
-       {
-       4, 0x2}, {
-       2, 0x3}, {
-       1, 0x0}, {
-       0, 0x0}
-       };
-
-/* SDIO Drive Strength to sel value table for PMU Rev 2, 3 */
-static const struct sdiod_drive_str sdiod_drive_strength_tab2[] = {
-       {
-       12, 0x7}, {
-       10, 0x6}, {
-       8, 0x5}, {
-       6, 0x4}, {
-       4, 0x2}, {
-       2, 0x1}, {
-       0, 0x0}
-       };
-
-/* SDIO Drive Strength to sel value table for PMU Rev 8 (1.8V) */
-static const struct sdiod_drive_str sdiod_drive_strength_tab3[] = {
-       {
-       32, 0x7}, {
-       26, 0x6}, {
-       22, 0x5}, {
-       16, 0x4}, {
-       12, 0x3}, {
-       8, 0x2}, {
-       4, 0x1}, {
-       0, 0x0}
-       };
-
-#define SDIOD_DRVSTR_KEY(chip, pmu)     (((chip) << 16) | (pmu))
-
-static char *brcmf_chipname(uint chipid, char *buf, uint len)
-{
-       const char *fmt;
-
-       fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
-       snprintf(buf, len, fmt, chipid);
-       return buf;
-}
-
-static void brcmf_sdbrcm_sdiod_drive_strength_init(struct brcmf_bus *bus,
-                                                  u32 drivestrength) {
-       struct sdiod_drive_str *str_tab = NULL;
-       u32 str_mask = 0;
-       u32 str_shift = 0;
-       char chn[8];
-
-       if (!(bus->ci->cccaps & CC_CAP_PMU))
-               return;
-
-       switch (SDIOD_DRVSTR_KEY(bus->ci->chip, bus->ci->pmurev)) {
-       case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1):
-               str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab1;
-               str_mask = 0x30000000;
-               str_shift = 28;
-               break;
-       case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 2):
-       case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 3):
-               str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab2;
-               str_mask = 0x00003800;
-               str_shift = 11;
-               break;
-       case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8):
-               str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab3;
-               str_mask = 0x00003800;
-               str_shift = 11;
-               break;
-       default:
-               brcmf_dbg(ERROR, "No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
-                         brcmf_chipname(bus->ci->chip, chn, 8),
-                         bus->ci->chiprev, bus->ci->pmurev);
-               break;
-       }
-
-       if (str_tab != NULL) {
-               u32 drivestrength_sel = 0;
-               u32 cc_data_temp;
-               int i;
-
-               for (i = 0; str_tab[i].strength != 0; i++) {
-                       if (drivestrength >= str_tab[i].strength) {
-                               drivestrength_sel = str_tab[i].sel;
-                               break;
-                       }
-               }
-
-               brcmf_sdcard_reg_write(bus->sdiodev,
-                       CORE_CC_REG(bus->ci->cccorebase, chipcontrol_addr),
-                       4, 1);
-               cc_data_temp = brcmf_sdcard_reg_read(bus->sdiodev,
-                       CORE_CC_REG(bus->ci->cccorebase, chipcontrol_addr), 4);
-               cc_data_temp &= ~str_mask;
-               drivestrength_sel <<= str_shift;
-               cc_data_temp |= drivestrength_sel;
-               brcmf_sdcard_reg_write(bus->sdiodev,
-                       CORE_CC_REG(bus->ci->cccorebase, chipcontrol_addr),
-                       4, cc_data_temp);
-
-               brcmf_dbg(INFO, "SDIO: %dmA drive strength selected, set to 0x%08x\n",
-                         drivestrength, cc_data_temp);
-       }
-}
-
-static int
-brcmf_sdbrcm_chip_recognition(struct brcmf_sdio_dev *sdiodev,
-                             struct chip_info *ci, u32 regs)
-{
-       u32 regdata;
-
-       /*
-        * Get CC core rev
-        * Chipid is assume to be at offset 0 from regs arg
-        * For different chiptypes or old sdio hosts w/o chipcommon,
-        * other ways of recognition should be added here.
-        */
-       ci->cccorebase = regs;
-       regdata = brcmf_sdcard_reg_read(sdiodev,
-                               CORE_CC_REG(ci->cccorebase, chipid), 4);
-       ci->chip = regdata & CID_ID_MASK;
-       ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT;
-
-       brcmf_dbg(INFO, "chipid=0x%x chiprev=%d\n", ci->chip, ci->chiprev);
-
-       /* Address of cores for new chips should be added here */
-       switch (ci->chip) {
-       case BCM4329_CHIP_ID:
-               ci->buscorebase = BCM4329_CORE_BUS_BASE;
-               ci->ramcorebase = BCM4329_CORE_SOCRAM_BASE;
-               ci->armcorebase = BCM4329_CORE_ARM_BASE;
-               ci->ramsize = BCM4329_RAMSIZE;
-               break;
-       default:
-               brcmf_dbg(ERROR, "chipid 0x%x is not supported\n", ci->chip);
-               return -ENODEV;
-       }
-
-       regdata = brcmf_sdcard_reg_read(sdiodev,
-               CORE_SB(ci->cccorebase, sbidhigh), 4);
-       ci->ccrev = SBCOREREV(regdata);
-
-       regdata = brcmf_sdcard_reg_read(sdiodev,
-               CORE_CC_REG(ci->cccorebase, pmucapabilities), 4);
-       ci->pmurev = regdata & PCAP_REV_MASK;
-
-       regdata = brcmf_sdcard_reg_read(sdiodev,
-                                       CORE_SB(ci->buscorebase, sbidhigh), 4);
-       ci->buscorerev = SBCOREREV(regdata);
-       ci->buscoretype = (regdata & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT;
-
-       brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n",
-                 ci->ccrev, ci->pmurev, ci->buscorerev, ci->buscoretype);
-
-       /* get chipcommon capabilites */
-       ci->cccaps = brcmf_sdcard_reg_read(sdiodev,
-               CORE_CC_REG(ci->cccorebase, capabilities), 4);
-
-       return 0;
-}
-
-static int
-brcmf_sdbrcm_chip_attach(struct brcmf_bus *bus, u32 regs)
-{
-       struct chip_info *ci;
-       int err;
-       u8 clkval, clkset;
-
-       brcmf_dbg(TRACE, "Enter\n");
-
-       /* alloc chip_info_t */
-       ci = kzalloc(sizeof(struct chip_info), GFP_ATOMIC);
-       if (NULL == ci)
-               return -ENOMEM;
-
-       /* bus/core/clk setup for register access */
-       /* Try forcing SDIO core to do ALPAvail request only */
-       clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
-       brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
-                              SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
-       if (err) {
-               brcmf_dbg(ERROR, "error writing for HT off\n");
-               goto fail;
-       }
-
-       /* If register supported, wait for ALPAvail and then force ALP */
-       /* This may take up to 15 milliseconds */
-       clkval = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
-                       SBSDIO_FUNC1_CHIPCLKCSR, NULL);
-       if ((clkval & ~SBSDIO_AVBITS) == clkset) {
-               SPINWAIT(((clkval =
-                               brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
-                                               SBSDIO_FUNC1_CHIPCLKCSR,
-                                               NULL)),
-                               !SBSDIO_ALPAV(clkval)),
-                               PMU_MAX_TRANSITION_DLY);
-               if (!SBSDIO_ALPAV(clkval)) {
-                       brcmf_dbg(ERROR, "timeout on ALPAV wait, clkval 0x%02x\n",
-                                 clkval);
-                       err = -EBUSY;
-                       goto fail;
-               }
-               clkset = SBSDIO_FORCE_HW_CLKREQ_OFF |
-                               SBSDIO_FORCE_ALP;
-               brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
-                               SBSDIO_FUNC1_CHIPCLKCSR,
-                               clkset, &err);
-               udelay(65);
-       } else {
-               brcmf_dbg(ERROR, "ChipClkCSR access: wrote 0x%02x read 0x%02x\n",
-                         clkset, clkval);
-               err = -EACCES;
-               goto fail;
-       }
-
-       /* Also, disable the extra SDIO pull-ups */
-       brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
-                              SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
-
-       err = brcmf_sdbrcm_chip_recognition(bus->sdiodev, ci, regs);
-       if (err)
-               goto fail;
-
-       /*
-        * Make sure any on-chip ARM is off (in case strapping is wrong),
-        * or downloaded code was already running.
-        */
-       brcmf_sdbrcm_chip_disablecore(bus->sdiodev, ci->armcorebase);
-
-       brcmf_sdcard_reg_write(bus->sdiodev,
-               CORE_CC_REG(ci->cccorebase, gpiopullup), 4, 0);
-       brcmf_sdcard_reg_write(bus->sdiodev,
-               CORE_CC_REG(ci->cccorebase, gpiopulldown), 4, 0);
-
-       /* Disable F2 to clear any intermediate frame state on the dongle */
-       brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx,
-               SDIO_FUNC_ENABLE_1, NULL);
-
-       /* WAR: cmd52 backplane read so core HW will drop ALPReq */
-       clkval = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
-                       0, NULL);
-
-       /* Done with backplane-dependent accesses, can drop clock... */
-       brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
-                              SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
-
-       bus->ci = ci;
-       return 0;
-fail:
-       bus->ci = NULL;
-       kfree(ci);
-       return err;
-}
-
 static bool
 brcmf_sdbrcm_probe_attach(struct brcmf_bus *bus, u32 regsva)
 {
@@ -4220,6 +3705,7 @@ brcmf_sdbrcm_probe_attach(struct brcmf_bus *bus, u32 regsva)
        int err = 0;
        int reg_addr;
        u32 reg_val;
+       u8 idx;
 
        bus->alp_only = true;
 
@@ -4234,7 +3720,7 @@ brcmf_sdbrcm_probe_attach(struct brcmf_bus *bus, u32 regsva)
 #endif                         /* BCMDBG */
 
        /*
-        * Force PLL off until brcmf_sdbrcm_chip_attach()
+        * Force PLL off until brcmf_sdio_chip_attach()
         * programs PLL control regs
         */
 
@@ -4252,8 +3738,8 @@ brcmf_sdbrcm_probe_attach(struct brcmf_bus *bus, u32 regsva)
                goto fail;
        }
 
-       if (brcmf_sdbrcm_chip_attach(bus, regsva)) {
-               brcmf_dbg(ERROR, "brcmf_sdbrcm_chip_attach failed!\n");
+       if (brcmf_sdio_chip_attach(bus->sdiodev, &bus->ci, regsva)) {
+               brcmf_dbg(ERROR, "brcmf_sdio_chip_attach failed!\n");
                goto fail;
        }
 
@@ -4262,11 +3748,10 @@ brcmf_sdbrcm_probe_attach(struct brcmf_bus *bus, u32 regsva)
                goto fail;
        }
 
-       brcmf_sdbrcm_sdiod_drive_strength_init(bus, SDIO_DRIVE_STRENGTH);
+       brcmf_sdio_chip_drivestrengthinit(bus->sdiodev, bus->ci,
+                                         SDIO_DRIVE_STRENGTH);
 
-       /* Get info on the ARM and SOCRAM cores... */
-       brcmf_sdcard_reg_read(bus->sdiodev,
-                 CORE_SB(bus->ci->armcorebase, sbidhigh), 4);
+       /* Get info on the SOCRAM cores... */
        bus->ramsize = bus->ci->ramsize;
        if (!(bus->ramsize)) {
                brcmf_dbg(ERROR, "failed to find SOCRAM memory!\n");
@@ -4274,7 +3759,8 @@ brcmf_sdbrcm_probe_attach(struct brcmf_bus *bus, u32 regsva)
        }
 
        /* Set core control so an SDIO reset does a backplane reset */
-       reg_addr = bus->ci->buscorebase +
+       idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
+       reg_addr = bus->ci->c_inf[idx].base +
                   offsetof(struct sdpcmd_regs, corecontrol);
        reg_val = brcmf_sdcard_reg_read(bus->sdiodev, reg_addr, sizeof(u32));
        brcmf_sdcard_reg_write(bus->sdiodev, reg_addr, sizeof(u32),
@@ -4364,15 +3850,6 @@ brcmf_sdbrcm_watchdog(unsigned long data)
        }
 }
 
-static void
-brcmf_sdbrcm_chip_detach(struct brcmf_bus *bus)
-{
-       brcmf_dbg(TRACE, "Enter\n");
-
-       kfree(bus->ci);
-       bus->ci = NULL;
-}
-
 static void brcmf_sdbrcm_release_dongle(struct brcmf_bus *bus)
 {
        brcmf_dbg(TRACE, "Enter\n");
@@ -4380,7 +3857,7 @@ static void brcmf_sdbrcm_release_dongle(struct brcmf_bus *bus)
        if (bus->ci) {
                brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
                brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
-               brcmf_sdbrcm_chip_detach(bus);
+               brcmf_sdio_chip_detach(&bus->ci);
                if (bus->vars && bus->varsz)
                        kfree(bus->vars);
                bus->vars = NULL;
@@ -4440,6 +3917,7 @@ void *brcmf_sdbrcm_probe(u16 bus_no, u16 slot, u16 func, uint bustype,
 
        bus->sdiodev = sdiodev;
        sdiodev->bus = bus;
+       skb_queue_head_init(&bus->glom);
        bus->txbound = BRCMF_TXBOUND;
        bus->rxbound = BRCMF_RXBOUND;
        bus->txminmax = BRCMF_TXMINMAX;
@@ -4521,9 +3999,10 @@ void *brcmf_sdbrcm_probe(u16 bus_no, u16 slot, u16 func, uint bustype,
                        goto fail;
                }
        }
-       /* Ok, have the per-port tell the stack we're open for business */
-       if (brcmf_net_attach(bus->drvr, 0) != 0) {
-               brcmf_dbg(ERROR, "Net attach failed!!\n");
+
+       /* add interface and open for business */
+       if (brcmf_add_if((struct brcmf_info *)bus->drvr, 0, "wlan%d", NULL)) {
+               brcmf_dbg(ERROR, "Add primary net device interface failed!!\n");
                goto fail;
        }
 
@@ -4554,10 +4033,6 @@ struct device *brcmf_bus_get_device(struct brcmf_bus *bus)
 void
 brcmf_sdbrcm_wd_timer(struct brcmf_bus *bus, uint wdtick)
 {
-       /* don't start the wd until fw is loaded */
-       if (bus->drvr->busstate == BRCMF_BUS_DOWN)
-               return;
-
        /* Totally stop the timer */
        if (!wdtick && bus->wd_timer_valid == true) {
                del_timer_sync(&bus->timer);
@@ -4566,6 +4041,10 @@ brcmf_sdbrcm_wd_timer(struct brcmf_bus *bus, uint wdtick)
                return;
        }
 
+       /* don't start the wd until fw is loaded */
+       if (bus->drvr->busstate == BRCMF_BUS_DOWN)
+               return;
+
        if (wdtick) {
                if (bus->save_ms != BRCMF_WD_POLL_MS) {
                        if (bus->wd_timer_valid == true)
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c
new file mode 100644 (file)
index 0000000..f6b1822
--- /dev/null
@@ -0,0 +1,622 @@
+/*
+ * Copyright (c) 2011 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/* ***** SDIO interface chip backplane handle functions ***** */
+
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/mmc/card.h>
+#include <linux/ssb/ssb_regs.h>
+#include <linux/bcma/bcma.h>
+
+#include <chipcommon.h>
+#include <brcm_hw_ids.h>
+#include <brcmu_wifi.h>
+#include <brcmu_utils.h>
+#include <soc.h>
+#include "dhd.h"
+#include "dhd_dbg.h"
+#include "sdio_host.h"
+#include "sdio_chip.h"
+
+/* chip core base & ramsize */
+/* bcm4329 */
+/* SDIO device core, ID 0x829 */
+#define BCM4329_CORE_BUS_BASE          0x18011000
+/* internal memory core, ID 0x80e */
+#define BCM4329_CORE_SOCRAM_BASE       0x18003000
+/* ARM Cortex M3 core, ID 0x82a */
+#define BCM4329_CORE_ARM_BASE          0x18002000
+#define BCM4329_RAMSIZE                        0x48000
+
+#define        SBCOREREV(sbidh) \
+       ((((sbidh) & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT) | \
+         ((sbidh) & SSB_IDHIGH_RCLO))
+
+/* SOC Interconnect types (aka chip types) */
+#define SOCI_SB                0
+#define SOCI_AI                1
+
+/* EROM CompIdentB */
+#define CIB_REV_MASK           0xff000000
+#define CIB_REV_SHIFT          24
+
+#define SDIOD_DRVSTR_KEY(chip, pmu)     (((chip) << 16) | (pmu))
+/* SDIO Pad drive strength to select value mappings */
+struct sdiod_drive_str {
+       u8 strength;    /* Pad Drive Strength in mA */
+       u8 sel;         /* Chip-specific select value */
+};
+/* SDIO Drive Strength to sel value table for PMU Rev 1 */
+static const struct sdiod_drive_str sdiod_drive_strength_tab1[] = {
+       {
+       4, 0x2}, {
+       2, 0x3}, {
+       1, 0x0}, {
+       0, 0x0}
+       };
+/* SDIO Drive Strength to sel value table for PMU Rev 2, 3 */
+static const struct sdiod_drive_str sdiod_drive_strength_tab2[] = {
+       {
+       12, 0x7}, {
+       10, 0x6}, {
+       8, 0x5}, {
+       6, 0x4}, {
+       4, 0x2}, {
+       2, 0x1}, {
+       0, 0x0}
+       };
+/* SDIO Drive Strength to sel value table for PMU Rev 8 (1.8V) */
+static const struct sdiod_drive_str sdiod_drive_strength_tab3[] = {
+       {
+       32, 0x7}, {
+       26, 0x6}, {
+       22, 0x5}, {
+       16, 0x4}, {
+       12, 0x3}, {
+       8, 0x2}, {
+       4, 0x1}, {
+       0, 0x0}
+       };
+
+u8
+brcmf_sdio_chip_getinfidx(struct chip_info *ci, u16 coreid)
+{
+       u8 idx;
+
+       for (idx = 0; idx < BRCMF_MAX_CORENUM; idx++)
+               if (coreid == ci->c_inf[idx].id)
+                       return idx;
+
+       return BRCMF_MAX_CORENUM;
+}
+
+static u32
+brcmf_sdio_sb_corerev(struct brcmf_sdio_dev *sdiodev,
+                     struct chip_info *ci, u16 coreid)
+{
+       u32 regdata;
+       u8 idx;
+
+       idx = brcmf_sdio_chip_getinfidx(ci, coreid);
+
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbidhigh), 4);
+       return SBCOREREV(regdata);
+}
+
+static u32
+brcmf_sdio_ai_corerev(struct brcmf_sdio_dev *sdiodev,
+                     struct chip_info *ci, u16 coreid)
+{
+       u8 idx;
+
+       idx = brcmf_sdio_chip_getinfidx(ci, coreid);
+
+       return (ci->c_inf[idx].cib & CIB_REV_MASK) >> CIB_REV_SHIFT;
+}
+
+static bool
+brcmf_sdio_sb_iscoreup(struct brcmf_sdio_dev *sdiodev,
+                      struct chip_info *ci, u16 coreid)
+{
+       u32 regdata;
+       u8 idx;
+
+       idx = brcmf_sdio_chip_getinfidx(ci, coreid);
+
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
+       regdata &= (SSB_TMSLOW_RESET | SSB_TMSLOW_REJECT |
+                   SSB_IMSTATE_REJECT | SSB_TMSLOW_CLOCK);
+       return (SSB_TMSLOW_CLOCK == regdata);
+}
+
+static bool
+brcmf_sdio_ai_iscoreup(struct brcmf_sdio_dev *sdiodev,
+                      struct chip_info *ci, u16 coreid)
+{
+       u32 regdata;
+       u8 idx;
+       bool ret;
+
+       idx = brcmf_sdio_chip_getinfidx(ci, coreid);
+
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                                       ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
+       ret = (regdata & (BCMA_IOCTL_FGC | BCMA_IOCTL_CLK)) == BCMA_IOCTL_CLK;
+
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                                       ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
+                                       4);
+       ret = ret && ((regdata & BCMA_RESET_CTL_RESET) == 0);
+
+       return ret;
+}
+
+static void
+brcmf_sdio_sb_coredisable(struct brcmf_sdio_dev *sdiodev,
+                         struct chip_info *ci, u16 coreid)
+{
+       u32 regdata;
+       u8 idx;
+
+       idx = brcmf_sdio_chip_getinfidx(ci, coreid);
+
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+               CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
+       if (regdata & SSB_TMSLOW_RESET)
+               return;
+
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+               CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
+       if ((regdata & SSB_TMSLOW_CLOCK) != 0) {
+               /*
+                * set target reject and spin until busy is clear
+                * (preserve core-specific bits)
+                */
+               regdata = brcmf_sdcard_reg_read(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
+               brcmf_sdcard_reg_write(sdiodev,
+                               CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
+                               4, regdata | SSB_TMSLOW_REJECT);
+
+               regdata = brcmf_sdcard_reg_read(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
+               udelay(1);
+               SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4) &
+                       SSB_TMSHIGH_BUSY), 100000);
+
+               regdata = brcmf_sdcard_reg_read(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4);
+               if (regdata & SSB_TMSHIGH_BUSY)
+                       brcmf_dbg(ERROR, "core state still busy\n");
+
+               regdata = brcmf_sdcard_reg_read(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbidlow), 4);
+               if (regdata & SSB_IDLOW_INITIATOR) {
+                       regdata = brcmf_sdcard_reg_read(sdiodev,
+                               CORE_SB(ci->c_inf[idx].base, sbimstate), 4) |
+                               SSB_IMSTATE_REJECT;
+                       brcmf_sdcard_reg_write(sdiodev,
+                               CORE_SB(ci->c_inf[idx].base, sbimstate), 4,
+                               regdata);
+                       regdata = brcmf_sdcard_reg_read(sdiodev,
+                               CORE_SB(ci->c_inf[idx].base, sbimstate), 4);
+                       udelay(1);
+                       SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
+                               CORE_SB(ci->c_inf[idx].base, sbimstate), 4) &
+                               SSB_IMSTATE_BUSY), 100000);
+               }
+
+               /* set reset and reject while enabling the clocks */
+               brcmf_sdcard_reg_write(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
+                       (SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
+                       SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET));
+               regdata = brcmf_sdcard_reg_read(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
+               udelay(10);
+
+               /* clear the initiator reject bit */
+               regdata = brcmf_sdcard_reg_read(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbidlow), 4);
+               if (regdata & SSB_IDLOW_INITIATOR) {
+                       regdata = brcmf_sdcard_reg_read(sdiodev,
+                               CORE_SB(ci->c_inf[idx].base, sbimstate), 4) &
+                               ~SSB_IMSTATE_REJECT;
+                       brcmf_sdcard_reg_write(sdiodev,
+                               CORE_SB(ci->c_inf[idx].base, sbimstate), 4,
+                               regdata);
+               }
+       }
+
+       /* leave reset and reject asserted */
+       brcmf_sdcard_reg_write(sdiodev,
+               CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
+               (SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET));
+       udelay(1);
+}
+
+static void
+brcmf_sdio_ai_coredisable(struct brcmf_sdio_dev *sdiodev,
+                         struct chip_info *ci, u16 coreid)
+{
+       u8 idx;
+       u32 regdata;
+
+       idx = brcmf_sdio_chip_getinfidx(ci, coreid);
+
+       /* if core is already in reset, just return */
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                                       ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
+                                       4);
+       if ((regdata & BCMA_RESET_CTL_RESET) != 0)
+               return;
+
+       brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
+                              4, 0);
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                                       ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
+       udelay(10);
+
+       brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
+                              4, BCMA_RESET_CTL_RESET);
+       udelay(1);
+}
+
+static void
+brcmf_sdio_sb_resetcore(struct brcmf_sdio_dev *sdiodev,
+                       struct chip_info *ci, u16 coreid)
+{
+       u32 regdata;
+       u8 idx;
+
+       idx = brcmf_sdio_chip_getinfidx(ci, coreid);
+
+       /*
+        * Must do the disable sequence first to work for
+        * arbitrary current core state.
+        */
+       brcmf_sdio_sb_coredisable(sdiodev, ci, coreid);
+
+       /*
+        * Now do the initialization sequence.
+        * set reset while enabling the clock and
+        * forcing them on throughout the core
+        */
+       brcmf_sdcard_reg_write(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
+                       SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET);
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                               CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
+       udelay(1);
+
+       /* clear any serror */
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                               CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4);
+       if (regdata & SSB_TMSHIGH_SERR)
+               brcmf_sdcard_reg_write(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4, 0);
+
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                               CORE_SB(ci->c_inf[idx].base, sbimstate), 4);
+       if (regdata & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO))
+               brcmf_sdcard_reg_write(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbimstate), 4,
+                       regdata & ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO));
+
+       /* clear reset and allow it to propagate throughout the core */
+       brcmf_sdcard_reg_write(sdiodev,
+               CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
+               SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK);
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                               CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
+       udelay(1);
+
+       /* leave clock enabled */
+       brcmf_sdcard_reg_write(sdiodev,
+                              CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
+                              4, SSB_TMSLOW_CLOCK);
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                               CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
+       udelay(1);
+}
+
+static void
+brcmf_sdio_ai_resetcore(struct brcmf_sdio_dev *sdiodev,
+                       struct chip_info *ci, u16 coreid)
+{
+       u8 idx;
+       u32 regdata;
+
+       idx = brcmf_sdio_chip_getinfidx(ci, coreid);
+
+       /* must disable first to work for arbitrary current core state */
+       brcmf_sdio_ai_coredisable(sdiodev, ci, coreid);
+
+       /* now do initialization sequence */
+       brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
+                              4, BCMA_IOCTL_FGC | BCMA_IOCTL_CLK);
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                                       ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
+       brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
+                              4, 0);
+       udelay(1);
+
+       brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
+                              4, BCMA_IOCTL_CLK);
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                                       ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
+       udelay(1);
+}
+
+static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev,
+                                      struct chip_info *ci, u32 regs)
+{
+       u32 regdata;
+
+       /*
+        * Get CC core rev
+        * Chipid is assume to be at offset 0 from regs arg
+        * For different chiptypes or old sdio hosts w/o chipcommon,
+        * other ways of recognition should be added here.
+        */
+       ci->c_inf[0].id = BCMA_CORE_CHIPCOMMON;
+       ci->c_inf[0].base = regs;
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                       CORE_CC_REG(ci->c_inf[0].base, chipid), 4);
+       ci->chip = regdata & CID_ID_MASK;
+       ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT;
+       ci->socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
+
+       brcmf_dbg(INFO, "chipid=0x%x chiprev=%d\n", ci->chip, ci->chiprev);
+
+       /* Address of cores for new chips should be added here */
+       switch (ci->chip) {
+       case BCM4329_CHIP_ID:
+               ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
+               ci->c_inf[1].base = BCM4329_CORE_BUS_BASE;
+               ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
+               ci->c_inf[2].base = BCM4329_CORE_SOCRAM_BASE;
+               ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
+               ci->c_inf[3].base = BCM4329_CORE_ARM_BASE;
+               ci->ramsize = BCM4329_RAMSIZE;
+               break;
+       default:
+               brcmf_dbg(ERROR, "chipid 0x%x is not supported\n", ci->chip);
+               return -ENODEV;
+       }
+
+       switch (ci->socitype) {
+       case SOCI_SB:
+               ci->iscoreup = brcmf_sdio_sb_iscoreup;
+               ci->corerev = brcmf_sdio_sb_corerev;
+               ci->coredisable = brcmf_sdio_sb_coredisable;
+               ci->resetcore = brcmf_sdio_sb_resetcore;
+               break;
+       case SOCI_AI:
+               ci->iscoreup = brcmf_sdio_ai_iscoreup;
+               ci->corerev = brcmf_sdio_ai_corerev;
+               ci->coredisable = brcmf_sdio_ai_coredisable;
+               ci->resetcore = brcmf_sdio_ai_resetcore;
+               break;
+       default:
+               brcmf_dbg(ERROR, "socitype %u not supported\n", ci->socitype);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static int
+brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
+{
+       int err = 0;
+       u8 clkval, clkset;
+
+       /* Try forcing SDIO core to do ALPAvail request only */
+       clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
+       brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
+                              SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
+       if (err) {
+               brcmf_dbg(ERROR, "error writing for HT off\n");
+               return err;
+       }
+
+       /* If register supported, wait for ALPAvail and then force ALP */
+       /* This may take up to 15 milliseconds */
+       clkval = brcmf_sdcard_cfg_read(sdiodev, SDIO_FUNC_1,
+                                      SBSDIO_FUNC1_CHIPCLKCSR, NULL);
+
+       if ((clkval & ~SBSDIO_AVBITS) != clkset) {
+               brcmf_dbg(ERROR, "ChipClkCSR access: wrote 0x%02x read 0x%02x\n",
+                         clkset, clkval);
+               return -EACCES;
+       }
+
+       SPINWAIT(((clkval = brcmf_sdcard_cfg_read(sdiodev, SDIO_FUNC_1,
+                               SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
+                       !SBSDIO_ALPAV(clkval)),
+                       PMU_MAX_TRANSITION_DLY);
+       if (!SBSDIO_ALPAV(clkval)) {
+               brcmf_dbg(ERROR, "timeout on ALPAV wait, clkval 0x%02x\n",
+                         clkval);
+               return -EBUSY;
+       }
+
+       clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP;
+       brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
+                              SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
+       udelay(65);
+
+       /* Also, disable the extra SDIO pull-ups */
+       brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
+                              SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
+
+       return 0;
+}
+
+static void
+brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev *sdiodev,
+                            struct chip_info *ci)
+{
+       /* get chipcommon rev */
+       ci->c_inf[0].rev = ci->corerev(sdiodev, ci, ci->c_inf[0].id);
+
+       /* get chipcommon capabilites */
+       ci->c_inf[0].caps =
+               brcmf_sdcard_reg_read(sdiodev,
+               CORE_CC_REG(ci->c_inf[0].base, capabilities), 4);
+
+       /* get pmu caps & rev */
+       if (ci->c_inf[0].caps & CC_CAP_PMU) {
+               ci->pmucaps = brcmf_sdcard_reg_read(sdiodev,
+                       CORE_CC_REG(ci->c_inf[0].base, pmucapabilities), 4);
+               ci->pmurev = ci->pmucaps & PCAP_REV_MASK;
+       }
+
+       ci->c_inf[1].rev = ci->corerev(sdiodev, ci, ci->c_inf[1].id);
+
+       brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n",
+                 ci->c_inf[0].rev, ci->pmurev,
+                 ci->c_inf[1].rev, ci->c_inf[1].id);
+
+       /*
+        * Make sure any on-chip ARM is off (in case strapping is wrong),
+        * or downloaded code was already running.
+        */
+       ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3);
+}
+
+int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev,
+                          struct chip_info **ci_ptr, u32 regs)
+{
+       int ret;
+       struct chip_info *ci;
+
+       brcmf_dbg(TRACE, "Enter\n");
+
+       /* alloc chip_info_t */
+       ci = kzalloc(sizeof(struct chip_info), GFP_ATOMIC);
+       if (!ci)
+               return -ENOMEM;
+
+       ret = brcmf_sdio_chip_buscoreprep(sdiodev);
+       if (ret != 0)
+               goto err;
+
+       ret = brcmf_sdio_chip_recognition(sdiodev, ci, regs);
+       if (ret != 0)
+               goto err;
+
+       brcmf_sdio_chip_buscoresetup(sdiodev, ci);
+
+       brcmf_sdcard_reg_write(sdiodev,
+               CORE_CC_REG(ci->c_inf[0].base, gpiopullup), 4, 0);
+       brcmf_sdcard_reg_write(sdiodev,
+               CORE_CC_REG(ci->c_inf[0].base, gpiopulldown), 4, 0);
+
+       *ci_ptr = ci;
+       return 0;
+
+err:
+       kfree(ci);
+       return ret;
+}
+
+void
+brcmf_sdio_chip_detach(struct chip_info **ci_ptr)
+{
+       brcmf_dbg(TRACE, "Enter\n");
+
+       kfree(*ci_ptr);
+       *ci_ptr = NULL;
+}
+
+static char *brcmf_sdio_chip_name(uint chipid, char *buf, uint len)
+{
+       const char *fmt;
+
+       fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
+       snprintf(buf, len, fmt, chipid);
+       return buf;
+}
+
+void
+brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
+                                 struct chip_info *ci, u32 drivestrength)
+{
+       struct sdiod_drive_str *str_tab = NULL;
+       u32 str_mask = 0;
+       u32 str_shift = 0;
+       char chn[8];
+
+       if (!(ci->c_inf[0].caps & CC_CAP_PMU))
+               return;
+
+       switch (SDIOD_DRVSTR_KEY(ci->chip, ci->pmurev)) {
+       case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1):
+               str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab1;
+               str_mask = 0x30000000;
+               str_shift = 28;
+               break;
+       case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 2):
+       case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 3):
+               str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab2;
+               str_mask = 0x00003800;
+               str_shift = 11;
+               break;
+       case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8):
+               str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab3;
+               str_mask = 0x00003800;
+               str_shift = 11;
+               break;
+       default:
+               brcmf_dbg(ERROR, "No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
+                         brcmf_sdio_chip_name(ci->chip, chn, 8),
+                         ci->chiprev, ci->pmurev);
+               break;
+       }
+
+       if (str_tab != NULL) {
+               u32 drivestrength_sel = 0;
+               u32 cc_data_temp;
+               int i;
+
+               for (i = 0; str_tab[i].strength != 0; i++) {
+                       if (drivestrength >= str_tab[i].strength) {
+                               drivestrength_sel = str_tab[i].sel;
+                               break;
+                       }
+               }
+
+               brcmf_sdcard_reg_write(sdiodev,
+                       CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr),
+                       4, 1);
+               cc_data_temp = brcmf_sdcard_reg_read(sdiodev,
+                       CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr), 4);
+               cc_data_temp &= ~str_mask;
+               drivestrength_sel <<= str_shift;
+               cc_data_temp |= drivestrength_sel;
+               brcmf_sdcard_reg_write(sdiodev,
+                       CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr),
+                       4, cc_data_temp);
+
+               brcmf_dbg(INFO, "SDIO: %dmA drive strength selected, set to 0x%08x\n",
+                         drivestrength, cc_data_temp);
+       }
+}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.h b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.h
new file mode 100644 (file)
index 0000000..ce974d7
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2011 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _BRCMFMAC_SDIO_CHIP_H_
+#define _BRCMFMAC_SDIO_CHIP_H_
+
+/*
+ * Core reg address translation.
+ * Both macro's returns a 32 bits byte address on the backplane bus.
+ */
+#define CORE_CC_REG(base, field) \
+               (base + offsetof(struct chipcregs, field))
+#define CORE_BUS_REG(base, field) \
+               (base + offsetof(struct sdpcmd_regs, field))
+#define CORE_SB(base, field) \
+               (base + SBCONFIGOFF + offsetof(struct sbconfig, field))
+
+/* SDIO function 1 register CHIPCLKCSR */
+/* Force ALP request to backplane */
+#define SBSDIO_FORCE_ALP               0x01
+/* Force HT request to backplane */
+#define SBSDIO_FORCE_HT                        0x02
+/* Force ILP request to backplane */
+#define SBSDIO_FORCE_ILP               0x04
+/* Make ALP ready (power up xtal) */
+#define SBSDIO_ALP_AVAIL_REQ           0x08
+/* Make HT ready (power up PLL) */
+#define SBSDIO_HT_AVAIL_REQ            0x10
+/* Squelch clock requests from HW */
+#define SBSDIO_FORCE_HW_CLKREQ_OFF     0x20
+/* Status: ALP is ready */
+#define SBSDIO_ALP_AVAIL               0x40
+/* Status: HT is ready */
+#define SBSDIO_HT_AVAIL                        0x80
+#define SBSDIO_AVBITS          (SBSDIO_HT_AVAIL | SBSDIO_ALP_AVAIL)
+#define SBSDIO_ALPAV(regval)   ((regval) & SBSDIO_AVBITS)
+#define SBSDIO_HTAV(regval)    (((regval) & SBSDIO_AVBITS) == SBSDIO_AVBITS)
+#define SBSDIO_ALPONLY(regval) (SBSDIO_ALPAV(regval) && !SBSDIO_HTAV(regval))
+#define SBSDIO_CLKAV(regval, alponly) \
+       (SBSDIO_ALPAV(regval) && (alponly ? 1 : SBSDIO_HTAV(regval)))
+
+#define BRCMF_MAX_CORENUM      6
+
+struct chip_core_info {
+       u16 id;
+       u16 rev;
+       u32 base;
+       u32 wrapbase;
+       u32 caps;
+       u32 cib;
+};
+
+struct chip_info {
+       u32 chip;
+       u32 chiprev;
+       u32 socitype;
+       /* core info */
+       /* always put chipcommon core at 0, bus core at 1 */
+       struct chip_core_info c_inf[BRCMF_MAX_CORENUM];
+       u32 pmurev;
+       u32 pmucaps;
+       u32 ramsize;
+
+       bool (*iscoreup)(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci,
+                        u16 coreid);
+       u32 (*corerev)(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci,
+                        u16 coreid);
+       void (*coredisable)(struct brcmf_sdio_dev *sdiodev,
+                       struct chip_info *ci, u16 coreid);
+       void (*resetcore)(struct brcmf_sdio_dev *sdiodev,
+                       struct chip_info *ci, u16 coreid);
+};
+
+struct sbconfig {
+       u32 PAD[2];
+       u32 sbipsflag;  /* initiator port ocp slave flag */
+       u32 PAD[3];
+       u32 sbtpsflag;  /* target port ocp slave flag */
+       u32 PAD[11];
+       u32 sbtmerrloga;        /* (sonics >= 2.3) */
+       u32 PAD;
+       u32 sbtmerrlog; /* (sonics >= 2.3) */
+       u32 PAD[3];
+       u32 sbadmatch3; /* address match3 */
+       u32 PAD;
+       u32 sbadmatch2; /* address match2 */
+       u32 PAD;
+       u32 sbadmatch1; /* address match1 */
+       u32 PAD[7];
+       u32 sbimstate;  /* initiator agent state */
+       u32 sbintvec;   /* interrupt mask */
+       u32 sbtmstatelow;       /* target state */
+       u32 sbtmstatehigh;      /* target state */
+       u32 sbbwa0;             /* bandwidth allocation table0 */
+       u32 PAD;
+       u32 sbimconfiglow;      /* initiator configuration */
+       u32 sbimconfighigh;     /* initiator configuration */
+       u32 sbadmatch0; /* address match0 */
+       u32 PAD;
+       u32 sbtmconfiglow;      /* target configuration */
+       u32 sbtmconfighigh;     /* target configuration */
+       u32 sbbconfig;  /* broadcast configuration */
+       u32 PAD;
+       u32 sbbstate;   /* broadcast state */
+       u32 PAD[3];
+       u32 sbactcnfg;  /* activate configuration */
+       u32 PAD[3];
+       u32 sbflagst;   /* current sbflags */
+       u32 PAD[3];
+       u32 sbidlow;            /* identification */
+       u32 sbidhigh;   /* identification */
+};
+
+extern int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev,
+                                 struct chip_info **ci_ptr, u32 regs);
+extern void brcmf_sdio_chip_detach(struct chip_info **ci_ptr);
+extern void brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
+                                             struct chip_info *ci,
+                                             u32 drivestrength);
+extern u8 brcmf_sdio_chip_getinfidx(struct chip_info *ci, u16 coreid);
+
+
+#endif         /* _BRCMFMAC_SDIO_CHIP_H_ */
index 5eddabe..cc19a73 100644 (file)
@@ -1997,7 +1997,7 @@ done:
 }
 
 static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_priv *cfg_priv,
-                                  struct brcmf_bss_info *bi)
+                                  struct brcmf_bss_info_le *bi)
 {
        struct wiphy *wiphy = cfg_to_wiphy(cfg_priv);
        struct ieee80211_channel *notify_channel;
@@ -2049,18 +2049,27 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_priv *cfg_priv,
                notify_timestamp, notify_capability, notify_interval, notify_ie,
                notify_ielen, notify_signal, GFP_KERNEL);
 
-       if (!bss) {
-               WL_ERR("cfg80211_inform_bss_frame error\n");
-               return -EINVAL;
-       }
+       if (!bss)
+               return -ENOMEM;
+
+       cfg80211_put_bss(bss);
 
        return err;
 }
 
+static struct brcmf_bss_info_le *
+next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
+{
+       if (bss == NULL)
+               return list->bss_info_le;
+       return (struct brcmf_bss_info_le *)((unsigned long)bss +
+                                           le32_to_cpu(bss->length));
+}
+
 static s32 brcmf_inform_bss(struct brcmf_cfg80211_priv *cfg_priv)
 {
        struct brcmf_scan_results *bss_list;
-       struct brcmf_bss_info *bi = NULL;       /* must be initialized */
+       struct brcmf_bss_info_le *bi = NULL;    /* must be initialized */
        s32 err = 0;
        int i;
 
@@ -2072,7 +2081,7 @@ static s32 brcmf_inform_bss(struct brcmf_cfg80211_priv *cfg_priv)
        }
        WL_SCAN("scanned AP count (%d)\n", bss_list->count);
        for (i = 0; i < bss_list->count && i < WL_AP_MAX; i++) {
-               bi = next_bss(bss_list, bi);
+               bi = next_bss_le(bss_list, bi);
                err = brcmf_inform_single_bss(cfg_priv, bi);
                if (err)
                        break;
@@ -2085,8 +2094,9 @@ static s32 wl_inform_ibss(struct brcmf_cfg80211_priv *cfg_priv,
 {
        struct wiphy *wiphy = cfg_to_wiphy(cfg_priv);
        struct ieee80211_channel *notify_channel;
-       struct brcmf_bss_info *bi = NULL;
+       struct brcmf_bss_info_le *bi = NULL;
        struct ieee80211_supported_band *band;
+       struct cfg80211_bss *bss;
        u8 *buf = NULL;
        s32 err = 0;
        u16 channel;
@@ -2114,7 +2124,7 @@ static s32 wl_inform_ibss(struct brcmf_cfg80211_priv *cfg_priv,
                goto CleanUp;
        }
 
-       bi = (struct brcmf_bss_info *)(buf + 4);
+       bi = (struct brcmf_bss_info_le *)(buf + 4);
 
        channel = bi->ctl_ch ? bi->ctl_ch :
                                CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
@@ -2140,10 +2150,17 @@ static s32 wl_inform_ibss(struct brcmf_cfg80211_priv *cfg_priv,
        WL_CONN("signal: %d\n", notify_signal);
        WL_CONN("notify_timestamp: %#018llx\n", notify_timestamp);
 
-       cfg80211_inform_bss(wiphy, notify_channel, bssid,
+       bss = cfg80211_inform_bss(wiphy, notify_channel, bssid,
                notify_timestamp, notify_capability, notify_interval,
                notify_ie, notify_ielen, notify_signal, GFP_KERNEL);
 
+       if (!bss) {
+               err = -ENOMEM;
+               goto CleanUp;
+       }
+
+       cfg80211_put_bss(bss);
+
 CleanUp:
 
        kfree(buf);
@@ -2188,7 +2205,7 @@ static struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key)
 
 static s32 brcmf_update_bss_info(struct brcmf_cfg80211_priv *cfg_priv)
 {
-       struct brcmf_bss_info *bi;
+       struct brcmf_bss_info_le *bi;
        struct brcmf_ssid *ssid;
        struct brcmf_tlv *tim;
        u16 beacon_interval;
@@ -2211,7 +2228,7 @@ static s32 brcmf_update_bss_info(struct brcmf_cfg80211_priv *cfg_priv)
                goto update_bss_info_out;
        }
 
-       bi = (struct brcmf_bss_info *)(cfg_priv->extra_buf + 4);
+       bi = (struct brcmf_bss_info_le *)(cfg_priv->extra_buf + 4);
        err = brcmf_inform_single_bss(cfg_priv, bi);
        if (err)
                goto update_bss_info_out;
index 62dc461..a613b49 100644 (file)
@@ -352,15 +352,6 @@ brcmf_cfg80211_connect_info *cfg_to_conn(struct brcmf_cfg80211_priv *cfg)
        return &cfg->conn_info;
 }
 
-static inline struct brcmf_bss_info *next_bss(struct brcmf_scan_results *list,
-                                          struct brcmf_bss_info *bss)
-{
-       return bss = bss ?
-               (struct brcmf_bss_info *)((unsigned long)bss +
-                                      le32_to_cpu(bss->length)) :
-               list->bss_info;
-}
-
 extern struct brcmf_cfg80211_dev *brcmf_cfg80211_attach(struct net_device *ndev,
                                                        struct device *busdev,
                                                        void *data);
index 106a742..b51d1e4 100644 (file)
 /* PCIE Client Mode sb2pcitranslation2 (2 ZettaBytes), high 32 bits */
 #define SI_PCIE_DMA_H32                0x80000000
 
-/* core codes */
-#define        NODEV_CORE_ID           0x700   /* Invalid coreid */
-#define        CC_CORE_ID              0x800   /* chipcommon core */
-#define        ILINE20_CORE_ID         0x801   /* iline20 core */
-#define        SRAM_CORE_ID            0x802   /* sram core */
-#define        SDRAM_CORE_ID           0x803   /* sdram core */
-#define        PCI_CORE_ID             0x804   /* pci core */
-#define        MIPS_CORE_ID            0x805   /* mips core */
-#define        ENET_CORE_ID            0x806   /* enet mac core */
-#define        CODEC_CORE_ID           0x807   /* v90 codec core */
-#define        USB_CORE_ID             0x808   /* usb 1.1 host/device core */
-#define        ADSL_CORE_ID            0x809   /* ADSL core */
-#define        ILINE100_CORE_ID        0x80a   /* iline100 core */
-#define        IPSEC_CORE_ID           0x80b   /* ipsec core */
-#define        UTOPIA_CORE_ID          0x80c   /* utopia core */
-#define        PCMCIA_CORE_ID          0x80d   /* pcmcia core */
-#define        SOCRAM_CORE_ID          0x80e   /* internal memory core */
-#define        MEMC_CORE_ID            0x80f   /* memc sdram core */
-#define        OFDM_CORE_ID            0x810   /* OFDM phy core */
-#define        EXTIF_CORE_ID           0x811   /* external interface core */
-#define        D11_CORE_ID             0x812   /* 802.11 MAC core */
-#define        APHY_CORE_ID            0x813   /* 802.11a phy core */
-#define        BPHY_CORE_ID            0x814   /* 802.11b phy core */
-#define        GPHY_CORE_ID            0x815   /* 802.11g phy core */
-#define        MIPS33_CORE_ID          0x816   /* mips3302 core */
-#define        USB11H_CORE_ID          0x817   /* usb 1.1 host core */
-#define        USB11D_CORE_ID          0x818   /* usb 1.1 device core */
-#define        USB20H_CORE_ID          0x819   /* usb 2.0 host core */
-#define        USB20D_CORE_ID          0x81a   /* usb 2.0 device core */
-#define        SDIOH_CORE_ID           0x81b   /* sdio host core */
-#define        ROBO_CORE_ID            0x81c   /* roboswitch core */
-#define        ATA100_CORE_ID          0x81d   /* parallel ATA core */
-#define        SATAXOR_CORE_ID         0x81e   /* serial ATA & XOR DMA core */
-#define        GIGETH_CORE_ID          0x81f   /* gigabit ethernet core */
-#define        PCIE_CORE_ID            0x820   /* pci express core */
-#define        NPHY_CORE_ID            0x821   /* 802.11n 2x2 phy core */
-#define        SRAMC_CORE_ID           0x822   /* SRAM controller core */
-#define        MINIMAC_CORE_ID         0x823   /* MINI MAC/phy core */
-#define        ARM11_CORE_ID           0x824   /* ARM 1176 core */
-#define        ARM7S_CORE_ID           0x825   /* ARM7tdmi-s core */
-#define        LPPHY_CORE_ID           0x826   /* 802.11a/b/g phy core */
-#define        PMU_CORE_ID             0x827   /* PMU core */
-#define        SSNPHY_CORE_ID          0x828   /* 802.11n single-stream phy core */
-#define        SDIOD_CORE_ID           0x829   /* SDIO device core */
-#define        ARMCM3_CORE_ID          0x82a   /* ARM Cortex M3 core */
-#define        HTPHY_CORE_ID           0x82b   /* 802.11n 4x4 phy core */
-#define        MIPS74K_CORE_ID         0x82c   /* mips 74k core */
-#define        GMAC_CORE_ID            0x82d   /* Gigabit MAC core */
-#define        DMEMC_CORE_ID           0x82e   /* DDR1/2 memory controller core */
-#define        PCIERC_CORE_ID          0x82f   /* PCIE Root Complex core */
-#define        OCP_CORE_ID             0x830   /* OCP2OCP bridge core */
-#define        SC_CORE_ID              0x831   /* shared common core */
-#define        AHB_CORE_ID             0x832   /* OCP2AHB bridge core */
-#define        SPIH_CORE_ID            0x833   /* SPI host core */
-#define        I2S_CORE_ID             0x834   /* I2S core */
-#define        DMEMS_CORE_ID           0x835   /* SDR/DDR1 memory controller core */
-#define        DEF_SHIM_COMP           0x837   /* SHIM component in ubus/6362 */
-#define OOB_ROUTER_CORE_ID     0x367   /* OOB router core ID */
-#define        DEF_AI_COMP             0xfff   /* Default component, in ai chips it
-                                        * maps all unused address ranges
-                                        */
-
 /* chipcommon being the first core: */
 #define        SI_CC_IDX               0
 
 /* SOC Interconnect types (aka chip types) */
 #define        SOCI_AI                 1
 
-/* Common core control flags */
-#define        SICF_BIST_EN            0x8000
-#define        SICF_PME_EN             0x4000
-#define        SICF_CORE_BITS          0x3ffc
-#define        SICF_FGC                0x0002
-#define        SICF_CLOCK_EN           0x0001
-
-/* Common core status flags */
-#define        SISF_BIST_DONE          0x8000
-#define        SISF_BIST_ERROR         0x4000
-#define        SISF_GATED_CLK          0x2000
-#define        SISF_DMA64              0x1000
-#define        SISF_CORE_BITS          0x0fff
-
 /* A register that is common to all cores to
  * communicate w/PMU regarding clock control.
  */
index 7f27dbd..43f7a72 100644 (file)
@@ -649,7 +649,7 @@ brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi,
                len = roundup(len, 4);
                ampdu_len += (len + (ndelim + 1) * AMPDU_DELIMITER_LEN);
 
-               dma_len += (u16) brcmu_pkttotlen(p);
+               dma_len += (u16) p->len;
 
                BCMMSG(wlc->wiphy, "wl%d: ampdu_len %d"
                        " seg_cnt %d null delim %d\n",
@@ -741,9 +741,7 @@ brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi,
                if (p) {
                        if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) &&
                            ((u8) (p->priority) == tid)) {
-
-                               plen = brcmu_pkttotlen(p) +
-                                      AMPDU_MAX_MPDU_OVERHEAD;
+                               plen = p->len + AMPDU_MAX_MPDU_OVERHEAD;
                                plen = max(scb_ampdu->min_len, plen);
 
                                if ((plen + ampdu_len) > max_ampdu_bytes) {
index 89ad1b7..55e9f45 100644 (file)
@@ -1153,121 +1153,6 @@ brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, u16 chanspec,
                              &txpwr);
 }
 
-#ifdef POWER_DBG
-static void wlc_phy_txpower_limits_dump(struct txpwr_limits *txpwr)
-{
-       int i;
-       char buf[80];
-       char fraction[4][4] = { "   ", ".25", ".5 ", ".75" };
-
-       sprintf(buf, "CCK                ");
-       for (i = 0; i < BRCMS_NUM_RATES_CCK; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->cck[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->cck[i] % BRCMS_TXPWR_DB_FACTOR]);
-       printk(KERN_DEBUG "%s\n", buf);
-
-       sprintf(buf, "20 MHz OFDM SISO   ");
-       for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->ofdm[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->ofdm[i] % BRCMS_TXPWR_DB_FACTOR]);
-       printk(KERN_DEBUG "%s\n", buf);
-
-       sprintf(buf, "20 MHz OFDM CDD    ");
-       for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->ofdm_cdd[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->ofdm_cdd[i] % BRCMS_TXPWR_DB_FACTOR]);
-       printk(KERN_DEBUG "%s\n", buf);
-
-       sprintf(buf, "40 MHz OFDM SISO   ");
-       for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->ofdm_40_siso[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->ofdm_40_siso[i] %
-                                                       BRCMS_TXPWR_DB_FACTOR]);
-       printk(KERN_DEBUG "%s\n", buf);
-
-       sprintf(buf, "40 MHz OFDM CDD    ");
-       for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->ofdm_40_cdd[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->ofdm_40_cdd[i] %
-                                                       BRCMS_TXPWR_DB_FACTOR]);
-       printk(KERN_DEBUG "%s\n", buf);
-
-       sprintf(buf, "20 MHz MCS0-7 SISO ");
-       for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->mcs_20_siso[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->mcs_20_siso[i] %
-                                                       BRCMS_TXPWR_DB_FACTOR]);
-       printk(KERN_DEBUG "%s\n", buf);
-
-       sprintf(buf, "20 MHz MCS0-7 CDD  ");
-       for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->mcs_20_cdd[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->mcs_20_cdd[i] %
-                                                       BRCMS_TXPWR_DB_FACTOR]);
-       printk(KERN_DEBUG "%s\n", buf);
-
-       sprintf(buf, "20 MHz MCS0-7 STBC ");
-       for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->mcs_20_stbc[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->mcs_20_stbc[i] %
-                                                       BRCMS_TXPWR_DB_FACTOR]);
-       printk(KERN_DEBUG "%s\n", buf);
-
-       sprintf(buf, "20 MHz MCS8-15 SDM ");
-       for (i = 0; i < BRCMS_NUM_RATES_MCS_2_STREAM; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->mcs_20_mimo[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->mcs_20_mimo[i] %
-                                                       BRCMS_TXPWR_DB_FACTOR]);
-       printk(KERN_DEBUG "%s\n", buf);
-
-       sprintf(buf, "40 MHz MCS0-7 SISO ");
-       for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->mcs_40_siso[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->mcs_40_siso[i] %
-                                                       BRCMS_TXPWR_DB_FACTOR]);
-       printk(KERN_DEBUG "%s\n", buf);
-
-       sprintf(buf, "40 MHz MCS0-7 CDD  ");
-       for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->mcs_40_cdd[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->mcs_40_cdd[i] %
-                                                       BRCMS_TXPWR_DB_FACTOR]);
-       printk(KERN_DEBUG "%s\n", buf);
-
-       sprintf(buf, "40 MHz MCS0-7 STBC ");
-       for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->mcs_40_stbc[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->mcs_40_stbc[i] %
-                                                       BRCMS_TXPWR_DB_FACTOR]);
-       printk(KERN_DEBUG "%s\n", buf);
-
-       sprintf(buf, "40 MHz MCS8-15 SDM ");
-       for (i = 0; i < BRCMS_NUM_RATES_MCS_2_STREAM; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->mcs_40_mimo[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->mcs_40_mimo[i] %
-                                                       BRCMS_TXPWR_DB_FACTOR]);
-       }
-       printk(KERN_DEBUG "%s\n", buf);
-
-       printk(KERN_DEBUG "MCS32               %2d%s\n",
-              txpwr->mcs32 / BRCMS_TXPWR_DB_FACTOR,
-              fraction[txpwr->mcs32 % BRCMS_TXPWR_DB_FACTOR]);
-}
-#endif                         /* POWER_DBG */
-
 void
 brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec,
                       struct txpwr_limits *txpwr)
@@ -1478,9 +1363,6 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec,
                        txpwr->mcs_40_stbc[i] = txpwr->mcs_40_cdd[i];
        }
 
-#ifdef POWER_DBG
-       wlc_phy_txpower_limits_dump(txpwr);
-#endif
        return;
 }
 
index b56a302..e286fb4 100644 (file)
@@ -14,7 +14,6 @@
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 #include <linux/slab.h>
-#include <linux/skbuff.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
 
@@ -22,6 +21,7 @@
 #include <aiutils.h>
 #include "types.h"
 #include "dma.h"
+#include "soc.h"
 
 /*
  * DMA hardware requires each descriptor ring to be 8kB aligned, and fit within
@@ -358,13 +358,14 @@ static uint nrxdactive(struct dma_info *di, uint h, uint t)
 
 static uint _dma_ctrlflags(struct dma_info *di, uint mask, uint flags)
 {
-       uint dmactrlflags = di->dma.dmactrlflags;
+       uint dmactrlflags;
 
        if (di == NULL) {
-               DMA_ERROR(("%s: _dma_ctrlflags: NULL dma handle\n", di->name));
+               DMA_ERROR(("_dma_ctrlflags: NULL dma handle\n"));
                return 0;
        }
 
+       dmactrlflags = di->dma.dmactrlflags;
        dmactrlflags &= ~mask;
        dmactrlflags |= flags;
 
@@ -900,7 +901,7 @@ static struct sk_buff *_dma_getnextrxp(struct dma_info *di, bool forceall)
 
 /*
  * !! rx entry routine
- * returns a pointer to the next frame received, or NULL if there are no more
+ * returns the number packages in the next frame, or 0 if there are no more
  *   if DMA_CTRL_RXMULTI is defined, DMA scattering(multiple buffers) is
  *   supported with pkts chain
  *   otherwise, it's treated as giant pkt and will be tossed.
@@ -908,38 +909,40 @@ static struct sk_buff *_dma_getnextrxp(struct dma_info *di, bool forceall)
  *   buffer data. After it reaches the max size of buffer, the data continues
  *   in next DMA descriptor buffer WITHOUT DMA header
  */
-struct sk_buff *dma_rx(struct dma_pub *pub)
+int dma_rx(struct dma_pub *pub, struct sk_buff_head *skb_list)
 {
        struct dma_info *di = (struct dma_info *)pub;
-       struct sk_buff *p, *head, *tail;
+       struct sk_buff_head dma_frames;
+       struct sk_buff *p, *next;
        uint len;
        uint pkt_len;
        int resid = 0;
+       int pktcnt = 1;
 
+       skb_queue_head_init(&dma_frames);
  next_frame:
-       head = _dma_getnextrxp(di, false);
-       if (head == NULL)
-               return NULL;
+       p = _dma_getnextrxp(di, false);
+       if (p == NULL)
+               return 0;
 
-       len = le16_to_cpu(*(__le16 *) (head->data));
+       len = le16_to_cpu(*(__le16 *) (p->data));
        DMA_TRACE(("%s: dma_rx len %d\n", di->name, len));
-       dma_spin_for_len(len, head);
+       dma_spin_for_len(len, p);
 
        /* set actual length */
        pkt_len = min((di->rxoffset + len), di->rxbufsize);
-       __skb_trim(head, pkt_len);
+       __skb_trim(p, pkt_len);
+       skb_queue_tail(&dma_frames, p);
        resid = len - (di->rxbufsize - di->rxoffset);
 
        /* check for single or multi-buffer rx */
        if (resid > 0) {
-               tail = head;
                while ((resid > 0) && (p = _dma_getnextrxp(di, false))) {
-                       tail->next = p;
                        pkt_len = min_t(uint, resid, di->rxbufsize);
                        __skb_trim(p, pkt_len);
-
-                       tail = p;
+                       skb_queue_tail(&dma_frames, p);
                        resid -= di->rxbufsize;
+                       pktcnt++;
                }
 
 #ifdef BCMDBG
@@ -958,13 +961,18 @@ struct sk_buff *dma_rx(struct dma_pub *pub)
                if ((di->dma.dmactrlflags & DMA_CTRL_RXMULTI) == 0) {
                        DMA_ERROR(("%s: dma_rx: bad frame length (%d)\n",
                                   di->name, len));
-                       brcmu_pkt_buf_free_skb(head);
+                       skb_queue_walk_safe(&dma_frames, p, next) {
+                               skb_unlink(p, &dma_frames);
+                               brcmu_pkt_buf_free_skb(p);
+                       }
                        di->dma.rxgiants++;
+                       pktcnt = 1;
                        goto next_frame;
                }
        }
 
-       return head;
+       skb_queue_splice_tail(&dma_frames, skb_list);
+       return pktcnt;
 }
 
 static bool dma64_rxidle(struct dma_info *di)
index ebc5bc5..d317c7c 100644 (file)
@@ -18,6 +18,7 @@
 #define        _BRCM_DMA_H_
 
 #include <linux/delay.h>
+#include <linux/skbuff.h>
 #include "types.h"             /* forward structure declarations */
 
 /* map/unmap direction */
@@ -80,7 +81,7 @@ extern struct dma_pub *dma_attach(char *name, struct si_pub *sih,
                            uint nrxpost, uint rxoffset, uint *msg_level);
 
 void dma_rxinit(struct dma_pub *pub);
-struct sk_buff *dma_rx(struct dma_pub *pub);
+int dma_rx(struct dma_pub *pub, struct sk_buff_head *skb_list);
 bool dma_rxfill(struct dma_pub *pub);
 bool dma_rxreset(struct dma_pub *pub);
 bool dma_txreset(struct dma_pub *pub);
index 0d8a9cd..8457e96 100644 (file)
@@ -216,8 +216,7 @@ static const struct ieee80211_supported_band brcms_band_2GHz_nphy_template = {
        .ht_cap = {
                   /* from include/linux/ieee80211.h */
                   .cap = IEEE80211_HT_CAP_GRN_FLD |
-                  IEEE80211_HT_CAP_SGI_20 |
-                  IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_40MHZ_INTOLERANT,
+                         IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40,
                   .ht_supported = true,
                   .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
                   .ampdu_density = AMPDU_DEF_MPDU_DENSITY,
@@ -238,8 +237,7 @@ static const struct ieee80211_supported_band brcms_band_5GHz_nphy_template = {
                        BRCMS_LEGACY_5G_RATE_OFFSET,
        .ht_cap = {
                   .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 |
-                         IEEE80211_HT_CAP_SGI_40 |
-                         IEEE80211_HT_CAP_40MHZ_INTOLERANT, /* No 40 mhz yet */
+                         IEEE80211_HT_CAP_SGI_40,
                   .ht_supported = true,
                   .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
                   .ampdu_density = AMPDU_DEF_MPDU_DENSITY,
@@ -287,6 +285,7 @@ static int brcms_ops_start(struct ieee80211_hw *hw)
 {
        struct brcms_info *wl = hw->priv;
        bool blocked;
+       int err;
 
        ieee80211_wake_queues(hw);
        spin_lock_bh(&wl->lock);
@@ -295,57 +294,69 @@ static int brcms_ops_start(struct ieee80211_hw *hw)
        if (!blocked)
                wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy);
 
-       return 0;
+       spin_lock_bh(&wl->lock);
+       /* avoid acknowledging frames before a non-monitor device is added */
+       wl->mute_tx = true;
+
+       if (!wl->pub->up)
+               err = brcms_up(wl);
+       else
+               err = -ENODEV;
+       spin_unlock_bh(&wl->lock);
+
+       if (err != 0)
+               wiphy_err(hw->wiphy, "%s: brcms_up() returned %d\n", __func__,
+                         err);
+       return err;
 }
 
 static void brcms_ops_stop(struct ieee80211_hw *hw)
 {
+       struct brcms_info *wl = hw->priv;
+       int status;
+
        ieee80211_stop_queues(hw);
+
+       if (wl->wlc == NULL)
+               return;
+
+       spin_lock_bh(&wl->lock);
+       status = brcms_c_chipmatch(wl->wlc->hw->vendorid,
+                                  wl->wlc->hw->deviceid);
+       spin_unlock_bh(&wl->lock);
+       if (!status) {
+               wiphy_err(wl->wiphy,
+                         "wl: brcms_ops_stop: chipmatch failed\n");
+               return;
+       }
+
+       /* put driver in down state */
+       spin_lock_bh(&wl->lock);
+       brcms_down(wl);
+       spin_unlock_bh(&wl->lock);
 }
 
 static int
 brcms_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
-       struct brcms_info *wl;
-       int err;
+       struct brcms_info *wl = hw->priv;
 
        /* Just STA for now */
-       if (vif->type != NL80211_IFTYPE_AP &&
-           vif->type != NL80211_IFTYPE_MESH_POINT &&
-           vif->type != NL80211_IFTYPE_STATION &&
-           vif->type != NL80211_IFTYPE_WDS &&
-           vif->type != NL80211_IFTYPE_ADHOC) {
+       if (vif->type != NL80211_IFTYPE_STATION) {
                wiphy_err(hw->wiphy, "%s: Attempt to add type %d, only"
                          " STA for now\n", __func__, vif->type);
                return -EOPNOTSUPP;
        }
 
-       wl = hw->priv;
-       spin_lock_bh(&wl->lock);
-       if (!wl->pub->up)
-               err = brcms_up(wl);
-       else
-               err = -ENODEV;
-       spin_unlock_bh(&wl->lock);
-
-       if (err != 0)
-               wiphy_err(hw->wiphy, "%s: brcms_up() returned %d\n", __func__,
-                         err);
+       wl->mute_tx = false;
+       brcms_c_mute(wl->wlc, false);
 
-       return err;
+       return 0;
 }
 
 static void
 brcms_ops_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
-       struct brcms_info *wl;
-
-       wl = hw->priv;
-
-       /* put driver in down state */
-       spin_lock_bh(&wl->lock);
-       brcms_down(wl);
-       spin_unlock_bh(&wl->lock);
 }
 
 static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed)
@@ -609,13 +620,6 @@ brcms_ops_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
        wl->pub->global_ampdu->scb = scb;
        wl->pub->global_ampdu->max_pdu = 16;
 
-       sta->ht_cap.ht_supported = true;
-       sta->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
-       sta->ht_cap.ampdu_density = AMPDU_DEF_MPDU_DENSITY;
-       sta->ht_cap.cap = IEEE80211_HT_CAP_GRN_FLD |
-           IEEE80211_HT_CAP_SGI_20 |
-           IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_40MHZ_INTOLERANT;
-
        /*
         * minstrel_ht initiates addBA on our behalf by calling
         * ieee80211_start_tx_ba_session()
@@ -877,37 +881,18 @@ static void brcms_free(struct brcms_info *wl)
 }
 
 /*
-* called from both kernel as from this kernel module.
+* called from both kernel as from this kernel module (error flow on attach)
 * precondition: perimeter lock is not acquired.
 */
 static void brcms_remove(struct pci_dev *pdev)
 {
-       struct brcms_info *wl;
-       struct ieee80211_hw *hw;
-       int status;
-
-       hw = pci_get_drvdata(pdev);
-       wl = hw->priv;
-       if (!wl) {
-               pr_err("wl: brcms_remove: pci_get_drvdata failed\n");
-               return;
-       }
+       struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+       struct brcms_info *wl = hw->priv;
 
-       spin_lock_bh(&wl->lock);
-       status = brcms_c_chipmatch(pdev->vendor, pdev->device);
-       spin_unlock_bh(&wl->lock);
-       if (!status) {
-               wiphy_err(wl->wiphy, "wl: brcms_remove: chipmatch "
-                                    "failed\n");
-               return;
-       }
        if (wl->wlc) {
                wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, false);
                wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy);
                ieee80211_unregister_hw(hw);
-               spin_lock_bh(&wl->lock);
-               brcms_down(wl);
-               spin_unlock_bh(&wl->lock);
        }
        pci_disable_device(pdev);
 
@@ -1081,9 +1066,6 @@ static struct brcms_info *brcms_attach(u16 vendor, u16 device,
 
        wl->pub->ieee_hw = hw;
 
-       /* disable mpc */
-       brcms_c_set_radio_mpc(wl->wlc, false);
-
        /* register our interrupt handler */
        if (request_irq(irq, brcms_isr, IRQF_SHARED, KBUILD_MODNAME, wl)) {
                wiphy_err(wl->wiphy, "wl%d: request_irq() failed\n", unit);
@@ -1319,8 +1301,7 @@ void brcms_init(struct brcms_info *wl)
 {
        BCMMSG(wl->pub->ieee_hw->wiphy, "wl%d\n", wl->pub->unit);
        brcms_reset(wl);
-
-       brcms_c_init(wl->wlc);
+       brcms_c_init(wl->wlc, wl->mute_tx);
 }
 
 /*
@@ -1337,6 +1318,14 @@ uint brcms_reset(struct brcms_info *wl)
        return 0;
 }
 
+void brcms_fatal_error(struct brcms_info *wl)
+{
+       wiphy_err(wl->wlc->wiphy, "wl%d: fatal error, reinitializing\n",
+                 wl->wlc->pub->unit);
+       brcms_reset(wl);
+       ieee80211_restart_hw(wl->pub->ieee_hw);
+}
+
 /*
  * These are interrupt on/off entry points. Disable interrupts
  * during interrupt state transition.
index 177f0e4..6242f18 100644 (file)
@@ -80,6 +80,7 @@ struct brcms_info {
        struct brcms_firmware fw;
        struct wiphy *wiphy;
        struct brcms_ucode ucode;
+       bool mute_tx;
 };
 
 /* misc callbacks */
@@ -104,5 +105,6 @@ extern bool brcms_del_timer(struct brcms_timer *timer);
 extern void brcms_msleep(struct brcms_info *wl, uint ms);
 extern void brcms_dpc(unsigned long data);
 extern void brcms_timer(struct brcms_timer *t);
+extern void brcms_fatal_error(struct brcms_info *wl);
 
 #endif                         /* _BRCM_MAC80211_IF_H_ */
index 510e9bb..36e3e06 100644 (file)
 #include "mac80211_if.h"
 #include "ucode_loader.h"
 #include "main.h"
+#include "soc.h"
 
 /*
  * Indication for txflowcontrol that all priority bits in
  * TXQ_STOP_FOR_PRIOFC_MASK are to be considered.
  */
-#define ALLPRIO                -1
-
-/*
- * 32 SSID chars, max of 4 chars for each SSID char "\xFF", plus NULL.
- */
-#define SSID_FMT_BUF_LEN       ((4 * IEEE80211_MAX_SSID_LEN) + 1)
+#define ALLPRIO                                -1
 
 /* watchdog timer, in unit of ms */
-#define        TIMER_INTERVAL_WATCHDOG 1000
+#define TIMER_INTERVAL_WATCHDOG                1000
 /* radio monitor timer, in unit of ms */
-#define        TIMER_INTERVAL_RADIOCHK 800
-
-/* Max MPC timeout, in unit of watchdog */
-#ifndef BRCMS_MPC_MAX_DELAYCNT
-#define        BRCMS_MPC_MAX_DELAYCNT  10
-#endif
-
-/* Min MPC timeout, in unit of watchdog */
-#define        BRCMS_MPC_MIN_DELAYCNT  1
-#define        BRCMS_MPC_THRESHOLD     3       /* MPC count threshold level */
+#define TIMER_INTERVAL_RADIOCHK                800
 
 /* beacon interval, in unit of 1024TU */
-#define        BEACON_INTERVAL_DEFAULT 100
-/* DTIM interval, in unit of beacon interval */
-#define        DTIM_INTERVAL_DEFAULT   3
-
-/* Scale down delays to accommodate QT slow speed */
-/* beacon interval, in unit of 1024TU */
-#define        BEACON_INTERVAL_DEF_QT  20
-/* DTIM interval, in unit of beacon interval */
-#define        DTIM_INTERVAL_DEF_QT    1
-
-#define        TBTT_ALIGN_LEEWAY_US    100     /* min leeway before first TBTT in us */
+#define BEACON_INTERVAL_DEFAULT                100
 
 /* n-mode support capability */
 /* 2x2 includes both 1x1 & 2x2 devices
 #define WL_11N_3x3                     3
 #define WL_11N_4x4                     4
 
-/* define 11n feature disable flags */
-#define WLFEATURE_DISABLE_11N          0x00000001
-#define WLFEATURE_DISABLE_11N_STBC_TX  0x00000002
-#define WLFEATURE_DISABLE_11N_STBC_RX  0x00000004
-#define WLFEATURE_DISABLE_11N_SGI_TX   0x00000008
-#define WLFEATURE_DISABLE_11N_SGI_RX   0x00000010
-#define WLFEATURE_DISABLE_11N_AMPDU_TX 0x00000020
-#define WLFEATURE_DISABLE_11N_AMPDU_RX 0x00000040
-#define WLFEATURE_DISABLE_11N_GF       0x00000080
-
-#define EDCF_ACI_MASK                0x60
-#define EDCF_ACI_SHIFT               5
-#define EDCF_ECWMIN_MASK             0x0f
-#define EDCF_ECWMAX_SHIFT            4
-#define EDCF_AIFSN_MASK              0x0f
-#define EDCF_AIFSN_MAX               15
-#define EDCF_ECWMAX_MASK             0xf0
-
-#define EDCF_AC_BE_TXOP_STA          0x0000
-#define EDCF_AC_BK_TXOP_STA          0x0000
-#define EDCF_AC_VO_ACI_STA           0x62
-#define EDCF_AC_VO_ECW_STA           0x32
-#define EDCF_AC_VI_ACI_STA           0x42
-#define EDCF_AC_VI_ECW_STA           0x43
-#define EDCF_AC_BK_ECW_STA           0xA4
-#define EDCF_AC_VI_TXOP_STA          0x005e
-#define EDCF_AC_VO_TXOP_STA          0x002f
-#define EDCF_AC_BE_ACI_STA           0x03
-#define EDCF_AC_BE_ECW_STA           0xA4
-#define EDCF_AC_BK_ACI_STA           0x27
-#define EDCF_AC_VO_TXOP_AP           0x002f
-
-#define EDCF_TXOP2USEC(txop)         ((txop) << 5)
-#define EDCF_ECW2CW(exp)             ((1 << (exp)) - 1)
-
-#define APHY_SYMBOL_TIME       4
-#define APHY_PREAMBLE_TIME     16
-#define APHY_SIGNAL_TIME       4
-#define APHY_SIFS_TIME         16
-#define APHY_SERVICE_NBITS     16
-#define APHY_TAIL_NBITS                6
-#define BPHY_SIFS_TIME         10
-#define BPHY_PLCP_SHORT_TIME   96
-
-#define PREN_PREAMBLE          24
-#define PREN_MM_EXT            12
-#define PREN_PREAMBLE_EXT      4
+#define EDCF_ACI_MASK                  0x60
+#define EDCF_ACI_SHIFT                 5
+#define EDCF_ECWMIN_MASK               0x0f
+#define EDCF_ECWMAX_SHIFT              4
+#define EDCF_AIFSN_MASK                        0x0f
+#define EDCF_AIFSN_MAX                 15
+#define EDCF_ECWMAX_MASK               0xf0
+
+#define EDCF_AC_BE_TXOP_STA            0x0000
+#define EDCF_AC_BK_TXOP_STA            0x0000
+#define EDCF_AC_VO_ACI_STA             0x62
+#define EDCF_AC_VO_ECW_STA             0x32
+#define EDCF_AC_VI_ACI_STA             0x42
+#define EDCF_AC_VI_ECW_STA             0x43
+#define EDCF_AC_BK_ECW_STA             0xA4
+#define EDCF_AC_VI_TXOP_STA            0x005e
+#define EDCF_AC_VO_TXOP_STA            0x002f
+#define EDCF_AC_BE_ACI_STA             0x03
+#define EDCF_AC_BE_ECW_STA             0xA4
+#define EDCF_AC_BK_ACI_STA             0x27
+#define EDCF_AC_VO_TXOP_AP             0x002f
+
+#define EDCF_TXOP2USEC(txop)           ((txop) << 5)
+#define EDCF_ECW2CW(exp)               ((1 << (exp)) - 1)
+
+#define APHY_SYMBOL_TIME               4
+#define APHY_PREAMBLE_TIME             16
+#define APHY_SIGNAL_TIME               4
+#define APHY_SIFS_TIME                 16
+#define APHY_SERVICE_NBITS             16
+#define APHY_TAIL_NBITS                        6
+#define BPHY_SIFS_TIME                 10
+#define BPHY_PLCP_SHORT_TIME           96
+
+#define PREN_PREAMBLE                  24
+#define PREN_MM_EXT                    12
+#define PREN_PREAMBLE_EXT              4
 
 #define DOT11_MAC_HDR_LEN              24
-#define        DOT11_ACK_LEN           10
-#define DOT11_BA_LEN           4
+#define DOT11_ACK_LEN                  10
+#define DOT11_BA_LEN                   4
 #define DOT11_OFDM_SIGNAL_EXTENSION    6
 #define DOT11_MIN_FRAG_LEN             256
-#define        DOT11_RTS_LEN           16
-#define        DOT11_CTS_LEN           10
+#define DOT11_RTS_LEN                  16
+#define DOT11_CTS_LEN                  10
 #define DOT11_BA_BITMAP_LEN            128
 #define DOT11_MIN_BEACON_PERIOD                1
 #define DOT11_MAX_BEACON_PERIOD                0xFFFF
-#define        DOT11_MAXNUMFRAGS       16
+#define DOT11_MAXNUMFRAGS              16
 #define DOT11_MAX_FRAG_LEN             2346
 
-#define BPHY_PLCP_TIME         192
-#define RIFS_11N_TIME          2
-
-#define WME_VER                        1
-#define WME_SUBTYPE_PARAM_IE   1
-#define WME_TYPE               2
-#define WME_OUI                        "\x00\x50\xf2"
-
-#define AC_BE                  0
-#define AC_BK                  1
-#define AC_VI                  2
-#define AC_VO                  3
+#define BPHY_PLCP_TIME                 192
+#define RIFS_11N_TIME                  2
 
-#define        BCN_TMPL_LEN            512     /* length of the BCN template area */
+/* length of the BCN template area */
+#define BCN_TMPL_LEN                   512
 
 /* brcms_bss_info flag bit values */
-#define BRCMS_BSS_HT           0x0020  /* BSS is HT (MIMO) capable */
+#define BRCMS_BSS_HT                   0x0020  /* BSS is HT (MIMO) capable */
 
-/* Flags used in brcms_c_txq_info.stopped */
-/* per prio flow control bits */
-#define TXQ_STOP_FOR_PRIOFC_MASK       0x000000FF
-/* stop txq enqueue for packet drain */
-#define TXQ_STOP_FOR_PKT_DRAIN         0x00000100
-/* stop txq enqueue for ampdu flow control */
-#define TXQ_STOP_FOR_AMPDU_FLOW_CNTRL  0x00000200
-
-#define        BRCMS_HWRXOFF           38      /* chip rx buffer offset */
-
-/* Find basic rate for a given rate */
-static u8 brcms_basic_rate(struct brcms_c_info *wlc, u32 rspec)
-{
-       if (is_mcs_rate(rspec))
-               return wlc->band->basic_rate[mcs_table[rspec & RSPEC_RATE_MASK]
-                      .leg_ofdm];
-       return wlc->band->basic_rate[rspec & RSPEC_RATE_MASK];
-}
-
-static u16 frametype(u32 rspec, u8 mimoframe)
-{
-       if (is_mcs_rate(rspec))
-               return mimoframe;
-       return is_cck_rate(rspec) ? FT_CCK : FT_OFDM;
-}
+/* chip rx buffer offset */
+#define BRCMS_HWRXOFF                  38
 
 /* rfdisable delay timer 500 ms, runs of ALP clock */
-#define RFDISABLE_DEFAULT      10000000
+#define RFDISABLE_DEFAULT              10000000
 
 #define BRCMS_TEMPSENSE_PERIOD         10      /* 10 second timeout */
 
@@ -194,87 +129,83 @@ static u16 frametype(u32 rspec, u8 mimoframe)
  * These constants are used ONLY by wlc_prio2prec_map.  Do not use them
  * elsewhere.
  */
-#define        _BRCMS_PREC_NONE                0       /* None = - */
-#define        _BRCMS_PREC_BK          2       /* BK - Background */
-#define        _BRCMS_PREC_BE          4       /* BE - Best-effort */
-#define        _BRCMS_PREC_EE          6       /* EE - Excellent-effort */
-#define        _BRCMS_PREC_CL          8       /* CL - Controlled Load */
-#define        _BRCMS_PREC_VI          10      /* Vi - Video */
-#define        _BRCMS_PREC_VO          12      /* Vo - Voice */
-#define        _BRCMS_PREC_NC          14      /* NC - Network Control */
-
-/* The BSS is generating beacons in HW */
-#define BRCMS_BSSCFG_HW_BCN    0x20
-
-#define        SYNTHPU_DLY_APHY_US     3700    /* a phy synthpu_dly time in us */
-#define        SYNTHPU_DLY_BPHY_US     1050    /* b/g phy synthpu_dly time in us */
-#define        SYNTHPU_DLY_NPHY_US     2048    /* n phy REV3 synthpu_dly time in us */
-#define        SYNTHPU_DLY_LPPHY_US    300     /* lpphy synthpu_dly time in us */
-
-#define        SYNTHPU_DLY_PHY_US_QT   100     /* QT synthpu_dly time in us */
-
-#define        ANTCNT                  10      /* vanilla M_MAX_ANTCNT value */
+#define _BRCMS_PREC_NONE               0       /* None = - */
+#define _BRCMS_PREC_BK                 2       /* BK - Background */
+#define _BRCMS_PREC_BE                 4       /* BE - Best-effort */
+#define _BRCMS_PREC_EE                 6       /* EE - Excellent-effort */
+#define _BRCMS_PREC_CL                 8       /* CL - Controlled Load */
+#define _BRCMS_PREC_VI                 10      /* Vi - Video */
+#define _BRCMS_PREC_VO                 12      /* Vo - Voice */
+#define _BRCMS_PREC_NC                 14      /* NC - Network Control */
+
+/* synthpu_dly times in us */
+#define SYNTHPU_DLY_APHY_US            3700
+#define SYNTHPU_DLY_BPHY_US            1050
+#define SYNTHPU_DLY_NPHY_US            2048
+#define SYNTHPU_DLY_LPPHY_US           300
+
+#define ANTCNT                         10      /* vanilla M_MAX_ANTCNT val */
 
 /* Per-AC retry limit register definitions; uses defs.h bitfield macros */
-#define EDCF_SHORT_S            0
-#define EDCF_SFB_S              4
-#define EDCF_LONG_S             8
-#define EDCF_LFB_S              12
-#define EDCF_SHORT_M            BITFIELD_MASK(4)
-#define EDCF_SFB_M              BITFIELD_MASK(4)
-#define EDCF_LONG_M             BITFIELD_MASK(4)
-#define EDCF_LFB_M              BITFIELD_MASK(4)
+#define EDCF_SHORT_S                   0
+#define EDCF_SFB_S                     4
+#define EDCF_LONG_S                    8
+#define EDCF_LFB_S                     12
+#define EDCF_SHORT_M                   BITFIELD_MASK(4)
+#define EDCF_SFB_M                     BITFIELD_MASK(4)
+#define EDCF_LONG_M                    BITFIELD_MASK(4)
+#define EDCF_LFB_M                     BITFIELD_MASK(4)
 
-#define        RETRY_SHORT_DEF                 7       /* Default Short retry Limit */
-#define        RETRY_SHORT_MAX                 255     /* Maximum Short retry Limit */
-#define        RETRY_LONG_DEF                  4       /* Default Long retry count */
-#define        RETRY_SHORT_FB                  3 /* Short count for fallback rate */
-#define        RETRY_LONG_FB                   2 /* Long count for fallback rate */
+#define RETRY_SHORT_DEF                        7       /* Default Short retry Limit */
+#define RETRY_SHORT_MAX                        255     /* Maximum Short retry Limit */
+#define RETRY_LONG_DEF                 4       /* Default Long retry count */
+#define RETRY_SHORT_FB                 3       /* Short count for fb rate */
+#define RETRY_LONG_FB                  2       /* Long count for fb rate */
 
-#define        APHY_CWMIN              15
-#define PHY_CWMAX              1023
+#define APHY_CWMIN                     15
+#define PHY_CWMAX                      1023
 
-#define EDCF_AIFSN_MIN               1
+#define EDCF_AIFSN_MIN                 1
 
-#define FRAGNUM_MASK           0xF
+#define FRAGNUM_MASK                   0xF
 
-#define APHY_SLOT_TIME         9
-#define BPHY_SLOT_TIME         20
+#define APHY_SLOT_TIME                 9
+#define BPHY_SLOT_TIME                 20
 
-#define        WL_SPURAVOID_OFF        0
-#define        WL_SPURAVOID_ON1        1
-#define        WL_SPURAVOID_ON2        2
+#define WL_SPURAVOID_OFF               0
+#define WL_SPURAVOID_ON1               1
+#define WL_SPURAVOID_ON2               2
 
 /* invalid core flags, use the saved coreflags */
-#define BRCMS_USE_COREFLAGS    0xffffffff
+#define BRCMS_USE_COREFLAGS            0xffffffff
 
 /* values for PLCPHdr_override */
-#define BRCMS_PLCP_AUTO        -1
-#define BRCMS_PLCP_SHORT       0
-#define BRCMS_PLCP_LONG        1
+#define BRCMS_PLCP_AUTO                        -1
+#define BRCMS_PLCP_SHORT               0
+#define BRCMS_PLCP_LONG                        1
 
 /* values for g_protection_override and n_protection_override */
 #define BRCMS_PROTECTION_AUTO          -1
 #define BRCMS_PROTECTION_OFF           0
 #define BRCMS_PROTECTION_ON            1
 #define BRCMS_PROTECTION_MMHDR_ONLY    2
-#define BRCMS_PROTECTION_CTS_ONLY              3
+#define BRCMS_PROTECTION_CTS_ONLY      3
 
 /* values for g_protection_control and n_protection_control */
-#define BRCMS_PROTECTION_CTL_OFF               0
+#define BRCMS_PROTECTION_CTL_OFF       0
 #define BRCMS_PROTECTION_CTL_LOCAL     1
 #define BRCMS_PROTECTION_CTL_OVERLAP   2
 
 /* values for n_protection */
 #define BRCMS_N_PROTECTION_OFF         0
 #define BRCMS_N_PROTECTION_OPTIONAL    1
-#define BRCMS_N_PROTECTION_20IN40              2
+#define BRCMS_N_PROTECTION_20IN40      2
 #define BRCMS_N_PROTECTION_MIXEDMODE   3
 
 /* values for band specific 40MHz capabilities */
-#define BRCMS_N_BW_20ALL                       0
-#define BRCMS_N_BW_40ALL                       1
-#define BRCMS_N_BW_20IN2G_40IN5G               2
+#define BRCMS_N_BW_20ALL               0
+#define BRCMS_N_BW_40ALL               1
+#define BRCMS_N_BW_20IN2G_40IN5G       2
 
 /* bitflags for SGI support (sgi_rx iovar) */
 #define BRCMS_N_SGI_20                 0x01
@@ -282,48 +213,42 @@ static u16 frametype(u32 rspec, u8 mimoframe)
 
 /* defines used by the nrate iovar */
 /* MSC in use,indicates b0-6 holds an mcs */
-#define NRATE_MCS_INUSE        0x00000080
+#define NRATE_MCS_INUSE                        0x00000080
 /* rate/mcs value */
-#define NRATE_RATE_MASK 0x0000007f
+#define NRATE_RATE_MASK                        0x0000007f
 /* stf mode mask: siso, cdd, stbc, sdm */
-#define NRATE_STF_MASK 0x0000ff00
+#define NRATE_STF_MASK                 0x0000ff00
 /* stf mode shift */
-#define NRATE_STF_SHIFT        8
-/* bit indicates override both rate & mode */
-#define NRATE_OVERRIDE 0x80000000
+#define NRATE_STF_SHIFT                        8
 /* bit indicate to override mcs only */
-#define NRATE_OVERRIDE_MCS_ONLY 0x40000000
-#define NRATE_SGI_MASK  0x00800000     /* sgi mode */
-#define NRATE_SGI_SHIFT 23     /* sgi mode */
-#define NRATE_LDPC_CODING 0x00400000   /* bit indicates adv coding in use */
-#define NRATE_LDPC_SHIFT 22    /* ldpc shift */
+#define NRATE_OVERRIDE_MCS_ONLY                0x40000000
+#define NRATE_SGI_MASK                 0x00800000      /* sgi mode */
+#define NRATE_SGI_SHIFT                        23              /* sgi mode */
+#define NRATE_LDPC_CODING              0x00400000      /* adv coding in use */
+#define NRATE_LDPC_SHIFT               22              /* ldpc shift */
 
-#define NRATE_STF_SISO 0       /* stf mode SISO */
-#define NRATE_STF_CDD  1       /* stf mode CDD */
-#define NRATE_STF_STBC 2       /* stf mode STBC */
-#define NRATE_STF_SDM  3       /* stf mode SDM */
+#define NRATE_STF_SISO                 0               /* stf mode SISO */
+#define NRATE_STF_CDD                  1               /* stf mode CDD */
+#define NRATE_STF_STBC                 2               /* stf mode STBC */
+#define NRATE_STF_SDM                  3               /* stf mode SDM */
 
-#define MAX_DMA_SEGS 4
+#define MAX_DMA_SEGS                   4
 
 /* Max # of entries in Tx FIFO based on 4kb page size */
-#define NTXD           256
+#define NTXD                           256
 /* Max # of entries in Rx FIFO based on 4kb page size */
-#define NRXD           256
+#define NRXD                           256
 
 /* try to keep this # rbufs posted to the chip */
-#define        NRXBUFPOST      32
+#define NRXBUFPOST                     32
 
 /* data msg txq hiwat mark */
-#define BRCMS_DATAHIWAT                50
+#define BRCMS_DATAHIWAT                        50
 
-/* bounded rx loops */
-#define RXBND          8 /* max # frames to process in brcms_c_recv() */
-#define TXSBND         8 /* max # tx status to process in wlc_txstatus() */
-
-/*
- * 32 SSID chars, max of 4 chars for each SSID char "\xFF", plus NULL.
- */
-#define SSID_FMT_BUF_LEN       ((4 * IEEE80211_MAX_SSID_LEN) + 1)
+/* max # frames to process in brcms_c_recv() */
+#define RXBND                          8
+/* max # tx status to process in wlc_txstatus() */
+#define TXSBND                         8
 
 /* brcmu_format_flags() bit description structure */
 struct brcms_c_bit_desc {
@@ -375,10 +300,22 @@ uint brcm_msg_level =
 #endif                         /* BCMDBG */
 
 /* TX FIFO number to WME/802.1E Access Category */
-static const u8 wme_fifo2ac[] = { AC_BK, AC_BE, AC_VI, AC_VO, AC_BE, AC_BE };
+static const u8 wme_fifo2ac[] = {
+       IEEE80211_AC_BK,
+       IEEE80211_AC_BE,
+       IEEE80211_AC_VI,
+       IEEE80211_AC_VO,
+       IEEE80211_AC_BE,
+       IEEE80211_AC_BE
+};
 
-/* WME/802.1E Access Category to TX FIFO number */
-static const u8 wme_ac2fifo[] = { 1, 0, 2, 3 };
+/* ieee80211 Access Category to TX FIFO number */
+static const u8 wme_ac2fifo[] = {
+       TX_AC_VO_FIFO,
+       TX_AC_VI_FIFO,
+       TX_AC_BE_FIFO,
+       TX_AC_BK_FIFO
+};
 
 /* 802.1D Priority to precedence queue mapping */
 const u8 wlc_prio2prec_map[] = {
@@ -405,13 +342,6 @@ static const u16 xmtfifo_sz[][NFIFO] = {
        {9, 58, 22, 14, 14, 5},
 };
 
-static const u8 acbitmap2maxprio[] = {
-       PRIO_8021D_BE, PRIO_8021D_BE, PRIO_8021D_BK, PRIO_8021D_BK,
-       PRIO_8021D_VI, PRIO_8021D_VI, PRIO_8021D_VI, PRIO_8021D_VI,
-       PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO,
-       PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO
-};
-
 #ifdef BCMDBG
 static const char * const fifo_names[] = {
        "AC_BK", "AC_BE", "AC_VI", "AC_VO", "BCMC", "ATIM" };
@@ -424,6 +354,22 @@ static const char fifo_names[6][0];
 static struct brcms_c_info *wlc_info_dbg = (struct brcms_c_info *) (NULL);
 #endif
 
+/* Find basic rate for a given rate */
+static u8 brcms_basic_rate(struct brcms_c_info *wlc, u32 rspec)
+{
+       if (is_mcs_rate(rspec))
+               return wlc->band->basic_rate[mcs_table[rspec & RSPEC_RATE_MASK]
+                      .leg_ofdm];
+       return wlc->band->basic_rate[rspec & RSPEC_RATE_MASK];
+}
+
+static u16 frametype(u32 rspec, u8 mimoframe)
+{
+       if (is_mcs_rate(rspec))
+               return mimoframe;
+       return is_cck_rate(rspec) ? FT_CCK : FT_OFDM;
+}
+
 /* currently the best mechanism for determining SIFS is the band in use */
 static u16 get_sifs(struct brcms_band *band)
 {
@@ -470,20 +416,6 @@ static int brcms_chspec_bw(u16 chanspec)
        return BRCMS_10_MHZ;
 }
 
-/*
- * return true if Minimum Power Consumption should
- * be entered, false otherwise
- */
-static bool brcms_c_is_non_delay_mpc(struct brcms_c_info *wlc)
-{
-       return false;
-}
-
-static bool brcms_c_ismpc(struct brcms_c_info *wlc)
-{
-       return (wlc->mpc_delay_off == 0) && (brcms_c_is_non_delay_mpc(wlc));
-}
-
 static void brcms_c_bsscfg_mfree(struct brcms_bss_cfg *cfg)
 {
        if (cfg == NULL)
@@ -669,9 +601,8 @@ static void brcms_b_update_slot_timing(struct brcms_hardware *wlc_hw,
  * calculate frame duration of a given rate and length, return
  * time in usec unit
  */
-uint
-brcms_c_calc_frame_time(struct brcms_c_info *wlc, u32 ratespec,
-                       u8 preamble_type, uint mac_len)
+static uint brcms_c_calc_frame_time(struct brcms_c_info *wlc, u32 ratespec,
+                                   u8 preamble_type, uint mac_len)
 {
        uint nsyms, dur = 0, Ndps, kNdps;
        uint rate = rspec2rate(ratespec);
@@ -969,7 +900,7 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs)
                    lfbl,       /* Long Frame Rate Fallback Limit */
                    fbl;
 
-               if (queue < AC_COUNT) {
+               if (queue < IEEE80211_NUM_ACS) {
                        sfbl = GFIELD(wlc->wme_retries[wme_fifo2ac[queue]],
                                      EDCF_SFB);
                        lfbl = GFIELD(wlc->wme_retries[wme_fifo2ac[queue]],
@@ -1018,7 +949,7 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs)
                        tx_info->flags |= IEEE80211_TX_STAT_ACK;
        }
 
-       totlen = brcmu_pkttotlen(p);
+       totlen = p->len;
        free_pdu = true;
 
        brcms_c_txfifo_complete(wlc, queue, 1);
@@ -2352,13 +2283,6 @@ void brcms_b_antsel_type_set(struct brcms_hardware *wlc_hw, u8 antsel_type)
        wlc_phy_antsel_type_set(wlc_hw->band->pi, antsel_type);
 }
 
-static void brcms_c_fatal_error(struct brcms_c_info *wlc)
-{
-       wiphy_err(wlc->wiphy, "wl%d: fatal error, reinitializing\n",
-                 wlc->pub->unit);
-       brcms_init(wlc->wl);
-}
-
 static void brcms_b_fifoerrors(struct brcms_hardware *wlc_hw)
 {
        bool fatal = false;
@@ -2414,7 +2338,7 @@ static void brcms_b_fifoerrors(struct brcms_hardware *wlc_hw)
                }
 
                if (fatal) {
-                       brcms_c_fatal_error(wlc_hw->wlc);       /* big hammer */
+                       brcms_fatal_error(wlc_hw->wlc->wl); /* big hammer */
                        break;
                } else
                        W_REG(&regs->intctrlregs[idx].intstatus,
@@ -2479,6 +2403,7 @@ void brcms_c_intrsrestore(struct brcms_c_info *wlc, u32 macintmask)
        W_REG(&wlc_hw->regs->macintmask, wlc->macintmask);
 }
 
+/* assumes that the d11 MAC is enabled */
 static void brcms_b_tx_fifo_suspend(struct brcms_hardware *wlc_hw,
                                    uint tx_fifo)
 {
@@ -2535,11 +2460,12 @@ static void brcms_b_tx_fifo_resume(struct brcms_hardware *wlc_hw,
        }
 }
 
-static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool on, u32 flags)
+/* precondition: requires the mac core to be enabled */
+static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool mute_tx)
 {
        static const u8 null_ether_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
 
-       if (on) {
+       if (mute_tx) {
                /* suspend tx fifos */
                brcms_b_tx_fifo_suspend(wlc_hw, TX_DATA_FIFO);
                brcms_b_tx_fifo_suspend(wlc_hw, TX_CTL_FIFO);
@@ -2561,14 +2487,20 @@ static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool on, u32 flags)
                                       wlc_hw->etheraddr);
        }
 
-       wlc_phy_mute_upd(wlc_hw->band->pi, on, flags);
+       wlc_phy_mute_upd(wlc_hw->band->pi, mute_tx, 0);
 
-       if (on)
+       if (mute_tx)
                brcms_c_ucode_mute_override_set(wlc_hw);
        else
                brcms_c_ucode_mute_override_clear(wlc_hw);
 }
 
+void
+brcms_c_mute(struct brcms_c_info *wlc, bool mute_tx)
+{
+       brcms_b_mute(wlc->hw, mute_tx);
+}
+
 /*
  * Read and clear macintmask and macintstatus and intstatus registers.
  * This routine should be called with interrupts off
@@ -3437,8 +3369,7 @@ static void brcms_b_coreinit(struct brcms_c_info *wlc)
 }
 
 void
-static brcms_b_init(struct brcms_hardware *wlc_hw, u16 chanspec,
-                         bool mute) {
+static brcms_b_init(struct brcms_hardware *wlc_hw, u16 chanspec) {
        u32 macintmask;
        bool fastclk;
        struct brcms_c_info *wlc = wlc_hw->wlc;
@@ -3463,10 +3394,6 @@ static brcms_b_init(struct brcms_hardware *wlc_hw, u16 chanspec,
        /* core-specific initialization */
        brcms_b_coreinit(wlc);
 
-       /* suspend the tx fifos and mute the phy for preism cac time */
-       if (mute)
-               brcms_b_mute(wlc_hw, ON, PHY_MUTE_FOR_PREISM);
-
        /* band-specific inits */
        brcms_b_bsinit(wlc, chanspec);
 
@@ -3656,42 +3583,30 @@ static void brcms_c_bandinit_ordered(struct brcms_c_info *wlc,
        brcms_c_set_phy_chanspec(wlc, chanspec);
 }
 
-static void brcms_c_mac_bcn_promisc(struct brcms_c_info *wlc)
-{
-       if (wlc->bcnmisc_monitor)
-               brcms_b_mctrl(wlc->hw, MCTL_BCNS_PROMISC, MCTL_BCNS_PROMISC);
-       else
-               brcms_b_mctrl(wlc->hw, MCTL_BCNS_PROMISC, 0);
-}
-
-void brcms_c_mac_bcn_promisc_change(struct brcms_c_info *wlc, bool promisc)
-{
-       wlc->bcnmisc_monitor = promisc;
-       brcms_c_mac_bcn_promisc(wlc);
-}
-
-/* set or clear maccontrol bits MCTL_PROMISC and MCTL_KEEPCONTROL */
+/*
+ * Set or clear maccontrol bits MCTL_PROMISC, MCTL_BCNS_PROMISC and
+ * MCTL_KEEPCONTROL
+ */
 static void brcms_c_mac_promisc(struct brcms_c_info *wlc)
 {
        u32 promisc_bits = 0;
 
-       /*
-        * promiscuous mode just sets MCTL_PROMISC
-        * Note: APs get all BSS traffic without the need to set
-        * the MCTL_PROMISC bit since all BSS data traffic is
-        * directed at the AP
-        */
-       if (wlc->pub->promisc)
-               promisc_bits |= MCTL_PROMISC;
+       if (wlc->bcnmisc_monitor)
+               promisc_bits |= MCTL_BCNS_PROMISC;
 
-       /* monitor mode needs both MCTL_PROMISC and MCTL_KEEPCONTROL
-        * Note: monitor mode also needs MCTL_BCNS_PROMISC, but that is
-        * handled in brcms_c_mac_bcn_promisc()
-        */
        if (wlc->monitor)
-               promisc_bits |= MCTL_PROMISC | MCTL_KEEPCONTROL;
+               promisc_bits |=
+                       MCTL_PROMISC | MCTL_BCNS_PROMISC | MCTL_KEEPCONTROL;
 
-       brcms_b_mctrl(wlc->hw, MCTL_PROMISC | MCTL_KEEPCONTROL, promisc_bits);
+       brcms_b_mctrl(wlc->hw,
+                       MCTL_PROMISC | MCTL_BCNS_PROMISC | MCTL_KEEPCONTROL,
+                       promisc_bits);
+}
+
+void brcms_c_mac_bcn_promisc_change(struct brcms_c_info *wlc, bool promisc)
+{
+       wlc->bcnmisc_monitor = promisc;
+       brcms_c_mac_promisc(wlc);
 }
 
 /*
@@ -3723,7 +3638,6 @@ static void brcms_c_ucode_mac_upd(struct brcms_c_info *wlc)
        }
 
        /* update the various promisc bits */
-       brcms_c_mac_bcn_promisc(wlc);
        brcms_c_mac_promisc(wlc);
 }
 
@@ -3979,7 +3893,7 @@ static void brcms_c_set_home_chanspec(struct brcms_c_info *wlc, u16 chanspec)
 
 void
 brcms_b_set_chanspec(struct brcms_hardware *wlc_hw, u16 chanspec,
-                     bool mute, struct txpwr_limits *txpwr)
+                     bool mute_tx, struct txpwr_limits *txpwr)
 {
        uint bandunit;
 
@@ -4005,7 +3919,7 @@ brcms_b_set_chanspec(struct brcms_hardware *wlc_hw, u16 chanspec,
                }
        }
 
-       wlc_phy_initcal_enable(wlc_hw->band->pi, !mute);
+       wlc_phy_initcal_enable(wlc_hw->band->pi, !mute_tx);
 
        if (!wlc_hw->up) {
                if (wlc_hw->clk)
@@ -4017,7 +3931,7 @@ brcms_b_set_chanspec(struct brcms_hardware *wlc_hw, u16 chanspec,
                wlc_phy_txpower_limit_set(wlc_hw->band->pi, txpwr, chanspec);
 
                /* Update muting of the channel */
-               brcms_b_mute(wlc_hw, mute, 0);
+               brcms_b_mute(wlc_hw, mute_tx);
        }
 }
 
@@ -4205,7 +4119,7 @@ void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci,
            EDCF_TXOP2USEC(acp_shm.txop);
        acp_shm.aifs = (params->aifs & EDCF_AIFSN_MASK);
 
-       if (aci == AC_VI && acp_shm.txop == 0
+       if (aci == IEEE80211_AC_VI && acp_shm.txop == 0
            && acp_shm.aifs < EDCF_AIFSN_MAX)
                acp_shm.aifs++;
 
@@ -4242,7 +4156,7 @@ void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci,
        }
 }
 
-void brcms_c_edcf_setparams(struct brcms_c_info *wlc, bool suspend)
+static void brcms_c_edcf_setparams(struct brcms_c_info *wlc, bool suspend)
 {
        u16 aci;
        int i_ac;
@@ -4255,7 +4169,7 @@ void brcms_c_edcf_setparams(struct brcms_c_info *wlc, bool suspend)
        }; /* ucode needs these parameters during its initialization */
        const struct edcf_acparam *edcf_acp = &default_edcf_acparams[0];
 
-       for (i_ac = 0; i_ac < AC_COUNT; i_ac++, edcf_acp++) {
+       for (i_ac = 0; i_ac < IEEE80211_NUM_ACS; i_ac++, edcf_acp++) {
                /* find out which ac this set of params applies to */
                aci = (edcf_acp->ACI & EDCF_ACI_MASK) >> EDCF_ACI_SHIFT;
 
@@ -4277,17 +4191,6 @@ void brcms_c_edcf_setparams(struct brcms_c_info *wlc, bool suspend)
        }
 }
 
-/* maintain LED behavior in down state */
-static void brcms_c_down_led_upd(struct brcms_c_info *wlc)
-{
-       /*
-        * maintain LEDs while in down state, turn on sbclk if
-        * not available yet. Turn on sbclk if necessary
-        */
-       brcms_b_pllreq(wlc->hw, true, BRCMS_PLLREQ_FLIP);
-       brcms_b_pllreq(wlc->hw, false, BRCMS_PLLREQ_FLIP);
-}
-
 static void brcms_c_radio_monitor_start(struct brcms_c_info *wlc)
 {
        /* Don't start the timer if HWRADIO feature is disabled */
@@ -4299,28 +4202,6 @@ static void brcms_c_radio_monitor_start(struct brcms_c_info *wlc)
        brcms_add_timer(wlc->radio_timer, TIMER_INTERVAL_RADIOCHK, true);
 }
 
-static void brcms_c_radio_disable(struct brcms_c_info *wlc)
-{
-       if (!wlc->pub->up) {
-               brcms_c_down_led_upd(wlc);
-               return;
-       }
-
-       brcms_c_radio_monitor_start(wlc);
-       brcms_down(wlc->wl);
-}
-
-static void brcms_c_radio_enable(struct brcms_c_info *wlc)
-{
-       if (wlc->pub->up)
-               return;
-
-       if (brcms_deviceremoved(wlc))
-               return;
-
-       brcms_up(wlc->wl);
-}
-
 static bool brcms_c_radio_monitor_stop(struct brcms_c_info *wlc)
 {
        if (!wlc->radio_monitor)
@@ -4343,18 +4224,6 @@ static void brcms_c_radio_hwdisable_upd(struct brcms_c_info *wlc)
                mboolclr(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE);
 }
 
-/*
- * centralized radio disable/enable function,
- * invoke radio enable/disable after updating hwradio status
- */
-static void brcms_c_radio_upd(struct brcms_c_info *wlc)
-{
-       if (wlc->pub->radio_disabled)
-               brcms_c_radio_disable(wlc);
-       else
-               brcms_c_radio_enable(wlc);
-}
-
 /* update hwradio status and return it */
 bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc)
 {
@@ -4376,12 +4245,7 @@ static void brcms_c_radio_timer(void *arg)
                return;
        }
 
-       /* cap mpc off count */
-       if (wlc->mpc_offcnt < BRCMS_MPC_MAX_DELAYCNT)
-               wlc->mpc_offcnt++;
-
        brcms_c_radio_hwdisable_upd(wlc);
-       brcms_c_radio_upd(wlc);
 }
 
 /* common low-level watchdog code */
@@ -4407,60 +4271,6 @@ static void brcms_b_watchdog(void *arg)
        wlc_phy_watchdog(wlc_hw->band->pi);
 }
 
-static void brcms_c_radio_mpc_upd(struct brcms_c_info *wlc)
-{
-       bool mpc_radio, radio_state;
-
-       /*
-        * Clear the WL_RADIO_MPC_DISABLE bit when mpc feature is disabled
-        * in case the WL_RADIO_MPC_DISABLE bit was set. Stop the radio
-        * monitor also when WL_RADIO_MPC_DISABLE is the only reason that
-        * the radio is going down.
-        */
-       if (!wlc->mpc) {
-               if (!wlc->pub->radio_disabled)
-                       return;
-               mboolclr(wlc->pub->radio_disabled, WL_RADIO_MPC_DISABLE);
-               brcms_c_radio_upd(wlc);
-               if (!wlc->pub->radio_disabled)
-                       brcms_c_radio_monitor_stop(wlc);
-               return;
-       }
-
-       /*
-        * sync ismpc logic with WL_RADIO_MPC_DISABLE bit in
-        * wlc->pub->radio_disabled to go ON, always call radio_upd
-        * synchronously to go OFF, postpone radio_upd to later when
-        * context is safe(e.g. watchdog)
-        */
-       radio_state =
-           (mboolisset(wlc->pub->radio_disabled, WL_RADIO_MPC_DISABLE) ? OFF :
-            ON);
-       mpc_radio = (brcms_c_ismpc(wlc) == true) ? OFF : ON;
-
-       if (radio_state == ON && mpc_radio == OFF)
-               wlc->mpc_delay_off = wlc->mpc_dlycnt;
-       else if (radio_state == OFF && mpc_radio == ON) {
-               mboolclr(wlc->pub->radio_disabled, WL_RADIO_MPC_DISABLE);
-               brcms_c_radio_upd(wlc);
-               if (wlc->mpc_offcnt < BRCMS_MPC_THRESHOLD)
-                       wlc->mpc_dlycnt = BRCMS_MPC_MAX_DELAYCNT;
-               else
-                       wlc->mpc_dlycnt = BRCMS_MPC_MIN_DELAYCNT;
-       }
-       /*
-        * Below logic is meant to capture the transition from mpc off
-        * to mpc on for reasons other than wlc->mpc_delay_off keeping
-        * the mpc off. In that case reset wlc->mpc_delay_off to
-        * wlc->mpc_dlycnt, so that we restart the countdown of mpc_delay_off
-        */
-       if ((wlc->prev_non_delay_mpc == false) &&
-           (brcms_c_is_non_delay_mpc(wlc) == true) && wlc->mpc_delay_off)
-               wlc->mpc_delay_off = wlc->mpc_dlycnt;
-
-       wlc->prev_non_delay_mpc = brcms_c_is_non_delay_mpc(wlc);
-}
-
 /* common watchdog code */
 static void brcms_c_watchdog(void *arg)
 {
@@ -4481,21 +4291,7 @@ static void brcms_c_watchdog(void *arg)
        /* increment second count */
        wlc->pub->now++;
 
-       /* delay radio disable */
-       if (wlc->mpc_delay_off) {
-               if (--wlc->mpc_delay_off == 0) {
-                       mboolset(wlc->pub->radio_disabled,
-                                WL_RADIO_MPC_DISABLE);
-                       if (wlc->mpc && brcms_c_ismpc(wlc))
-                               wlc->mpc_offcnt = 0;
-               }
-       }
-
-       /* mpc sync */
-       brcms_c_radio_mpc_upd(wlc);
-       /* radio sync: sw/hw/mpc --> radio_disable/radio_enable */
        brcms_c_radio_hwdisable_upd(wlc);
-       brcms_c_radio_upd(wlc);
        /* if radio is disable, driver may be down, quit here */
        if (wlc->pub->radio_disabled)
                return;
@@ -4599,9 +4395,6 @@ static void brcms_c_info_init(struct brcms_c_info *wlc, int unit)
        /* WME QoS mode is Auto by default */
        wlc->pub->_ampdu = AMPDU_AGG_HOST;
        wlc->pub->bcmerror = 0;
-
-       /* initialize mpc delay */
-       wlc->mpc_delay_off = wlc->mpc_dlycnt = BRCMS_MPC_MIN_DELAYCNT;
 }
 
 static uint brcms_c_attach_module(struct brcms_c_info *wlc)
@@ -5259,9 +5052,6 @@ static void brcms_c_ap_upd(struct brcms_c_info *wlc)
 {
        /* STA-BSS; short capable */
        wlc->PLCPHdr_override = BRCMS_PLCP_SHORT;
-
-       /* fixup mpc */
-       wlc->mpc = true;
 }
 
 /* Initialize just the hardware when coming out of POR or S3/S5 system states */
@@ -5376,7 +5166,7 @@ static void brcms_c_wme_retries_write(struct brcms_c_info *wlc)
        if (!wlc->clk)
                return;
 
-       for (ac = 0; ac < AC_COUNT; ac++)
+       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
                brcms_b_write_shm(wlc->hw, M_AC_TXLMT_ADDR(ac),
                                  wlc->wme_retries[ac]);
 }
@@ -5575,7 +5365,6 @@ uint brcms_c_down(struct brcms_c_info *wlc)
        if (!wlc->pub->up)
                return callbacks;
 
-       /* in between, mpc could try to bring down again.. */
        wlc->going_down = true;
 
        callbacks += brcms_b_bmac_down_prep(wlc->hw);
@@ -5852,7 +5641,7 @@ int brcms_c_set_rate_limit(struct brcms_c_info *wlc, u16 srl, u16 lrl)
 
        brcms_b_retrylimit_upd(wlc->hw, wlc->SRL, wlc->LRL);
 
-       for (ac = 0; ac < AC_COUNT; ac++) {
+       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
                wlc->wme_retries[ac] =  SFIELD(wlc->wme_retries[ac],
                                               EDCF_SHORT,  wlc->SRL);
                wlc->wme_retries[ac] =  SFIELD(wlc->wme_retries[ac],
@@ -6103,7 +5892,6 @@ void brcms_c_print_txdesc(struct d11txh *txh)
 
        u8 *rtsph = txh->RTSPhyHeader;
        struct ieee80211_rts rts = txh->rts_frame;
-       char hexbuf[256];
 
        /* add plcp header along with txh descriptor */
        printk(KERN_DEBUG "Raw TxDesc + plcp header:\n");
@@ -6124,17 +5912,16 @@ void brcms_c_print_txdesc(struct d11txh *txh)
        printk(KERN_DEBUG "XtraFrameTypes: %04x ", xtraft);
        printk(KERN_DEBUG "\n");
 
-       brcmu_format_hex(hexbuf, iv, sizeof(txh->IV));
-       printk(KERN_DEBUG "SecIV:       %s\n", hexbuf);
-       brcmu_format_hex(hexbuf, ra, sizeof(txh->TxFrameRA));
-       printk(KERN_DEBUG "RA:          %s\n", hexbuf);
+       print_hex_dump_bytes("SecIV:", DUMP_PREFIX_OFFSET, iv, sizeof(txh->IV));
+       print_hex_dump_bytes("RA:", DUMP_PREFIX_OFFSET,
+                            ra, sizeof(txh->TxFrameRA));
 
        printk(KERN_DEBUG "Fb FES Time: %04x ", tfestfb);
-       brcmu_format_hex(hexbuf, rtspfb, sizeof(txh->RTSPLCPFallback));
-       printk(KERN_DEBUG "RTS PLCP: %s ", hexbuf);
+       print_hex_dump_bytes("Fb RTS PLCP:", DUMP_PREFIX_OFFSET,
+                            rtspfb, sizeof(txh->RTSPLCPFallback));
        printk(KERN_DEBUG "RTS DUR: %04x ", rtsdfb);
-       brcmu_format_hex(hexbuf, fragpfb, sizeof(txh->FragPLCPFallback));
-       printk(KERN_DEBUG "PLCP: %s ", hexbuf);
+       print_hex_dump_bytes("PLCP:", DUMP_PREFIX_OFFSET,
+                            fragpfb, sizeof(txh->FragPLCPFallback));
        printk(KERN_DEBUG "DUR: %04x", fragdfb);
        printk(KERN_DEBUG "\n");
 
@@ -6149,18 +5936,18 @@ void brcms_c_print_txdesc(struct d11txh *txh)
        printk(KERN_DEBUG "MaxAggbyte_fb:  %04x\n", mabyte_f);
        printk(KERN_DEBUG "MinByte:     %04x\n", mmbyte);
 
-       brcmu_format_hex(hexbuf, rtsph, sizeof(txh->RTSPhyHeader));
-       printk(KERN_DEBUG "RTS PLCP: %s ", hexbuf);
-       brcmu_format_hex(hexbuf, (u8 *) &rts, sizeof(txh->rts_frame));
-       printk(KERN_DEBUG "RTS Frame: %s", hexbuf);
+       print_hex_dump_bytes("RTS PLCP:", DUMP_PREFIX_OFFSET,
+                            rtsph, sizeof(txh->RTSPhyHeader));
+       print_hex_dump_bytes("RTS Frame:", DUMP_PREFIX_OFFSET,
+                            (u8 *)&rts, sizeof(txh->rts_frame));
        printk(KERN_DEBUG "\n");
 }
 #endif                         /* defined(BCMDBG) */
 
 #if defined(BCMDBG)
-int
+static int
 brcms_c_format_flags(const struct brcms_c_bit_desc *bd, u32 flags, char *buf,
-                  int len)
+                    int len)
 {
        int i;
        char *p = buf;
@@ -6916,7 +6703,7 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
        qos = ieee80211_is_data_qos(h->frame_control);
 
        /* compute length of frame in bytes for use in PLCP computations */
-       len = brcmu_pkttotlen(p);
+       len = p->len;
        phylen = len + FCS_LEN;
 
        /* Get tx_info */
@@ -8253,12 +8040,6 @@ int brcms_c_get_tx_power(struct brcms_c_info *wlc)
        return (int)(qdbm / BRCMS_TXPWR_DB_FACTOR);
 }
 
-void brcms_c_set_radio_mpc(struct brcms_c_info *wlc, bool mpc)
-{
-       wlc->mpc = mpc;
-       brcms_c_radio_mpc_upd(wlc);
-}
-
 /* Process received frames */
 /*
  * Return true if more frames need to be processed. false otherwise.
@@ -8328,21 +8109,17 @@ static bool
 brcms_b_recv(struct brcms_hardware *wlc_hw, uint fifo, bool bound)
 {
        struct sk_buff *p;
-       struct sk_buff *head = NULL;
-       struct sk_buff *tail = NULL;
+       struct sk_buff *next = NULL;
+       struct sk_buff_head recv_frames;
+
        uint n = 0;
        uint bound_limit = bound ? RXBND : -1;
 
        BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
-       /* gather received frames */
-       while ((p = dma_rx(wlc_hw->di[fifo]))) {
+       skb_queue_head_init(&recv_frames);
 
-               if (!tail)
-                       head = tail = p;
-               else {
-                       tail->prev = p;
-                       tail = p;
-               }
+       /* gather received frames */
+       while (dma_rx(wlc_hw->di[fifo], &recv_frames)) {
 
                /* !give others some time to run! */
                if (++n >= bound_limit)
@@ -8353,12 +8130,11 @@ brcms_b_recv(struct brcms_hardware *wlc_hw, uint fifo, bool bound)
        dma_rxfill(wlc_hw->di[fifo]);
 
        /* process each frame */
-       while ((p = head) != NULL) {
+       skb_queue_walk_safe(&recv_frames, p, next) {
                struct d11rxhdr_le *rxh_le;
                struct d11rxhdr *rxh;
-               head = head->prev;
-               p->prev = NULL;
 
+               skb_unlink(p, &recv_frames);
                rxh_le = (struct d11rxhdr_le *)p->data;
                rxh = (struct d11rxhdr *)p->data;
 
@@ -8448,8 +8224,7 @@ bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded)
                printk_once("%s : PSM Watchdog, chipid 0x%x, chiprev 0x%x\n",
                                        __func__, wlc_hw->sih->chip,
                                        wlc_hw->sih->chiprev);
-               /* big hammer */
-               brcms_init(wlc->wl);
+               brcms_fatal_error(wlc_hw->wlc->wl);
        }
 
        /* gptimer timeout */
@@ -8470,15 +8245,14 @@ bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded)
        return wlc->macintstatus != 0;
 
  fatal:
-       brcms_init(wlc->wl);
+       brcms_fatal_error(wlc_hw->wlc->wl);
        return wlc->macintstatus != 0;
 }
 
-void brcms_c_init(struct brcms_c_info *wlc)
+void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx)
 {
        struct d11regs __iomem *regs;
        u16 chanspec;
-       bool mute = false;
 
        BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
 
@@ -8494,7 +8268,7 @@ void brcms_c_init(struct brcms_c_info *wlc)
        else
                chanspec = brcms_c_init_chanspec(wlc);
 
-       brcms_b_init(wlc->hw, chanspec, mute);
+       brcms_b_init(wlc->hw, chanspec);
 
        /* update beacon listen interval */
        brcms_c_bcn_li_upd(wlc);
@@ -8560,15 +8334,16 @@ void brcms_c_init(struct brcms_c_info *wlc)
        /* ..now really unleash hell (allow the MAC out of suspend) */
        brcms_c_enable_mac(wlc);
 
+       /* suspend the tx fifos and mute the phy for preism cac time */
+       if (mute_tx)
+               brcms_b_mute(wlc->hw, true);
+
        /* clear tx flow control */
        brcms_c_txflowcontrol_reset(wlc);
 
        /* enable the RF Disable Delay timer */
        W_REG(&wlc->regs->rfdisabledly, RFDISABLE_DEFAULT);
 
-       /* initialize mpc delay */
-       wlc->mpc_delay_off = wlc->mpc_dlycnt = BRCMS_MPC_MIN_DELAYCNT;
-
        /*
         * Initialize WME parameters; if they haven't been set by some other
         * mechanism (IOVar, etc) then read them from the hardware.
@@ -8577,7 +8352,7 @@ void brcms_c_init(struct brcms_c_info *wlc)
                /* Uninitialized; read from HW */
                int ac;
 
-               for (ac = 0; ac < AC_COUNT; ac++)
+               for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
                        wlc->wme_retries[ac] =
                            brcms_b_read_shm(wlc->hw, M_AC_TXLMT_ADDR(ac));
        }
@@ -8754,8 +8529,6 @@ brcms_c_attach(struct brcms_info *wl, u16 vendor, u16 device, uint unit,
                brcms_c_ht_update_sgi_rx(wlc, 0);
        }
 
-       /* initialize radio_mpc_disable according to wlc->mpc */
-       brcms_c_radio_mpc_upd(wlc);
        brcms_b_antsel_set(wlc->hw, wlc->asi->antsel_avail);
 
        if (perr)
index c0e0fcf..251c350 100644 (file)
@@ -44,8 +44,6 @@
 /* transmit buffer max headroom for protocol headers */
 #define TXOFF (D11_TXH_LEN + D11_PHY_HDR_LEN)
 
-#define AC_COUNT               4
-
 /* Macros for doing definition and get/set of bitfields
  * Usage example, e.g. a three-bit field (bits 4-6):
  *    #define <NAME>_M BITFIELD_MASK(3)
@@ -427,11 +425,6 @@ struct brcms_txq_info {
  * bandinit_pending: track band init in auto band.
  * radio_monitor: radio timer is running.
  * going_down: down path intermediate variable.
- * mpc: enable minimum power consumption.
- * mpc_dlycnt: # of watchdog cnt before turn disable radio.
- * mpc_offcnt: # of watchdog cnt that radio is disabled.
- * mpc_delay_off: delay radio disable by # of watchdog cnt.
- * prev_non_delay_mpc: prev state brcms_c_is_non_delay_mpc.
  * wdtimer: timer for watchdog routine.
  * radio_timer: timer for hw radio button monitor routine.
  * monitor: monitor (MPDU sniffing) mode.
@@ -441,7 +434,7 @@ struct brcms_txq_info {
  * bcn_li_dtim: beacon listen interval in # dtims.
  * WDarmed: watchdog timer is armed.
  * WDlast: last time wlc_watchdog() was called.
- * edcf_txop[AC_COUNT]: current txop for each ac.
+ * edcf_txop[IEEE80211_NUM_ACS]: current txop for each ac.
  * wme_retries: per-AC retry limits.
  * tx_prec_map: Precedence map based on HW FIFO space.
  * fifo2prec_map[NFIFO]: pointer to fifo2_prec map based on WME.
@@ -522,12 +515,6 @@ struct brcms_c_info {
        bool radio_monitor;
        bool going_down;
 
-       bool mpc;
-       u8 mpc_dlycnt;
-       u8 mpc_offcnt;
-       u8 mpc_delay_off;
-       u8 prev_non_delay_mpc;
-
        struct brcms_timer *wdtimer;
        struct brcms_timer *radio_timer;
 
@@ -546,9 +533,9 @@ struct brcms_c_info {
        u32 WDlast;
 
        /* WME */
-       u16 edcf_txop[AC_COUNT];
+       u16 edcf_txop[IEEE80211_NUM_ACS];
 
-       u16 wme_retries[AC_COUNT];
+       u16 wme_retries[IEEE80211_NUM_ACS];
        u16 tx_prec_map;
        u16 fifo2prec_map[NFIFO];
 
index a314925..e17edf7 100644 (file)
@@ -112,7 +112,7 @@ static const struct chan_info_basic chan_info_all[] = {
        {216, 50800}
 };
 
-const u8 ofdm_rate_lookup[] = {
+static const u8 ofdm_rate_lookup[] = {
 
        BRCM_RATE_48M,
        BRCM_RATE_24M,
@@ -190,15 +190,7 @@ u16 read_radio_reg(struct brcms_phy *pi, u16 addr)
                data = R_REG(&pi->regs->radioregdata);
        } else {
                W_REG_FLUSH(&pi->regs->phy4waddr, addr);
-
-#ifdef __ARM_ARCH_4T__
-               __asm__(" .align 4 ");
-               __asm__(" nop ");
-               data = R_REG(&pi->regs->phy4wdatalo);
-#else
                data = R_REG(&pi->regs->phy4wdatalo);
-#endif
-
        }
        pi->phy_wreg = 0;
 
index bea8524..5f9478b 100644 (file)
@@ -774,11 +774,6 @@ struct brcms_phy {
        s16 nphy_noise_win[PHY_CORE_MAX][PHY_NOISE_WINDOW_SZ];
        u8 nphy_noise_index;
 
-       u8 nphy_txpid2g[PHY_CORE_NUM_2];
-       u8 nphy_txpid5g[PHY_CORE_NUM_2];
-       u8 nphy_txpid5gl[PHY_CORE_NUM_2];
-       u8 nphy_txpid5gh[PHY_CORE_NUM_2];
-
        bool nphy_gain_boost;
        bool nphy_elna_gain_config;
        u16 old_bphy_test;
index cd19c2f..ec9b566 100644 (file)
@@ -29,6 +29,7 @@
 #include "phy_radio.h"
 #include "phyreg_n.h"
 #include "phytbl_n.h"
+#include "soc.h"
 
 #define READ_RADIO_REG2(pi, radio_type, jspace, core, reg_name)        \
        read_radio_reg(pi, radio_type##_##jspace##_##reg_name | \
@@ -14417,12 +14418,6 @@ static void wlc_phy_txpwr_srom_read_ppr_nphy(struct brcms_phy *pi)
                switch (band_num) {
                case 0:
 
-                       pi->nphy_txpid2g[PHY_CORE_0] =
-                               (u8) wlapi_getintvar(shim,
-                                                    BRCMS_SROM_TXPID2GA0);
-                       pi->nphy_txpid2g[PHY_CORE_1] =
-                               (u8) wlapi_getintvar(shim,
-                                                    BRCMS_SROM_TXPID2GA1);
                        pi->nphy_pwrctrl_info[PHY_CORE_0].max_pwr_2g =
                                (s8) wlapi_getintvar(shim,
                                                     BRCMS_SROM_MAXP2GA0);
@@ -14486,12 +14481,6 @@ static void wlc_phy_txpwr_srom_read_ppr_nphy(struct brcms_phy *pi)
                        break;
                case 1:
 
-                       pi->nphy_txpid5g[PHY_CORE_0] =
-                               (u8) wlapi_getintvar(shim,
-                                                    BRCMS_SROM_TXPID5GA0);
-                       pi->nphy_txpid5g[PHY_CORE_1] =
-                               (u8) wlapi_getintvar(shim,
-                                                    BRCMS_SROM_TXPID5GA1);
                        pi->nphy_pwrctrl_info[PHY_CORE_0].max_pwr_5gm =
                                (s8) wlapi_getintvar(shim, BRCMS_SROM_MAXP5GA0);
                        pi->nphy_pwrctrl_info[PHY_CORE_1].max_pwr_5gm =
@@ -14551,12 +14540,6 @@ static void wlc_phy_txpwr_srom_read_ppr_nphy(struct brcms_phy *pi)
                        break;
                case 2:
 
-                       pi->nphy_txpid5gl[0] =
-                               (u8) wlapi_getintvar(shim,
-                                                    BRCMS_SROM_TXPID5GLA0);
-                       pi->nphy_txpid5gl[1] =
-                               (u8) wlapi_getintvar(shim,
-                                                    BRCMS_SROM_TXPID5GLA1);
                        pi->nphy_pwrctrl_info[0].max_pwr_5gl =
                                (s8) wlapi_getintvar(shim,
                                                     BRCMS_SROM_MAXP5GLA0);
@@ -14615,12 +14598,6 @@ static void wlc_phy_txpwr_srom_read_ppr_nphy(struct brcms_phy *pi)
                        break;
                case 3:
 
-                       pi->nphy_txpid5gh[0] =
-                               (u8) wlapi_getintvar(shim,
-                                                    BRCMS_SROM_TXPID5GHA0);
-                       pi->nphy_txpid5gh[1] =
-                               (u8) wlapi_getintvar(shim,
-                                                    BRCMS_SROM_TXPID5GHA1);
                        pi->nphy_pwrctrl_info[0].max_pwr_5gh =
                                (s8) wlapi_getintvar(shim,
                                                     BRCMS_SROM_MAXP5GHA0);
@@ -27994,20 +27971,11 @@ void wlc_phy_txpwr_fixpower_nphy(struct brcms_phy *pi)
                chan_freq_range = wlc_phy_get_chan_freq_range_nphy(pi, 0);
                switch (chan_freq_range) {
                case WL_CHAN_FREQ_RANGE_2G:
-                       txpi[0] = pi->nphy_txpid2g[0];
-                       txpi[1] = pi->nphy_txpid2g[1];
-                       break;
                case WL_CHAN_FREQ_RANGE_5GL:
-                       txpi[0] = pi->nphy_txpid5gl[0];
-                       txpi[1] = pi->nphy_txpid5gl[1];
-                       break;
                case WL_CHAN_FREQ_RANGE_5GM:
-                       txpi[0] = pi->nphy_txpid5g[0];
-                       txpi[1] = pi->nphy_txpid5g[1];
-                       break;
                case WL_CHAN_FREQ_RANGE_5GH:
-                       txpi[0] = pi->nphy_txpid5gh[0];
-                       txpi[1] = pi->nphy_txpid5gh[1];
+                       txpi[0] = 0;
+                       txpi[1] = 0;
                        break;
                default:
                        txpi[0] = txpi[1] = 91;
index 3b36e3a..12ba575 100644 (file)
@@ -23,6 +23,7 @@
 #include "pub.h"
 #include "aiutils.h"
 #include "pmu.h"
+#include "soc.h"
 
 /*
  * external LPO crystal frequency
index 37bb2dc..21ccf3a 100644 (file)
@@ -170,22 +170,6 @@ enum brcms_srom_id {
        BRCMS_SROM_TSSIPOS2G,
        BRCMS_SROM_TSSIPOS5G,
        BRCMS_SROM_TXCHAIN,
-       BRCMS_SROM_TXPID2GA0,
-       BRCMS_SROM_TXPID2GA1,
-       BRCMS_SROM_TXPID2GA2,
-       BRCMS_SROM_TXPID2GA3,
-       BRCMS_SROM_TXPID5GA0,
-       BRCMS_SROM_TXPID5GA1,
-       BRCMS_SROM_TXPID5GA2,
-       BRCMS_SROM_TXPID5GA3,
-       BRCMS_SROM_TXPID5GHA0,
-       BRCMS_SROM_TXPID5GHA1,
-       BRCMS_SROM_TXPID5GHA2,
-       BRCMS_SROM_TXPID5GHA3,
-       BRCMS_SROM_TXPID5GLA0,
-       BRCMS_SROM_TXPID5GLA1,
-       BRCMS_SROM_TXPID5GLA2,
-       BRCMS_SROM_TXPID5GLA3,
        /*
         * per-path identifiers (see srom.c)
         */
@@ -225,10 +209,6 @@ enum brcms_srom_id {
        BRCMS_SROM_PA2GW2A1,
        BRCMS_SROM_PA2GW2A2,
        BRCMS_SROM_PA2GW2A3,
-       BRCMS_SROM_PA2GW3A0,
-       BRCMS_SROM_PA2GW3A1,
-       BRCMS_SROM_PA2GW3A2,
-       BRCMS_SROM_PA2GW3A3,
        BRCMS_SROM_PA5GHW0A0,
        BRCMS_SROM_PA5GHW0A1,
        BRCMS_SROM_PA5GHW0A2,
@@ -241,10 +221,6 @@ enum brcms_srom_id {
        BRCMS_SROM_PA5GHW2A1,
        BRCMS_SROM_PA5GHW2A2,
        BRCMS_SROM_PA5GHW2A3,
-       BRCMS_SROM_PA5GHW3A0,
-       BRCMS_SROM_PA5GHW3A1,
-       BRCMS_SROM_PA5GHW3A2,
-       BRCMS_SROM_PA5GHW3A3,
        BRCMS_SROM_PA5GLW0A0,
        BRCMS_SROM_PA5GLW0A1,
        BRCMS_SROM_PA5GLW0A2,
@@ -257,10 +233,6 @@ enum brcms_srom_id {
        BRCMS_SROM_PA5GLW2A1,
        BRCMS_SROM_PA5GLW2A2,
        BRCMS_SROM_PA5GLW2A3,
-       BRCMS_SROM_PA5GLW3A0,
-       BRCMS_SROM_PA5GLW3A1,
-       BRCMS_SROM_PA5GLW3A2,
-       BRCMS_SROM_PA5GLW3A3,
        BRCMS_SROM_PA5GW0A0,
        BRCMS_SROM_PA5GW0A1,
        BRCMS_SROM_PA5GW0A2,
@@ -273,14 +245,9 @@ enum brcms_srom_id {
        BRCMS_SROM_PA5GW2A1,
        BRCMS_SROM_PA5GW2A2,
        BRCMS_SROM_PA5GW2A3,
-       BRCMS_SROM_PA5GW3A0,
-       BRCMS_SROM_PA5GW3A1,
-       BRCMS_SROM_PA5GW3A2,
-       BRCMS_SROM_PA5GW3A3,
 };
 
 #define        BRCMS_NUMRATES  16      /* max # of rates in a rateset */
-#define        D11_PHY_HDR_LEN 6       /* Phy header length - 6 bytes */
 
 /* phy types */
 #define        PHY_TYPE_A      0       /* Phy type A */
@@ -414,7 +381,6 @@ struct brcms_pub {
        uint _nbands;           /* # bands supported */
        uint now;               /* # elapsed seconds */
 
-       bool promisc;           /* promiscuous destination address */
        bool delayed_down;      /* down delayed */
        bool associated;        /* true:part of [I]BSS, false: not */
        /* (union of stas_associated, aps_associated) */
@@ -572,7 +538,7 @@ extern int brcms_c_up(struct brcms_c_info *wlc);
 extern uint brcms_c_down(struct brcms_c_info *wlc);
 
 extern bool brcms_c_chipmatch(u16 vendor, u16 device);
-extern void brcms_c_init(struct brcms_c_info *wlc);
+extern void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx);
 extern void brcms_c_reset(struct brcms_c_info *wlc);
 
 extern void brcms_c_intrson(struct brcms_c_info *wlc);
@@ -628,7 +594,7 @@ extern void brcms_c_set_beacon_listen_interval(struct brcms_c_info *wlc,
                                        u8 interval);
 extern int brcms_c_set_tx_power(struct brcms_c_info *wlc, int txpwr);
 extern int brcms_c_get_tx_power(struct brcms_c_info *wlc);
-extern void brcms_c_set_radio_mpc(struct brcms_c_info *wlc, bool mpc);
 extern bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc);
+extern void brcms_c_mute(struct brcms_c_info *wlc, bool on);
 
 #endif                         /* _BRCM_PUB_H_ */
index e7b9dc2..980d578 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "types.h"
 #include "d11.h"
+#include "phy_hal.h"
 
 extern const u8 rate_info[];
 extern const struct brcms_c_rateset cck_ofdm_mimo_rates;
@@ -198,11 +199,9 @@ static inline u8 cck_rspec(u8 cck)
 
 /* Convert encoded rate value in plcp header to numerical rates in 500 KHz
  * increments */
-extern const u8 ofdm_rate_lookup[];
-
 static inline u8 ofdm_phy2mac_rate(u8 rlpt)
 {
-       return ofdm_rate_lookup[rlpt & 0x7];
+       return wlc_phy_get_ofdm_rate_lookup()[rlpt & 0x7];
 }
 
 static inline u8 cck_phy2mac_rate(u8 signal)
index 99f7910..b6987ea 100644 (file)
@@ -28,6 +28,7 @@
 #include "aiutils.h"
 #include "otp.h"
 #include "srom.h"
+#include "soc.h"
 
 /*
  * SROM CRC8 polynomial value:
@@ -62,9 +63,6 @@
 #define        SROM_MACHI_ET1          42
 #define        SROM_MACMID_ET1         43
 #define        SROM_MACLO_ET1          44
-#define        SROM3_MACHI             37
-#define        SROM3_MACMID            38
-#define        SROM3_MACLO             39
 
 #define        SROM_BXARSSI2G          40
 #define        SROM_BXARSSI5G          41
 
 #define        SROM_BFL                57
 #define        SROM_BFL2               28
-#define        SROM3_BFL2              61
 
 #define        SROM_AG10               58
 
 
 #define        SROM_OPO                60
 
-#define        SROM3_LEDDC             62
-
 #define        SROM_CRCREV             63
 
-/* SROM Rev 4: Reallocate the software part of the srom to accommodate
- * MIMO features. It assumes up to two PCIE functions and 440 bytes
- * of usable srom i.e. the usable storage in chips with OTP that
- * implements hardware redundancy.
- */
-
 #define        SROM4_WORDS             220
 
-#define        SROM4_SIGN              32
-#define        SROM4_SIGNATURE         0x5372
-
-#define        SROM4_BREV              33
-
-#define        SROM4_BFL0              34
-#define        SROM4_BFL1              35
-#define        SROM4_BFL2              36
-#define        SROM4_BFL3              37
-#define        SROM5_BFL0              37
-#define        SROM5_BFL1              38
-#define        SROM5_BFL2              39
-#define        SROM5_BFL3              40
-
-#define        SROM4_MACHI             38
-#define        SROM4_MACMID            39
-#define        SROM4_MACLO             40
-#define        SROM5_MACHI             41
-#define        SROM5_MACMID            42
-#define        SROM5_MACLO             43
-
-#define        SROM4_CCODE             41
-#define        SROM4_REGREV            42
-#define        SROM5_CCODE             34
-#define        SROM5_REGREV            35
-
-#define        SROM4_LEDBH10           43
-#define        SROM4_LEDBH32           44
-#define        SROM5_LEDBH10           59
-#define        SROM5_LEDBH32           60
-
-#define        SROM4_LEDDC             45
-#define        SROM5_LEDDC             45
-
-#define        SROM4_AA                46
-
-#define        SROM4_AG10              47
-#define        SROM4_AG32              48
-
-#define        SROM4_TXPID2G           49
-#define        SROM4_TXPID5G           51
-#define        SROM4_TXPID5GL          53
-#define        SROM4_TXPID5GH          55
-
-#define SROM4_TXRXC            61
 #define SROM4_TXCHAIN_MASK     0x000f
-#define SROM4_TXCHAIN_SHIFT    0
 #define SROM4_RXCHAIN_MASK     0x00f0
-#define SROM4_RXCHAIN_SHIFT    4
 #define SROM4_SWITCH_MASK      0xff00
-#define SROM4_SWITCH_SHIFT     8
 
 /* Per-path fields */
 #define        MAX_PATH_SROM           4
-#define        SROM4_PATH0             64
-#define        SROM4_PATH1             87
-#define        SROM4_PATH2             110
-#define        SROM4_PATH3             133
-
-#define        SROM4_2G_ITT_MAXP       0
-#define        SROM4_2G_PA             1
-#define        SROM4_5G_ITT_MAXP       5
-#define        SROM4_5GLH_MAXP         6
-#define        SROM4_5G_PA             7
-#define        SROM4_5GL_PA            11
-#define        SROM4_5GH_PA            15
-
-/* All the miriad power offsets */
-#define        SROM4_2G_CCKPO          156
-#define        SROM4_2G_OFDMPO         157
-#define        SROM4_5G_OFDMPO         159
-#define        SROM4_5GL_OFDMPO        161
-#define        SROM4_5GH_OFDMPO        163
-#define        SROM4_2G_MCSPO          165
-#define        SROM4_5G_MCSPO          173
-#define        SROM4_5GL_MCSPO         181
-#define        SROM4_5GH_MCSPO         189
-#define        SROM4_CDDPO             197
-#define        SROM4_STBCPO            198
-#define        SROM4_BW40PO            199
-#define        SROM4_BWDUPPO           200
 
 #define        SROM4_CRCREV            219
 
@@ -424,103 +338,32 @@ struct brcms_varbuf {
 static const struct brcms_sromvar pci_sromvars[] = {
        {BRCMS_SROM_DEVID, 0xffffff00, SRFL_PRHEX | SRFL_NOVAR, PCI_F0DEVID,
         0xffff},
-       {BRCMS_SROM_BOARDREV, 0x0000000e, SRFL_PRHEX, SROM_AABREV,
-        SROM_BR_MASK},
-       {BRCMS_SROM_BOARDREV, 0x000000f0, SRFL_PRHEX, SROM4_BREV, 0xffff},
        {BRCMS_SROM_BOARDREV, 0xffffff00, SRFL_PRHEX, SROM8_BREV, 0xffff},
-       {BRCMS_SROM_BOARDFLAGS, 0x00000002, SRFL_PRHEX, SROM_BFL, 0xffff},
-       {BRCMS_SROM_BOARDFLAGS, 0x00000004, SRFL_PRHEX | SRFL_MORE, SROM_BFL,
-        0xffff},
-       {BRCMS_SROM_CONT, 0, 0, SROM_BFL2, 0xffff},
-       {BRCMS_SROM_BOARDFLAGS, 0x00000008, SRFL_PRHEX | SRFL_MORE, SROM_BFL,
-        0xffff},
-       {BRCMS_SROM_CONT, 0, 0, SROM3_BFL2, 0xffff},
-       {BRCMS_SROM_BOARDFLAGS, 0x00000010, SRFL_PRHEX | SRFL_MORE, SROM4_BFL0,
-        0xffff},
-       {BRCMS_SROM_CONT, 0, 0, SROM4_BFL1, 0xffff},
-       {BRCMS_SROM_BOARDFLAGS, 0x000000e0, SRFL_PRHEX | SRFL_MORE, SROM5_BFL0,
-        0xffff},
-       {BRCMS_SROM_CONT, 0, 0, SROM5_BFL1, 0xffff},
        {BRCMS_SROM_BOARDFLAGS, 0xffffff00, SRFL_PRHEX | SRFL_MORE, SROM8_BFL0,
         0xffff},
        {BRCMS_SROM_CONT, 0, 0, SROM8_BFL1, 0xffff},
-       {BRCMS_SROM_BOARDFLAGS2, 0x00000010, SRFL_PRHEX | SRFL_MORE, SROM4_BFL2,
-        0xffff},
-       {BRCMS_SROM_CONT, 0, 0, SROM4_BFL3, 0xffff},
-       {BRCMS_SROM_BOARDFLAGS2, 0x000000e0, SRFL_PRHEX | SRFL_MORE, SROM5_BFL2,
-        0xffff},
-       {BRCMS_SROM_CONT, 0, 0, SROM5_BFL3, 0xffff},
        {BRCMS_SROM_BOARDFLAGS2, 0xffffff00, SRFL_PRHEX | SRFL_MORE, SROM8_BFL2,
         0xffff},
        {BRCMS_SROM_CONT, 0, 0, SROM8_BFL3, 0xffff},
        {BRCMS_SROM_BOARDTYPE, 0xfffffffc, SRFL_PRHEX, SROM_SSID, 0xffff},
-       {BRCMS_SROM_BOARDNUM, 0x00000006, 0, SROM_MACLO_IL0, 0xffff},
-       {BRCMS_SROM_BOARDNUM, 0x00000008, 0, SROM3_MACLO, 0xffff},
-       {BRCMS_SROM_BOARDNUM, 0x00000010, 0, SROM4_MACLO, 0xffff},
-       {BRCMS_SROM_BOARDNUM, 0x000000e0, 0, SROM5_MACLO, 0xffff},
        {BRCMS_SROM_BOARDNUM, 0xffffff00, 0, SROM8_MACLO, 0xffff},
-       {BRCMS_SROM_CC, 0x00000002, 0, SROM_AABREV, SROM_CC_MASK},
-       {BRCMS_SROM_REGREV, 0x00000008, 0, SROM_OPO, 0xff00},
-       {BRCMS_SROM_REGREV, 0x00000010, 0, SROM4_REGREV, 0x00ff},
-       {BRCMS_SROM_REGREV, 0x000000e0, 0, SROM5_REGREV, 0x00ff},
        {BRCMS_SROM_REGREV, 0xffffff00, 0, SROM8_REGREV, 0x00ff},
-       {BRCMS_SROM_LEDBH0, 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0x00ff},
-       {BRCMS_SROM_LEDBH1, 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0xff00},
-       {BRCMS_SROM_LEDBH2, 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0x00ff},
-       {BRCMS_SROM_LEDBH3, 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0xff00},
-       {BRCMS_SROM_LEDBH0, 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0x00ff},
-       {BRCMS_SROM_LEDBH1, 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0xff00},
-       {BRCMS_SROM_LEDBH2, 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0x00ff},
-       {BRCMS_SROM_LEDBH3, 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0xff00},
-       {BRCMS_SROM_LEDBH0, 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0x00ff},
-       {BRCMS_SROM_LEDBH1, 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0xff00},
-       {BRCMS_SROM_LEDBH2, 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0x00ff},
-       {BRCMS_SROM_LEDBH3, 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0xff00},
        {BRCMS_SROM_LEDBH0, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0x00ff},
        {BRCMS_SROM_LEDBH1, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0xff00},
        {BRCMS_SROM_LEDBH2, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0x00ff},
        {BRCMS_SROM_LEDBH3, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0xff00},
-       {BRCMS_SROM_PA0B0, 0x0000000e, SRFL_PRHEX, SROM_WL0PAB0, 0xffff},
-       {BRCMS_SROM_PA0B1, 0x0000000e, SRFL_PRHEX, SROM_WL0PAB1, 0xffff},
-       {BRCMS_SROM_PA0B2, 0x0000000e, SRFL_PRHEX, SROM_WL0PAB2, 0xffff},
-       {BRCMS_SROM_PA0ITSSIT, 0x0000000e, 0, SROM_ITT, 0x00ff},
-       {BRCMS_SROM_PA0MAXPWR, 0x0000000e, 0, SROM_WL10MAXP, 0x00ff},
        {BRCMS_SROM_PA0B0, 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB0, 0xffff},
        {BRCMS_SROM_PA0B1, 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB1, 0xffff},
        {BRCMS_SROM_PA0B2, 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB2, 0xffff},
        {BRCMS_SROM_PA0ITSSIT, 0xffffff00, 0, SROM8_W0_ITTMAXP, 0xff00},
        {BRCMS_SROM_PA0MAXPWR, 0xffffff00, 0, SROM8_W0_ITTMAXP, 0x00ff},
-       {BRCMS_SROM_OPO, 0x0000000c, 0, SROM_OPO, 0x00ff},
        {BRCMS_SROM_OPO, 0xffffff00, 0, SROM8_2G_OFDMPO, 0x00ff},
-       {BRCMS_SROM_AA2G, 0x0000000e, 0, SROM_AABREV, SROM_AA0_MASK},
-       {BRCMS_SROM_AA2G, 0x000000f0, 0, SROM4_AA, 0x00ff},
        {BRCMS_SROM_AA2G, 0xffffff00, 0, SROM8_AA, 0x00ff},
-       {BRCMS_SROM_AA5G, 0x0000000e, 0, SROM_AABREV, SROM_AA1_MASK},
-       {BRCMS_SROM_AA5G, 0x000000f0, 0, SROM4_AA, 0xff00},
        {BRCMS_SROM_AA5G, 0xffffff00, 0, SROM8_AA, 0xff00},
-       {BRCMS_SROM_AG0, 0x0000000e, 0, SROM_AG10, 0x00ff},
-       {BRCMS_SROM_AG1, 0x0000000e, 0, SROM_AG10, 0xff00},
-       {BRCMS_SROM_AG0, 0x000000f0, 0, SROM4_AG10, 0x00ff},
-       {BRCMS_SROM_AG1, 0x000000f0, 0, SROM4_AG10, 0xff00},
-       {BRCMS_SROM_AG2, 0x000000f0, 0, SROM4_AG32, 0x00ff},
-       {BRCMS_SROM_AG3, 0x000000f0, 0, SROM4_AG32, 0xff00},
        {BRCMS_SROM_AG0, 0xffffff00, 0, SROM8_AG10, 0x00ff},
        {BRCMS_SROM_AG1, 0xffffff00, 0, SROM8_AG10, 0xff00},
        {BRCMS_SROM_AG2, 0xffffff00, 0, SROM8_AG32, 0x00ff},
        {BRCMS_SROM_AG3, 0xffffff00, 0, SROM8_AG32, 0xff00},
-       {BRCMS_SROM_PA1B0, 0x0000000e, SRFL_PRHEX, SROM_WL1PAB0, 0xffff},
-       {BRCMS_SROM_PA1B1, 0x0000000e, SRFL_PRHEX, SROM_WL1PAB1, 0xffff},
-       {BRCMS_SROM_PA1B2, 0x0000000e, SRFL_PRHEX, SROM_WL1PAB2, 0xffff},
-       {BRCMS_SROM_PA1LOB0, 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB0, 0xffff},
-       {BRCMS_SROM_PA1LOB1, 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB1, 0xffff},
-       {BRCMS_SROM_PA1LOB2, 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB2, 0xffff},
-       {BRCMS_SROM_PA1HIB0, 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB0, 0xffff},
-       {BRCMS_SROM_PA1HIB1, 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB1, 0xffff},
-       {BRCMS_SROM_PA1HIB2, 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB2, 0xffff},
-       {BRCMS_SROM_PA1ITSSIT, 0x0000000e, 0, SROM_ITT, 0xff00},
-       {BRCMS_SROM_PA1MAXPWR, 0x0000000e, 0, SROM_WL10MAXP, 0xff00},
-       {BRCMS_SROM_PA1LOMAXPWR, 0x0000000c, 0, SROM_WL1LHMAXP, 0xff00},
-       {BRCMS_SROM_PA1HIMAXPWR, 0x0000000c, 0, SROM_WL1LHMAXP, 0x00ff},
        {BRCMS_SROM_PA1B0, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0, 0xffff},
        {BRCMS_SROM_PA1B1, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1, 0xffff},
        {BRCMS_SROM_PA1B2, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2, 0xffff},
@@ -534,40 +377,20 @@ static const struct brcms_sromvar pci_sromvars[] = {
        {BRCMS_SROM_PA1MAXPWR, 0xffffff00, 0, SROM8_W1_ITTMAXP, 0x00ff},
        {BRCMS_SROM_PA1LOMAXPWR, 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0xff00},
        {BRCMS_SROM_PA1HIMAXPWR, 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0x00ff},
-       {BRCMS_SROM_BXA2G, 0x00000008, 0, SROM_BXARSSI2G, 0x1800},
-       {BRCMS_SROM_RSSISAV2G, 0x00000008, 0, SROM_BXARSSI2G, 0x0700},
-       {BRCMS_SROM_RSSISMC2G, 0x00000008, 0, SROM_BXARSSI2G, 0x00f0},
-       {BRCMS_SROM_RSSISMF2G, 0x00000008, 0, SROM_BXARSSI2G, 0x000f},
        {BRCMS_SROM_BXA2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x1800},
        {BRCMS_SROM_RSSISAV2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x0700},
        {BRCMS_SROM_RSSISMC2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x00f0},
        {BRCMS_SROM_RSSISMF2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x000f},
-       {BRCMS_SROM_BXA5G, 0x00000008, 0, SROM_BXARSSI5G, 0x1800},
-       {BRCMS_SROM_RSSISAV5G, 0x00000008, 0, SROM_BXARSSI5G, 0x0700},
-       {BRCMS_SROM_RSSISMC5G, 0x00000008, 0, SROM_BXARSSI5G, 0x00f0},
-       {BRCMS_SROM_RSSISMF5G, 0x00000008, 0, SROM_BXARSSI5G, 0x000f},
        {BRCMS_SROM_BXA5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x1800},
        {BRCMS_SROM_RSSISAV5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x0700},
        {BRCMS_SROM_RSSISMC5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x00f0},
        {BRCMS_SROM_RSSISMF5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x000f},
-       {BRCMS_SROM_TRI2G, 0x00000008, 0, SROM_TRI52G, 0x00ff},
-       {BRCMS_SROM_TRI5G, 0x00000008, 0, SROM_TRI52G, 0xff00},
-       {BRCMS_SROM_TRI5GL, 0x00000008, 0, SROM_TRI5GHL, 0x00ff},
-       {BRCMS_SROM_TRI5GH, 0x00000008, 0, SROM_TRI5GHL, 0xff00},
        {BRCMS_SROM_TRI2G, 0xffffff00, 0, SROM8_TRI52G, 0x00ff},
        {BRCMS_SROM_TRI5G, 0xffffff00, 0, SROM8_TRI52G, 0xff00},
        {BRCMS_SROM_TRI5GL, 0xffffff00, 0, SROM8_TRI5GHL, 0x00ff},
        {BRCMS_SROM_TRI5GH, 0xffffff00, 0, SROM8_TRI5GHL, 0xff00},
-       {BRCMS_SROM_RXPO2G, 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0x00ff},
-       {BRCMS_SROM_RXPO5G, 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0xff00},
        {BRCMS_SROM_RXPO2G, 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0x00ff},
        {BRCMS_SROM_RXPO5G, 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0xff00},
-       {BRCMS_SROM_TXCHAIN, 0x000000f0, SRFL_NOFFS, SROM4_TXRXC,
-        SROM4_TXCHAIN_MASK},
-       {BRCMS_SROM_RXCHAIN, 0x000000f0, SRFL_NOFFS, SROM4_TXRXC,
-        SROM4_RXCHAIN_MASK},
-       {BRCMS_SROM_ANTSWITCH, 0x000000f0, SRFL_NOFFS, SROM4_TXRXC,
-        SROM4_SWITCH_MASK},
        {BRCMS_SROM_TXCHAIN, 0xffffff00, SRFL_NOFFS, SROM8_TXRXC,
         SROM4_TXCHAIN_MASK},
        {BRCMS_SROM_RXCHAIN, 0xffffff00, SRFL_NOFFS, SROM8_TXRXC,
@@ -594,43 +417,11 @@ static const struct brcms_sromvar pci_sromvars[] = {
         SROM8_FEM_ANTSWLUT_MASK},
        {BRCMS_SROM_TEMPTHRESH, 0xffffff00, 0, SROM8_THERMAL, 0xff00},
        {BRCMS_SROM_TEMPOFFSET, 0xffffff00, 0, SROM8_THERMAL, 0x00ff},
-       {BRCMS_SROM_TXPID2GA0, 0x000000f0, 0, SROM4_TXPID2G, 0x00ff},
-       {BRCMS_SROM_TXPID2GA1, 0x000000f0, 0, SROM4_TXPID2G, 0xff00},
-       {BRCMS_SROM_TXPID2GA2, 0x000000f0, 0, SROM4_TXPID2G + 1, 0x00ff},
-       {BRCMS_SROM_TXPID2GA3, 0x000000f0, 0, SROM4_TXPID2G + 1, 0xff00},
-       {BRCMS_SROM_TXPID5GA0, 0x000000f0, 0, SROM4_TXPID5G, 0x00ff},
-       {BRCMS_SROM_TXPID5GA1, 0x000000f0, 0, SROM4_TXPID5G, 0xff00},
-       {BRCMS_SROM_TXPID5GA2, 0x000000f0, 0, SROM4_TXPID5G + 1, 0x00ff},
-       {BRCMS_SROM_TXPID5GA3, 0x000000f0, 0, SROM4_TXPID5G + 1, 0xff00},
-       {BRCMS_SROM_TXPID5GLA0, 0x000000f0, 0, SROM4_TXPID5GL, 0x00ff},
-       {BRCMS_SROM_TXPID5GLA1, 0x000000f0, 0, SROM4_TXPID5GL, 0xff00},
-       {BRCMS_SROM_TXPID5GLA2, 0x000000f0, 0, SROM4_TXPID5GL + 1, 0x00ff},
-       {BRCMS_SROM_TXPID5GLA3, 0x000000f0, 0, SROM4_TXPID5GL + 1, 0xff00},
-       {BRCMS_SROM_TXPID5GHA0, 0x000000f0, 0, SROM4_TXPID5GH, 0x00ff},
-       {BRCMS_SROM_TXPID5GHA1, 0x000000f0, 0, SROM4_TXPID5GH, 0xff00},
-       {BRCMS_SROM_TXPID5GHA2, 0x000000f0, 0, SROM4_TXPID5GH + 1, 0x00ff},
-       {BRCMS_SROM_TXPID5GHA3, 0x000000f0, 0, SROM4_TXPID5GH + 1, 0xff00},
-
-       {BRCMS_SROM_CCODE, 0x0000000f, SRFL_CCODE, SROM_CCODE, 0xffff},
-       {BRCMS_SROM_CCODE, 0x00000010, SRFL_CCODE, SROM4_CCODE, 0xffff},
-       {BRCMS_SROM_CCODE, 0x000000e0, SRFL_CCODE, SROM5_CCODE, 0xffff},
+
        {BRCMS_SROM_CCODE, 0xffffff00, SRFL_CCODE, SROM8_CCODE, 0xffff},
        {BRCMS_SROM_MACADDR, 0xffffff00, SRFL_ETHADDR, SROM8_MACHI, 0xffff},
-       {BRCMS_SROM_MACADDR, 0x000000e0, SRFL_ETHADDR, SROM5_MACHI, 0xffff},
-       {BRCMS_SROM_MACADDR, 0x00000010, SRFL_ETHADDR, SROM4_MACHI, 0xffff},
-       {BRCMS_SROM_MACADDR, 0x00000008, SRFL_ETHADDR, SROM3_MACHI, 0xffff},
-       {BRCMS_SROM_IL0MACADDR, 0x00000007, SRFL_ETHADDR, SROM_MACHI_IL0,
-        0xffff},
-       {BRCMS_SROM_ET1MACADDR, 0x00000007, SRFL_ETHADDR, SROM_MACHI_ET1,
-        0xffff},
        {BRCMS_SROM_LEDDC, 0xffffff00, SRFL_NOFFS | SRFL_LEDDC, SROM8_LEDDC,
         0xffff},
-       {BRCMS_SROM_LEDDC, 0x000000e0, SRFL_NOFFS | SRFL_LEDDC, SROM5_LEDDC,
-        0xffff},
-       {BRCMS_SROM_LEDDC, 0x00000010, SRFL_NOFFS | SRFL_LEDDC, SROM4_LEDDC,
-        0xffff},
-       {BRCMS_SROM_LEDDC, 0x00000008, SRFL_NOFFS | SRFL_LEDDC, SROM3_LEDDC,
-        0xffff},
        {BRCMS_SROM_RAWTEMPSENSE, 0xffffff00, SRFL_PRHEX, SROM8_MPWR_RAWTS,
         0x01ff},
        {BRCMS_SROM_MEASPOWER, 0xffffff00, SRFL_PRHEX, SROM8_MPWR_RAWTS,
@@ -650,16 +441,7 @@ static const struct brcms_sromvar pci_sromvars[] = {
        {BRCMS_SROM_PHYCAL_TEMPDELTA, 0xffffff00, 0, SROM8_PHYCAL_TEMPDELTA,
         0x00ff},
 
-       {BRCMS_SROM_CCK2GPO, 0x000000f0, 0, SROM4_2G_CCKPO, 0xffff},
        {BRCMS_SROM_CCK2GPO, 0x00000100, 0, SROM8_2G_CCKPO, 0xffff},
-       {BRCMS_SROM_OFDM2GPO, 0x000000f0, SRFL_MORE, SROM4_2G_OFDMPO, 0xffff},
-       {BRCMS_SROM_CONT, 0, 0, SROM4_2G_OFDMPO + 1, 0xffff},
-       {BRCMS_SROM_OFDM5GPO, 0x000000f0, SRFL_MORE, SROM4_5G_OFDMPO, 0xffff},
-       {BRCMS_SROM_CONT, 0, 0, SROM4_5G_OFDMPO + 1, 0xffff},
-       {BRCMS_SROM_OFDM5GLPO, 0x000000f0, SRFL_MORE, SROM4_5GL_OFDMPO, 0xffff},
-       {BRCMS_SROM_CONT, 0, 0, SROM4_5GL_OFDMPO + 1, 0xffff},
-       {BRCMS_SROM_OFDM5GHPO, 0x000000f0, SRFL_MORE, SROM4_5GH_OFDMPO, 0xffff},
-       {BRCMS_SROM_CONT, 0, 0, SROM4_5GH_OFDMPO + 1, 0xffff},
        {BRCMS_SROM_OFDM2GPO, 0x00000100, SRFL_MORE, SROM8_2G_OFDMPO, 0xffff},
        {BRCMS_SROM_CONT, 0, 0, SROM8_2G_OFDMPO + 1, 0xffff},
        {BRCMS_SROM_OFDM5GPO, 0x00000100, SRFL_MORE, SROM8_5G_OFDMPO, 0xffff},
@@ -668,38 +450,6 @@ static const struct brcms_sromvar pci_sromvars[] = {
        {BRCMS_SROM_CONT, 0, 0, SROM8_5GL_OFDMPO + 1, 0xffff},
        {BRCMS_SROM_OFDM5GHPO, 0x00000100, SRFL_MORE, SROM8_5GH_OFDMPO, 0xffff},
        {BRCMS_SROM_CONT, 0, 0, SROM8_5GH_OFDMPO + 1, 0xffff},
-       {BRCMS_SROM_MCS2GPO0, 0x000000f0, 0, SROM4_2G_MCSPO, 0xffff},
-       {BRCMS_SROM_MCS2GPO1, 0x000000f0, 0, SROM4_2G_MCSPO + 1, 0xffff},
-       {BRCMS_SROM_MCS2GPO2, 0x000000f0, 0, SROM4_2G_MCSPO + 2, 0xffff},
-       {BRCMS_SROM_MCS2GPO3, 0x000000f0, 0, SROM4_2G_MCSPO + 3, 0xffff},
-       {BRCMS_SROM_MCS2GPO4, 0x000000f0, 0, SROM4_2G_MCSPO + 4, 0xffff},
-       {BRCMS_SROM_MCS2GPO5, 0x000000f0, 0, SROM4_2G_MCSPO + 5, 0xffff},
-       {BRCMS_SROM_MCS2GPO6, 0x000000f0, 0, SROM4_2G_MCSPO + 6, 0xffff},
-       {BRCMS_SROM_MCS2GPO7, 0x000000f0, 0, SROM4_2G_MCSPO + 7, 0xffff},
-       {BRCMS_SROM_MCS5GPO0, 0x000000f0, 0, SROM4_5G_MCSPO, 0xffff},
-       {BRCMS_SROM_MCS5GPO1, 0x000000f0, 0, SROM4_5G_MCSPO + 1, 0xffff},
-       {BRCMS_SROM_MCS5GPO2, 0x000000f0, 0, SROM4_5G_MCSPO + 2, 0xffff},
-       {BRCMS_SROM_MCS5GPO3, 0x000000f0, 0, SROM4_5G_MCSPO + 3, 0xffff},
-       {BRCMS_SROM_MCS5GPO4, 0x000000f0, 0, SROM4_5G_MCSPO + 4, 0xffff},
-       {BRCMS_SROM_MCS5GPO5, 0x000000f0, 0, SROM4_5G_MCSPO + 5, 0xffff},
-       {BRCMS_SROM_MCS5GPO6, 0x000000f0, 0, SROM4_5G_MCSPO + 6, 0xffff},
-       {BRCMS_SROM_MCS5GPO7, 0x000000f0, 0, SROM4_5G_MCSPO + 7, 0xffff},
-       {BRCMS_SROM_MCS5GLPO0, 0x000000f0, 0, SROM4_5GL_MCSPO, 0xffff},
-       {BRCMS_SROM_MCS5GLPO1, 0x000000f0, 0, SROM4_5GL_MCSPO + 1, 0xffff},
-       {BRCMS_SROM_MCS5GLPO2, 0x000000f0, 0, SROM4_5GL_MCSPO + 2, 0xffff},
-       {BRCMS_SROM_MCS5GLPO3, 0x000000f0, 0, SROM4_5GL_MCSPO + 3, 0xffff},
-       {BRCMS_SROM_MCS5GLPO4, 0x000000f0, 0, SROM4_5GL_MCSPO + 4, 0xffff},
-       {BRCMS_SROM_MCS5GLPO5, 0x000000f0, 0, SROM4_5GL_MCSPO + 5, 0xffff},
-       {BRCMS_SROM_MCS5GLPO6, 0x000000f0, 0, SROM4_5GL_MCSPO + 6, 0xffff},
-       {BRCMS_SROM_MCS5GLPO7, 0x000000f0, 0, SROM4_5GL_MCSPO + 7, 0xffff},
-       {BRCMS_SROM_MCS5GHPO0, 0x000000f0, 0, SROM4_5GH_MCSPO, 0xffff},
-       {BRCMS_SROM_MCS5GHPO1, 0x000000f0, 0, SROM4_5GH_MCSPO + 1, 0xffff},
-       {BRCMS_SROM_MCS5GHPO2, 0x000000f0, 0, SROM4_5GH_MCSPO + 2, 0xffff},
-       {BRCMS_SROM_MCS5GHPO3, 0x000000f0, 0, SROM4_5GH_MCSPO + 3, 0xffff},
-       {BRCMS_SROM_MCS5GHPO4, 0x000000f0, 0, SROM4_5GH_MCSPO + 4, 0xffff},
-       {BRCMS_SROM_MCS5GHPO5, 0x000000f0, 0, SROM4_5GH_MCSPO + 5, 0xffff},
-       {BRCMS_SROM_MCS5GHPO6, 0x000000f0, 0, SROM4_5GH_MCSPO + 6, 0xffff},
-       {BRCMS_SROM_MCS5GHPO7, 0x000000f0, 0, SROM4_5GH_MCSPO + 7, 0xffff},
        {BRCMS_SROM_MCS2GPO0, 0x00000100, 0, SROM8_2G_MCSPO, 0xffff},
        {BRCMS_SROM_MCS2GPO1, 0x00000100, 0, SROM8_2G_MCSPO + 1, 0xffff},
        {BRCMS_SROM_MCS2GPO2, 0x00000100, 0, SROM8_2G_MCSPO + 2, 0xffff},
@@ -732,10 +482,6 @@ static const struct brcms_sromvar pci_sromvars[] = {
        {BRCMS_SROM_MCS5GHPO5, 0x00000100, 0, SROM8_5GH_MCSPO + 5, 0xffff},
        {BRCMS_SROM_MCS5GHPO6, 0x00000100, 0, SROM8_5GH_MCSPO + 6, 0xffff},
        {BRCMS_SROM_MCS5GHPO7, 0x00000100, 0, SROM8_5GH_MCSPO + 7, 0xffff},
-       {BRCMS_SROM_CDDPO, 0x000000f0, 0, SROM4_CDDPO, 0xffff},
-       {BRCMS_SROM_STBCPO, 0x000000f0, 0, SROM4_STBCPO, 0xffff},
-       {BRCMS_SROM_BW40PO, 0x000000f0, 0, SROM4_BW40PO, 0xffff},
-       {BRCMS_SROM_BWDUPPO, 0x000000f0, 0, SROM4_BWDUPPO, 0xffff},
        {BRCMS_SROM_CDDPO, 0x00000100, 0, SROM8_CDDPO, 0xffff},
        {BRCMS_SROM_STBCPO, 0x00000100, 0, SROM8_STBCPO, 0xffff},
        {BRCMS_SROM_BW40PO, 0x00000100, 0, SROM8_BW40PO, 0xffff},
@@ -811,34 +557,6 @@ static const struct brcms_sromvar pci_sromvars[] = {
 };
 
 static const struct brcms_sromvar perpath_pci_sromvars[] = {
-       {BRCMS_SROM_MAXP2GA0, 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0x00ff},
-       {BRCMS_SROM_ITT2GA0, 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0xff00},
-       {BRCMS_SROM_ITT5GA0, 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0xff00},
-       {BRCMS_SROM_PA2GW0A0, 0x000000f0, SRFL_PRHEX, SROM4_2G_PA, 0xffff},
-       {BRCMS_SROM_PA2GW1A0, 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 1, 0xffff},
-       {BRCMS_SROM_PA2GW2A0, 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 2, 0xffff},
-       {BRCMS_SROM_PA2GW3A0, 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 3, 0xffff},
-       {BRCMS_SROM_MAXP5GA0, 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0x00ff},
-       {BRCMS_SROM_MAXP5GHA0, 0x000000f0, 0, SROM4_5GLH_MAXP, 0x00ff},
-       {BRCMS_SROM_MAXP5GLA0, 0x000000f0, 0, SROM4_5GLH_MAXP, 0xff00},
-       {BRCMS_SROM_PA5GW0A0, 0x000000f0, SRFL_PRHEX, SROM4_5G_PA, 0xffff},
-       {BRCMS_SROM_PA5GW1A0, 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 1, 0xffff},
-       {BRCMS_SROM_PA5GW2A0, 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 2, 0xffff},
-       {BRCMS_SROM_PA5GW3A0, 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 3, 0xffff},
-       {BRCMS_SROM_PA5GLW0A0, 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA, 0xffff},
-       {BRCMS_SROM_PA5GLW1A0, 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 1,
-        0xffff},
-       {BRCMS_SROM_PA5GLW2A0, 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 2,
-        0xffff},
-       {BRCMS_SROM_PA5GLW3A0, 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 3,
-        0xffff},
-       {BRCMS_SROM_PA5GHW0A0, 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA, 0xffff},
-       {BRCMS_SROM_PA5GHW1A0, 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 1,
-        0xffff},
-       {BRCMS_SROM_PA5GHW2A0, 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 2,
-        0xffff},
-       {BRCMS_SROM_PA5GHW3A0, 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 3,
-        0xffff},
        {BRCMS_SROM_MAXP2GA0, 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0x00ff},
        {BRCMS_SROM_ITT2GA0, 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0xff00},
        {BRCMS_SROM_ITT5GA0, 0xffffff00, 0, SROM8_5G_ITT_MAXP, 0xff00},
@@ -868,24 +586,17 @@ static const struct brcms_sromvar perpath_pci_sromvars[] = {
  * shared between devices. */
 static u8 brcms_srom_crc8_table[CRC8_TABLE_SIZE];
 
-static u16 __iomem *
+static u8 __iomem *
 srom_window_address(struct si_pub *sih, u8 __iomem *curmap)
 {
        if (sih->ccrev < 32)
-               return (u16 __iomem *)(curmap + PCI_BAR0_SPROM_OFFSET);
+               return curmap + PCI_BAR0_SPROM_OFFSET;
        if (sih->cccaps & CC_CAP_SROM)
-               return (u16 __iomem *)
-                      (curmap + PCI_16KB0_CCREGS_OFFSET + CC_SROM_OTP);
+               return curmap + PCI_16KB0_CCREGS_OFFSET + CC_SROM_OTP;
 
        return NULL;
 }
 
-/* Parse SROM and create name=value pairs. 'srom' points to
- * the SROM word array. 'off' specifies the offset of the
- * first word 'srom' points to, which should be either 0 or
- * SROM3_SWRG_OFF (full SROM or software region).
- */
-
 static uint mask_shift(u16 mask)
 {
        uint i;
@@ -906,18 +617,16 @@ static uint mask_width(u16 mask)
        return 0;
 }
 
-static inline void ltoh16_buf(u16 *buf, unsigned int size)
+static inline void le16_to_cpu_buf(u16 *buf, uint nwords)
 {
-       size /= 2;
-       while (size--)
-               *(buf + size) = le16_to_cpu(*(__le16 *)(buf + size));
+       while (nwords--)
+               *(buf + nwords) = le16_to_cpu(*(__le16 *)(buf + nwords));
 }
 
-static inline void htol16_buf(u16 *buf, unsigned int size)
+static inline void cpu_to_le16_buf(u16 *buf, uint nwords)
 {
-       size /= 2;
-       while (size--)
-               *(__le16 *)(buf + size) = cpu_to_le16(*(buf + size));
+       while (nwords--)
+               *(__le16 *)(buf + nwords) = cpu_to_le16(*(buf + nwords));
 }
 
 /*
@@ -929,11 +638,14 @@ _initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list)
        struct brcms_srom_list_head *entry;
        enum brcms_srom_id id;
        u16 w;
-       u32 val;
+       u32 val = 0;
        const struct brcms_sromvar *srv;
        uint width;
        uint flags;
        u32 sr = (1 << sromrev);
+       uint p;
+       uint pb =  SROM8_PATH0;
+       const uint psz = SROM8_PATH1 - SROM8_PATH0;
 
        /* first store the srom revision */
        entry = kzalloc(sizeof(struct brcms_srom_list_head), GFP_KERNEL);
@@ -1031,47 +743,34 @@ _initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list)
                list_add(&entry->var_list, var_list);
        }
 
-       if (sromrev >= 4) {
-               /* Do per-path variables */
-               uint p, pb, psz;
-
-               if (sromrev >= 8) {
-                       pb = SROM8_PATH0;
-                       psz = SROM8_PATH1 - SROM8_PATH0;
-               } else {
-                       pb = SROM4_PATH0;
-                       psz = SROM4_PATH1 - SROM4_PATH0;
-               }
-
-               for (p = 0; p < MAX_PATH_SROM; p++) {
-                       for (srv = perpath_pci_sromvars;
-                            srv->varid != BRCMS_SROM_NULL; srv++) {
-                               if ((srv->revmask & sr) == 0)
-                                       continue;
+       for (p = 0; p < MAX_PATH_SROM; p++) {
+               for (srv = perpath_pci_sromvars;
+                    srv->varid != BRCMS_SROM_NULL; srv++) {
+                       if ((srv->revmask & sr) == 0)
+                               continue;
 
-                               if (srv->flags & SRFL_NOVAR)
-                                       continue;
+                       if (srv->flags & SRFL_NOVAR)
+                               continue;
 
-                               w = srom[pb + srv->off];
-                               val = (w & srv->mask) >> mask_shift(srv->mask);
-                               width = mask_width(srv->mask);
+                       w = srom[pb + srv->off];
+                       val = (w & srv->mask) >> mask_shift(srv->mask);
+                       width = mask_width(srv->mask);
 
-                               /* Cheating: no per-path var is more than
-                                * 1 word */
-                               if ((srv->flags & SRFL_NOFFS)
-                                   && ((int)val == (1 << width) - 1))
-                                       continue;
+                       /* Cheating: no per-path var is more than
+                        * 1 word */
+                       if ((srv->flags & SRFL_NOFFS)
+                           && ((int)val == (1 << width) - 1))
+                               continue;
 
-                               entry =
-                                   kzalloc(sizeof(struct brcms_srom_list_head),
-                                           GFP_KERNEL);
-                               entry->varid = srv->varid+p;
-                               entry->var_type = BRCMS_SROM_UNUMBER;
-                               entry->uval = val;
-                               list_add(&entry->var_list, var_list);
-                       }
-                       pb += psz;
+                       entry =
+                           kzalloc(sizeof(struct brcms_srom_list_head),
+                                   GFP_KERNEL);
+                       entry->varid = srv->varid+p;
+                       entry->var_type = BRCMS_SROM_UNUMBER;
+                       entry->uval = val;
+                       list_add(&entry->var_list, var_list);
                }
+               pb += psz;
        }
 }
 
@@ -1080,41 +779,38 @@ _initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list)
  * Return 0 on success, nonzero on error.
  */
 static int
-sprom_read_pci(struct si_pub *sih, u16 __iomem *sprom, uint wordoff,
+sprom_read_pci(struct si_pub *sih, u8 __iomem *sprom, uint wordoff,
               u16 *buf, uint nwords, bool check_crc)
 {
        int err = 0;
        uint i;
+       u8 *bbuf = (u8 *)buf; /* byte buffer */
+       uint nbytes = nwords << 1;
 
-       /* read the sprom */
-       for (i = 0; i < nwords; i++)
-               buf[i] = R_REG(&sprom[wordoff + i]);
-
-       if (check_crc) {
+       /* read the sprom in bytes */
+       for (i = 0; i < nbytes; i++)
+               bbuf[i] = readb(sprom+i);
 
-               if (buf[0] == 0xffff)
-                       /*
-                        * The hardware thinks that an srom that starts with
-                        * 0xffff is blank, regardless of the rest of the
-                        * content, so declare it bad.
-                        */
-                       return -ENODATA;
-
-               /* fixup the endianness so crc8 will pass */
-               htol16_buf(buf, nwords * 2);
-               if (crc8(brcms_srom_crc8_table, (u8 *) buf, nwords * 2,
-                        CRC8_INIT_VALUE) !=
-                        CRC8_GOOD_VALUE(brcms_srom_crc8_table))
-                       /* DBG only pci always read srom4 first, then srom8/9 */
-                       err = -EIO;
+       if (buf[0] == 0xffff)
+               /*
+                * The hardware thinks that an srom that starts with
+                * 0xffff is blank, regardless of the rest of the
+                * content, so declare it bad.
+                */
+               return -ENODATA;
 
+       if (check_crc &&
+           crc8(brcms_srom_crc8_table, bbuf, nbytes, CRC8_INIT_VALUE) !=
+                CRC8_GOOD_VALUE(brcms_srom_crc8_table))
+               err = -EIO;
+       else
                /* now correct the endianness of the byte array */
-               ltoh16_buf(buf, nwords * 2);
-       }
+               le16_to_cpu_buf(buf, nwords);
+
        return err;
 }
 
-static int otp_read_pci(struct si_pub *sih, u16 *buf, uint bufsz)
+static int otp_read_pci(struct si_pub *sih, u16 *buf, uint nwords)
 {
        u8 *otp;
        uint sz = OTP_SZ_MAX / 2;       /* size in words */
@@ -1126,7 +822,8 @@ static int otp_read_pci(struct si_pub *sih, u16 *buf, uint bufsz)
 
        err = otp_read_region(sih, OTP_HW_RGN, (u16 *) otp, &sz);
 
-       memcpy(buf, otp, bufsz);
+       sz = min_t(uint, sz, nwords);
+       memcpy(buf, otp, sz * 2);
 
        kfree(otp);
 
@@ -1139,13 +836,13 @@ static int otp_read_pci(struct si_pub *sih, u16 *buf, uint bufsz)
                return -ENODATA;
 
        /* fixup the endianness so crc8 will pass */
-       htol16_buf(buf, bufsz);
-       if (crc8(brcms_srom_crc8_table, (u8 *) buf, SROM4_WORDS * 2,
+       cpu_to_le16_buf(buf, sz);
+       if (crc8(brcms_srom_crc8_table, (u8 *) buf, sz * 2,
                 CRC8_INIT_VALUE) != CRC8_GOOD_VALUE(brcms_srom_crc8_table))
                err = -EIO;
-
-       /* now correct the endianness of the byte array */
-       ltoh16_buf(buf, bufsz);
+       else
+               /* now correct the endianness of the byte array */
+               le16_to_cpu_buf(buf, sz);
 
        return err;
 }
@@ -1157,7 +854,7 @@ static int otp_read_pci(struct si_pub *sih, u16 *buf, uint bufsz)
 static int initvars_srom_pci(struct si_pub *sih, void __iomem *curmap)
 {
        u16 *srom;
-       u16 __iomem *sromwindow;
+       u8 __iomem *sromwindow;
        u8 sromrev = 0;
        u32 sr;
        int err = 0;
@@ -1173,29 +870,16 @@ static int initvars_srom_pci(struct si_pub *sih, void __iomem *curmap)
 
        crc8_populate_lsb(brcms_srom_crc8_table, SROM_CRC8_POLY);
        if (ai_is_sprom_available(sih)) {
-               err = sprom_read_pci(sih, sromwindow, 0, srom, SROM_WORDS,
-                                    true);
-
-               if ((srom[SROM4_SIGN] == SROM4_SIGNATURE) ||
-                   (((sih->buscoretype == PCIE_CORE_ID)
-                     && (sih->buscorerev >= 6))
-                    || ((sih->buscoretype == PCI_CORE_ID)
-                        && (sih->buscorerev >= 0xe)))) {
-                       /* sromrev >= 4, read more */
-                       err = sprom_read_pci(sih, sromwindow, 0, srom,
-                                            SROM4_WORDS, true);
-                       sromrev = srom[SROM4_CRCREV] & 0xff;
-               } else if (err == 0) {
-                       /* srom is good and is rev < 4 */
+               err = sprom_read_pci(sih, sromwindow, 0, srom,
+                                    SROM4_WORDS, true);
+
+               if (err == 0)
+                       /* srom read and passed crc */
                        /* top word of sprom contains version and crc8 */
-                       sromrev = srom[SROM_CRCREV] & 0xff;
-                       /* bcm4401 sroms misprogrammed */
-                       if (sromrev == 0x10)
-                               sromrev = 1;
-               }
+                       sromrev = srom[SROM4_CRCREV] & 0xff;
        } else {
                /* Use OTP if SPROM not available */
-               err = otp_read_pci(sih, srom, SROM_MAX);
+               err = otp_read_pci(sih, srom, SROM4_WORDS);
                if (err == 0)
                        /* OTP only contain SROM rev8/rev9 for now */
                        sromrev = srom[SROM4_CRCREV] & 0xff;
@@ -1208,10 +892,9 @@ static int initvars_srom_pci(struct si_pub *sih, void __iomem *curmap)
                sr = 1 << sromrev;
 
                /*
-                * srom version check: Current valid versions: 1, 2, 3, 4, 5, 8,
-                * 9
+                * srom version check: Current valid versions: 8, 9
                 */
-               if ((sr & 0x33e) == 0) {
+               if ((sr & 0x300) == 0) {
                        err = -EINVAL;
                        goto errout;
                }
index 708c43f..c81df97 100644 (file)
@@ -26,9 +26,4 @@ extern void srom_free_vars(struct si_pub *sih);
 extern int srom_read(struct si_pub *sih, uint bus, void *curmap,
                     uint byteoff, uint nbytes, u16 *buf, bool check_crc);
 
-/* parse standard PCMCIA cis, normally used by SB/PCMCIA/SDIO/SPI/OTP
- *   and extract from it into name=value pairs
- */
-extern int srom_parsecis(u8 **pcis, uint ciscnt,
-                        char **vars, uint *count);
 #endif                         /* _BRCM_SROM_H_ */
index f27c489..b7537f7 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <linux/netdevice.h>
 #include <linux/module.h>
+
 #include <brcmu_utils.h>
 
 MODULE_AUTHOR("Broadcom Corporation");
@@ -40,74 +41,20 @@ EXPORT_SYMBOL(brcmu_pkt_buf_get_skb);
 /* Free the driver packet. Free the tag if present */
 void brcmu_pkt_buf_free_skb(struct sk_buff *skb)
 {
-       struct sk_buff *nskb;
-       int nest = 0;
-
-       /* perversion: we use skb->next to chain multi-skb packets */
-       while (skb) {
-               nskb = skb->next;
-               skb->next = NULL;
-
-               if (skb->destructor)
-                       /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if
-                        * destructor exists
-                        */
-                       dev_kfree_skb_any(skb);
-               else
-                       /* can free immediately (even in_irq()) if destructor
-                        * does not exist
-                        */
-                       dev_kfree_skb(skb);
-
-               nest++;
-               skb = nskb;
-       }
+       WARN_ON(skb->next);
+       if (skb->destructor)
+               /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if
+                * destructor exists
+                */
+               dev_kfree_skb_any(skb);
+       else
+               /* can free immediately (even in_irq()) if destructor
+                * does not exist
+                */
+               dev_kfree_skb(skb);
 }
 EXPORT_SYMBOL(brcmu_pkt_buf_free_skb);
 
-
-/* copy a buffer into a pkt buffer chain */
-uint brcmu_pktfrombuf(struct sk_buff *p, uint offset, int len,
-               unsigned char *buf)
-{
-       uint n, ret = 0;
-
-       /* skip 'offset' bytes */
-       for (; p && offset; p = p->next) {
-               if (offset < (uint) (p->len))
-                       break;
-               offset -= p->len;
-       }
-
-       if (!p)
-               return 0;
-
-       /* copy the data */
-       for (; p && len; p = p->next) {
-               n = min((uint) (p->len) - offset, (uint) len);
-               memcpy(p->data + offset, buf, n);
-               buf += n;
-               len -= n;
-               ret += n;
-               offset = 0;
-       }
-
-       return ret;
-}
-EXPORT_SYMBOL(brcmu_pktfrombuf);
-
-/* return total length of buffer chain */
-uint brcmu_pkttotlen(struct sk_buff *p)
-{
-       uint total;
-
-       total = 0;
-       for (; p; p = p->next)
-               total += p->len;
-       return total;
-}
-EXPORT_SYMBOL(brcmu_pkttotlen);
-
 /*
  * osl multiple-precedence packet queue
  * hi_prec is always >= the number of the highest non-empty precedence
@@ -115,21 +62,13 @@ EXPORT_SYMBOL(brcmu_pkttotlen);
 struct sk_buff *brcmu_pktq_penq(struct pktq *pq, int prec,
                                      struct sk_buff *p)
 {
-       struct pktq_prec *q;
+       struct sk_buff_head *q;
 
        if (pktq_full(pq) || pktq_pfull(pq, prec))
                return NULL;
 
-       q = &pq->q[prec];
-
-       if (q->head)
-               q->tail->prev = p;
-       else
-               q->head = p;
-
-       q->tail = p;
-       q->len++;
-
+       q = &pq->q[prec].skblist;
+       skb_queue_tail(q, p);
        pq->len++;
 
        if (pq->hi_prec < prec)
@@ -142,20 +81,13 @@ EXPORT_SYMBOL(brcmu_pktq_penq);
 struct sk_buff *brcmu_pktq_penq_head(struct pktq *pq, int prec,
                                           struct sk_buff *p)
 {
-       struct pktq_prec *q;
+       struct sk_buff_head *q;
 
        if (pktq_full(pq) || pktq_pfull(pq, prec))
                return NULL;
 
-       q = &pq->q[prec];
-
-       if (q->head == NULL)
-               q->tail = p;
-
-       p->prev = q->head;
-       q->head = p;
-       q->len++;
-
+       q = &pq->q[prec].skblist;
+       skb_queue_head(q, p);
        pq->len++;
 
        if (pq->hi_prec < prec)
@@ -167,53 +99,30 @@ EXPORT_SYMBOL(brcmu_pktq_penq_head);
 
 struct sk_buff *brcmu_pktq_pdeq(struct pktq *pq, int prec)
 {
-       struct pktq_prec *q;
+       struct sk_buff_head *q;
        struct sk_buff *p;
 
-       q = &pq->q[prec];
-
-       p = q->head;
+       q = &pq->q[prec].skblist;
+       p = skb_dequeue(q);
        if (p == NULL)
                return NULL;
 
-       q->head = p->prev;
-       if (q->head == NULL)
-               q->tail = NULL;
-
-       q->len--;
-
        pq->len--;
-
-       p->prev = NULL;
-
        return p;
 }
 EXPORT_SYMBOL(brcmu_pktq_pdeq);
 
 struct sk_buff *brcmu_pktq_pdeq_tail(struct pktq *pq, int prec)
 {
-       struct pktq_prec *q;
-       struct sk_buff *p, *prev;
-
-       q = &pq->q[prec];
+       struct sk_buff_head *q;
+       struct sk_buff *p;
 
-       p = q->head;
+       q = &pq->q[prec].skblist;
+       p = skb_dequeue_tail(q);
        if (p == NULL)
                return NULL;
 
-       for (prev = NULL; p != q->tail; p = p->prev)
-               prev = p;
-
-       if (prev)
-               prev->prev = NULL;
-       else
-               q->head = NULL;
-
-       q->tail = prev;
-       q->len--;
-
        pq->len--;
-
        return p;
 }
 EXPORT_SYMBOL(brcmu_pktq_pdeq_tail);
@@ -222,31 +131,17 @@ void
 brcmu_pktq_pflush(struct pktq *pq, int prec, bool dir,
                  bool (*fn)(struct sk_buff *, void *), void *arg)
 {
-       struct pktq_prec *q;
-       struct sk_buff *p, *prev = NULL;
+       struct sk_buff_head *q;
+       struct sk_buff *p, *next;
 
-       q = &pq->q[prec];
-       p = q->head;
-       while (p) {
+       q = &pq->q[prec].skblist;
+       skb_queue_walk_safe(q, p, next) {
                if (fn == NULL || (*fn) (p, arg)) {
-                       bool head = (p == q->head);
-                       if (head)
-                               q->head = p->prev;
-                       else
-                               prev->prev = p->prev;
-                       p->prev = NULL;
+                       skb_unlink(p, q);
                        brcmu_pkt_buf_free_skb(p);
-                       q->len--;
                        pq->len--;
-                       p = (head ? q->head : prev->prev);
-               } else {
-                       prev = p;
-                       p = p->prev;
                }
        }
-
-       if (q->head == NULL)
-               q->tail = NULL;
 }
 EXPORT_SYMBOL(brcmu_pktq_pflush);
 
@@ -271,8 +166,10 @@ void brcmu_pktq_init(struct pktq *pq, int num_prec, int max_len)
 
        pq->max = (u16) max_len;
 
-       for (prec = 0; prec < num_prec; prec++)
+       for (prec = 0; prec < num_prec; prec++) {
                pq->q[prec].max = pq->max;
+               skb_queue_head_init(&pq->q[prec].skblist);
+       }
 }
 EXPORT_SYMBOL(brcmu_pktq_init);
 
@@ -284,13 +181,13 @@ struct sk_buff *brcmu_pktq_peek_tail(struct pktq *pq, int *prec_out)
                return NULL;
 
        for (prec = 0; prec < pq->hi_prec; prec++)
-               if (pq->q[prec].head)
+               if (!skb_queue_empty(&pq->q[prec].skblist))
                        break;
 
        if (prec_out)
                *prec_out = prec;
 
-       return pq->q[prec].tail;
+       return skb_peek_tail(&pq->q[prec].skblist);
 }
 EXPORT_SYMBOL(brcmu_pktq_peek_tail);
 
@@ -303,7 +200,7 @@ int brcmu_pktq_mlen(struct pktq *pq, uint prec_bmp)
 
        for (prec = 0; prec <= pq->hi_prec; prec++)
                if (prec_bmp & (1 << prec))
-                       len += pq->q[prec].len;
+                       len += pq->q[prec].skblist.qlen;
 
        return len;
 }
@@ -313,39 +210,32 @@ EXPORT_SYMBOL(brcmu_pktq_mlen);
 struct sk_buff *brcmu_pktq_mdeq(struct pktq *pq, uint prec_bmp,
                                      int *prec_out)
 {
-       struct pktq_prec *q;
+       struct sk_buff_head *q;
        struct sk_buff *p;
        int prec;
 
        if (pq->len == 0)
                return NULL;
 
-       while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
+       while ((prec = pq->hi_prec) > 0 &&
+              skb_queue_empty(&pq->q[prec].skblist))
                pq->hi_prec--;
 
-       while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
+       while ((prec_bmp & (1 << prec)) == 0 ||
+              skb_queue_empty(&pq->q[prec].skblist))
                if (prec-- == 0)
                        return NULL;
 
-       q = &pq->q[prec];
-
-       p = q->head;
+       q = &pq->q[prec].skblist;
+       p = skb_dequeue(q);
        if (p == NULL)
                return NULL;
 
-       q->head = p->prev;
-       if (q->head == NULL)
-               q->tail = NULL;
-
-       q->len--;
+       pq->len--;
 
        if (prec_out)
                *prec_out = prec;
 
-       pq->len--;
-
-       p->prev = NULL;
-
        return p;
 }
 EXPORT_SYMBOL(brcmu_pktq_mdeq);
@@ -364,23 +254,3 @@ void brcmu_prpkt(const char *msg, struct sk_buff *p0)
 }
 EXPORT_SYMBOL(brcmu_prpkt);
 #endif                         /* defined(BCMDBG) */
-
-#if defined(BCMDBG)
-/*
- * print bytes formatted as hex to a string. return the resulting
- * string length
- */
-int brcmu_format_hex(char *str, const void *bytes, int len)
-{
-       int i;
-       char *p = str;
-       const u8 *src = (const u8 *)bytes;
-
-       for (i = 0; i < len; i++) {
-               p += snprintf(p, 3, "%02X", *src);
-               src++;
-       }
-       return (int)(p - str);
-}
-EXPORT_SYMBOL(brcmu_format_hex);
-#endif                         /* defined(BCMDBG) */
index 7d0f46e..ad249a0 100644 (file)
@@ -65,9 +65,7 @@
 #define ETHER_ADDR_STR_LEN     18
 
 struct pktq_prec {
-       struct sk_buff *head;   /* first packet to dequeue */
-       struct sk_buff *tail;   /* last packet to dequeue */
-       u16 len;                /* number of queued packets */
+       struct sk_buff_head skblist;
        u16 max;                /* maximum number of queued packets */
 };
 
@@ -88,32 +86,32 @@ struct pktq {
 
 static inline int pktq_plen(struct pktq *pq, int prec)
 {
-       return pq->q[prec].len;
+       return pq->q[prec].skblist.qlen;
 }
 
 static inline int pktq_pavail(struct pktq *pq, int prec)
 {
-       return pq->q[prec].max - pq->q[prec].len;
+       return pq->q[prec].max - pq->q[prec].skblist.qlen;
 }
 
 static inline bool pktq_pfull(struct pktq *pq, int prec)
 {
-       return pq->q[prec].len >= pq->q[prec].max;
+       return pq->q[prec].skblist.qlen >= pq->q[prec].max;
 }
 
 static inline bool pktq_pempty(struct pktq *pq, int prec)
 {
-       return pq->q[prec].len == 0;
+       return skb_queue_empty(&pq->q[prec].skblist);
 }
 
 static inline struct sk_buff *pktq_ppeek(struct pktq *pq, int prec)
 {
-       return pq->q[prec].head;
+       return skb_peek(&pq->q[prec].skblist);
 }
 
 static inline struct sk_buff *pktq_ppeek_tail(struct pktq *pq, int prec)
 {
-       return pq->q[prec].tail;
+       return skb_peek_tail(&pq->q[prec].skblist);
 }
 
 extern struct sk_buff *brcmu_pktq_penq(struct pktq *pq, int prec,
@@ -172,24 +170,16 @@ extern void brcmu_pktq_flush(struct pktq *pq, bool dir,
                bool (*fn)(struct sk_buff *, void *), void *arg);
 
 /* externs */
-/* packet */
-extern uint brcmu_pktfrombuf(struct sk_buff *p,
-       uint offset, int len, unsigned char *buf);
-extern uint brcmu_pkttotlen(struct sk_buff *p);
-
 /* ip address */
 struct ipv4_addr;
 
+
+/* externs */
+/* format/print */
 #ifdef BCMDBG
 extern void brcmu_prpkt(const char *msg, struct sk_buff *p0);
 #else
 #define brcmu_prpkt(a, b)
 #endif                         /* BCMDBG */
 
-/* externs */
-/* format/print */
-#if defined(BCMDBG)
-extern int brcmu_format_hex(char *str, const void *bytes, int len);
-#endif
-
 #endif                         /* _BRCMU_UTILS_H_ */
index 1e5f310..f0d8c04 100644 (file)
@@ -62,7 +62,6 @@
 
 #define WL_RADIO_SW_DISABLE            (1<<0)
 #define WL_RADIO_HW_DISABLE            (1<<1)
-#define WL_RADIO_MPC_DISABLE           (1<<2)
 /* some countries don't support any channel */
 #define WL_RADIO_COUNTRY_DISABLE       (1<<3)
 
index 4fcb956..4e9b7e4 100644 (file)
@@ -77,8 +77,9 @@
 #define        DMEMS_CORE_ID           0x835   /* SDR/DDR1 memory controller core */
 #define        DEF_SHIM_COMP           0x837   /* SHIM component in ubus/6362 */
 #define OOB_ROUTER_CORE_ID     0x367   /* OOB router core ID */
-/* Default component, in ai chips it maps all unused address ranges */
-#define        DEF_AI_COMP             0xfff
+#define        DEF_AI_COMP             0xfff   /* Default component, in ai chips it
+                                        * maps all unused address ranges
+                                        */
 
 /* Common core control flags */
 #define        SICF_BIST_EN            0x8000
 #define        SICF_FGC                0x0002
 #define        SICF_CLOCK_EN           0x0001
 
+/* Common core status flags */
+#define        SISF_BIST_DONE          0x8000
+#define        SISF_BIST_ERROR         0x4000
+#define        SISF_GATED_CLK          0x2000
+#define        SISF_DMA64              0x1000
+#define        SISF_CORE_BITS          0x0fff
+
 #endif                         /* _BRCM_SOC_H */
index 99a710d..9957588 100644 (file)
@@ -131,6 +131,14 @@ static struct ieee80211_rate ipw2200_rates[] = {
 #define ipw2200_bg_rates       (ipw2200_rates + 0)
 #define ipw2200_num_bg_rates   12
 
+/* Ugly macro to convert literal channel numbers into their mhz equivalents
+ * There are certianly some conditions that will break this (like feeding it '30')
+ * but they shouldn't arise since nothing talks on channel 30. */
+#define ieee80211chan2mhz(x) \
+       (((x) <= 14) ? \
+       (((x) == 14) ? 2484 : ((x) * 5) + 2407) : \
+       ((x) + 1000) * 5)
+
 #ifdef CONFIG_IPW2200_QOS
 static int qos_enable = 0;
 static int qos_burst_enable = 0;
index 70f5586..3d5821e 100644 (file)
@@ -66,16 +66,8 @@ extern u32 libipw_debug_level;
 do { if (libipw_debug_level & (level)) \
   printk(KERN_DEBUG "libipw: %c %s " fmt, \
          in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0)
-static inline bool libipw_ratelimit_debug(u32 level)
-{
-       return (libipw_debug_level & level) && net_ratelimit();
-}
 #else
 #define LIBIPW_DEBUG(level, fmt, args...) do {} while (0)
-static inline bool libipw_ratelimit_debug(u32 level)
-{
-       return false;
-}
 #endif                         /* CONFIG_LIBIPW_DEBUG */
 
 /*
index c73e5ed..a7ab280 100644 (file)
@@ -1,6 +1,6 @@
 # WIFI
 obj-$(CONFIG_IWLWIFI)  += iwlwifi.o
-iwlwifi-objs           := iwl-agn.o iwl-agn-rs.o
+iwlwifi-objs           := iwl-agn.o iwl-agn-rs.o iwl-mac80211.o
 iwlwifi-objs           += iwl-agn-ucode.o iwl-agn-tx.o
 iwlwifi-objs           += iwl-agn-lib.o iwl-agn-calib.o iwl-io.o
 iwlwifi-objs           += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-rx.o
index 7943197..b319357 100644 (file)
@@ -270,11 +270,6 @@ struct iwl_cfg iwl2000_2bgn_cfg = {
        .ht_params = &iwl2000_ht_params,
 };
 
-struct iwl_cfg iwl2000_2bg_cfg = {
-       .name = "2000 Series 2x2 BG",
-       IWL_DEVICE_2000,
-};
-
 struct iwl_cfg iwl2000_2bgn_d_cfg = {
        .name = "2000D Series 2x2 BGN",
        IWL_DEVICE_2000,
@@ -304,11 +299,6 @@ struct iwl_cfg iwl2030_2bgn_cfg = {
        .ht_params = &iwl2000_ht_params,
 };
 
-struct iwl_cfg iwl2030_2bg_cfg = {
-       .name = "2000 Series 2x2 BG/BT",
-       IWL_DEVICE_2030,
-};
-
 #define IWL_DEVICE_105                                         \
        .fw_name_pre = IWL105_FW_PRE,                           \
        .ucode_api_max = IWL105_UCODE_API_MAX,                  \
@@ -326,11 +316,6 @@ struct iwl_cfg iwl2030_2bg_cfg = {
        .rx_with_siso_diversity = true,                         \
        .iq_invert = true                                       \
 
-struct iwl_cfg iwl105_bg_cfg = {
-       .name = "105 Series 1x1 BG",
-       IWL_DEVICE_105,
-};
-
 struct iwl_cfg iwl105_bgn_cfg = {
        .name = "105 Series 1x1 BGN",
        IWL_DEVICE_105,
@@ -361,11 +346,6 @@ struct iwl_cfg iwl105_bgn_d_cfg = {
        .rx_with_siso_diversity = true,                         \
        .iq_invert = true                                       \
 
-struct iwl_cfg iwl135_bg_cfg = {
-       .name = "135 Series 1x1 BG/BT",
-       IWL_DEVICE_135,
-};
-
 struct iwl_cfg iwl135_bgn_cfg = {
        .name = "135 Series 1x1 BGN/BT",
        IWL_DEVICE_135,
index c840c78..ee3363f 100644 (file)
@@ -439,16 +439,6 @@ struct iwl_cfg iwl6035_2agn_cfg = {
        .ht_params = &iwl6000_ht_params,
 };
 
-struct iwl_cfg iwl6035_2abg_cfg = {
-       .name = "6035 Series 2x2 ABG/BT",
-       IWL_DEVICE_6030,
-};
-
-struct iwl_cfg iwl6035_2bg_cfg = {
-       .name = "6035 Series 2x2 BG/BT",
-       IWL_DEVICE_6030,
-};
-
 struct iwl_cfg iwl1030_bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 1030 BGN",
        IWL_DEVICE_6030,
index 1a52ed2..0bc9622 100644 (file)
@@ -827,6 +827,7 @@ static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt)
        case IEEE80211_SMPS_STATIC:
        case IEEE80211_SMPS_DYNAMIC:
                return IWL_NUM_IDLE_CHAINS_SINGLE;
+       case IEEE80211_SMPS_AUTOMATIC:
        case IEEE80211_SMPS_OFF:
                return active_cnt;
        default:
@@ -983,3 +984,360 @@ void iwlagn_remove_notification(struct iwl_priv *priv,
        list_del(&wait_entry->list);
        spin_unlock_bh(&priv->notif_wait_lock);
 }
+
+#ifdef CONFIG_PM_SLEEP
+static void iwlagn_convert_p1k(u16 *p1k, __le16 *out)
+{
+       int i;
+
+       for (i = 0; i < IWLAGN_P1K_SIZE; i++)
+               out[i] = cpu_to_le16(p1k[i]);
+}
+
+struct wowlan_key_data {
+       struct iwl_rxon_context *ctx;
+       struct iwlagn_wowlan_rsc_tsc_params_cmd *rsc_tsc;
+       struct iwlagn_wowlan_tkip_params_cmd *tkip;
+       const u8 *bssid;
+       bool error, use_rsc_tsc, use_tkip;
+};
+
+
+static void iwlagn_wowlan_program_keys(struct ieee80211_hw *hw,
+                              struct ieee80211_vif *vif,
+                              struct ieee80211_sta *sta,
+                              struct ieee80211_key_conf *key,
+                              void *_data)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct wowlan_key_data *data = _data;
+       struct iwl_rxon_context *ctx = data->ctx;
+       struct aes_sc *aes_sc, *aes_tx_sc = NULL;
+       struct tkip_sc *tkip_sc, *tkip_tx_sc = NULL;
+       struct iwlagn_p1k_cache *rx_p1ks;
+       u8 *rx_mic_key;
+       struct ieee80211_key_seq seq;
+       u32 cur_rx_iv32 = 0;
+       u16 p1k[IWLAGN_P1K_SIZE];
+       int ret, i;
+
+       mutex_lock(&priv->shrd->mutex);
+
+       if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
+            key->cipher == WLAN_CIPHER_SUITE_WEP104) &&
+            !sta && !ctx->key_mapping_keys)
+               ret = iwl_set_default_wep_key(priv, ctx, key);
+       else
+               ret = iwl_set_dynamic_key(priv, ctx, key, sta);
+
+       if (ret) {
+               IWL_ERR(priv, "Error setting key during suspend!\n");
+               data->error = true;
+       }
+
+       switch (key->cipher) {
+       case WLAN_CIPHER_SUITE_TKIP:
+               if (sta) {
+                       tkip_sc = data->rsc_tsc->all_tsc_rsc.tkip.unicast_rsc;
+                       tkip_tx_sc = &data->rsc_tsc->all_tsc_rsc.tkip.tsc;
+
+                       rx_p1ks = data->tkip->rx_uni;
+
+                       ieee80211_get_key_tx_seq(key, &seq);
+                       tkip_tx_sc->iv16 = cpu_to_le16(seq.tkip.iv16);
+                       tkip_tx_sc->iv32 = cpu_to_le32(seq.tkip.iv32);
+
+                       ieee80211_get_tkip_p1k_iv(key, seq.tkip.iv32, p1k);
+                       iwlagn_convert_p1k(p1k, data->tkip->tx.p1k);
+
+                       memcpy(data->tkip->mic_keys.tx,
+                              &key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY],
+                              IWLAGN_MIC_KEY_SIZE);
+
+                       rx_mic_key = data->tkip->mic_keys.rx_unicast;
+               } else {
+                       tkip_sc =
+                               data->rsc_tsc->all_tsc_rsc.tkip.multicast_rsc;
+                       rx_p1ks = data->tkip->rx_multi;
+                       rx_mic_key = data->tkip->mic_keys.rx_mcast;
+               }
+
+               /*
+                * For non-QoS this relies on the fact that both the uCode and
+                * mac80211 use TID 0 (as they need to to avoid replay attacks)
+                * for checking the IV in the frames.
+                */
+               for (i = 0; i < IWLAGN_NUM_RSC; i++) {
+                       ieee80211_get_key_rx_seq(key, i, &seq);
+                       tkip_sc[i].iv16 = cpu_to_le16(seq.tkip.iv16);
+                       tkip_sc[i].iv32 = cpu_to_le32(seq.tkip.iv32);
+                       /* wrapping isn't allowed, AP must rekey */
+                       if (seq.tkip.iv32 > cur_rx_iv32)
+                               cur_rx_iv32 = seq.tkip.iv32;
+               }
+
+               ieee80211_get_tkip_rx_p1k(key, data->bssid, cur_rx_iv32, p1k);
+               iwlagn_convert_p1k(p1k, rx_p1ks[0].p1k);
+               ieee80211_get_tkip_rx_p1k(key, data->bssid,
+                                         cur_rx_iv32 + 1, p1k);
+               iwlagn_convert_p1k(p1k, rx_p1ks[1].p1k);
+
+               memcpy(rx_mic_key,
+                      &key->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY],
+                      IWLAGN_MIC_KEY_SIZE);
+
+               data->use_tkip = true;
+               data->use_rsc_tsc = true;
+               break;
+       case WLAN_CIPHER_SUITE_CCMP:
+               if (sta) {
+                       u8 *pn = seq.ccmp.pn;
+
+                       aes_sc = data->rsc_tsc->all_tsc_rsc.aes.unicast_rsc;
+                       aes_tx_sc = &data->rsc_tsc->all_tsc_rsc.aes.tsc;
+
+                       ieee80211_get_key_tx_seq(key, &seq);
+                       aes_tx_sc->pn = cpu_to_le64(
+                                       (u64)pn[5] |
+                                       ((u64)pn[4] << 8) |
+                                       ((u64)pn[3] << 16) |
+                                       ((u64)pn[2] << 24) |
+                                       ((u64)pn[1] << 32) |
+                                       ((u64)pn[0] << 40));
+               } else
+                       aes_sc = data->rsc_tsc->all_tsc_rsc.aes.multicast_rsc;
+
+               /*
+                * For non-QoS this relies on the fact that both the uCode and
+                * mac80211 use TID 0 for checking the IV in the frames.
+                */
+               for (i = 0; i < IWLAGN_NUM_RSC; i++) {
+                       u8 *pn = seq.ccmp.pn;
+
+                       ieee80211_get_key_rx_seq(key, i, &seq);
+                       aes_sc->pn = cpu_to_le64(
+                                       (u64)pn[5] |
+                                       ((u64)pn[4] << 8) |
+                                       ((u64)pn[3] << 16) |
+                                       ((u64)pn[2] << 24) |
+                                       ((u64)pn[1] << 32) |
+                                       ((u64)pn[0] << 40));
+               }
+               data->use_rsc_tsc = true;
+               break;
+       }
+
+       mutex_unlock(&priv->shrd->mutex);
+}
+
+int iwlagn_send_patterns(struct iwl_priv *priv,
+                       struct cfg80211_wowlan *wowlan)
+{
+       struct iwlagn_wowlan_patterns_cmd *pattern_cmd;
+       struct iwl_host_cmd cmd = {
+               .id = REPLY_WOWLAN_PATTERNS,
+               .dataflags[0] = IWL_HCMD_DFL_NOCOPY,
+               .flags = CMD_SYNC,
+       };
+       int i, err;
+
+       if (!wowlan->n_patterns)
+               return 0;
+
+       cmd.len[0] = sizeof(*pattern_cmd) +
+               wowlan->n_patterns * sizeof(struct iwlagn_wowlan_pattern);
+
+       pattern_cmd = kmalloc(cmd.len[0], GFP_KERNEL);
+       if (!pattern_cmd)
+               return -ENOMEM;
+
+       pattern_cmd->n_patterns = cpu_to_le32(wowlan->n_patterns);
+
+       for (i = 0; i < wowlan->n_patterns; i++) {
+               int mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8);
+
+               memcpy(&pattern_cmd->patterns[i].mask,
+                       wowlan->patterns[i].mask, mask_len);
+               memcpy(&pattern_cmd->patterns[i].pattern,
+                       wowlan->patterns[i].pattern,
+                       wowlan->patterns[i].pattern_len);
+               pattern_cmd->patterns[i].mask_size = mask_len;
+               pattern_cmd->patterns[i].pattern_size =
+                       wowlan->patterns[i].pattern_len;
+       }
+
+       cmd.data[0] = pattern_cmd;
+       err = iwl_trans_send_cmd(trans(priv), &cmd);
+       kfree(pattern_cmd);
+       return err;
+}
+
+int iwlagn_suspend(struct iwl_priv *priv,
+               struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
+{
+       struct iwlagn_wowlan_wakeup_filter_cmd wakeup_filter_cmd;
+       struct iwl_rxon_cmd rxon;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+       struct iwlagn_wowlan_kek_kck_material_cmd kek_kck_cmd;
+       struct iwlagn_wowlan_tkip_params_cmd tkip_cmd = {};
+       struct iwlagn_d3_config_cmd d3_cfg_cmd = {};
+       struct wowlan_key_data key_data = {
+               .ctx = ctx,
+               .bssid = ctx->active.bssid_addr,
+               .use_rsc_tsc = false,
+               .tkip = &tkip_cmd,
+               .use_tkip = false,
+       };
+       int ret, i;
+       u16 seq;
+
+       key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL);
+       if (!key_data.rsc_tsc)
+               return -ENOMEM;
+
+       memset(&wakeup_filter_cmd, 0, sizeof(wakeup_filter_cmd));
+
+       /*
+        * We know the last used seqno, and the uCode expects to know that
+        * one, it will increment before TX.
+        */
+       seq = le16_to_cpu(priv->last_seq_ctl) & IEEE80211_SCTL_SEQ;
+       wakeup_filter_cmd.non_qos_seq = cpu_to_le16(seq);
+
+       /*
+        * For QoS counters, we store the one to use next, so subtract 0x10
+        * since the uCode will add 0x10 before using the value.
+        */
+       for (i = 0; i < 8; i++) {
+               seq = priv->shrd->tid_data[IWL_AP_ID][i].seq_number;
+               seq -= 0x10;
+               wakeup_filter_cmd.qos_seq[i] = cpu_to_le16(seq);
+       }
+
+       if (wowlan->disconnect)
+               wakeup_filter_cmd.enabled |=
+                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_BEACON_MISS |
+                                   IWLAGN_WOWLAN_WAKEUP_LINK_CHANGE);
+       if (wowlan->magic_pkt)
+               wakeup_filter_cmd.enabled |=
+                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_MAGIC_PACKET);
+       if (wowlan->gtk_rekey_failure)
+               wakeup_filter_cmd.enabled |=
+                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_GTK_REKEY_FAIL);
+       if (wowlan->eap_identity_req)
+               wakeup_filter_cmd.enabled |=
+                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_EAP_IDENT_REQ);
+       if (wowlan->four_way_handshake)
+               wakeup_filter_cmd.enabled |=
+                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_4WAY_HANDSHAKE);
+       if (wowlan->n_patterns)
+               wakeup_filter_cmd.enabled |=
+                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_PATTERN_MATCH);
+
+       if (wowlan->rfkill_release)
+               d3_cfg_cmd.wakeup_flags |=
+                       cpu_to_le32(IWLAGN_D3_WAKEUP_RFKILL);
+
+       iwl_scan_cancel_timeout(priv, 200);
+
+       memcpy(&rxon, &ctx->active, sizeof(rxon));
+
+       iwl_trans_stop_device(trans(priv));
+
+       priv->shrd->wowlan = true;
+
+       ret = iwlagn_load_ucode_wait_alive(priv, IWL_UCODE_WOWLAN);
+       if (ret)
+               goto out;
+
+       /* now configure WoWLAN ucode */
+       ret = iwl_alive_start(priv);
+       if (ret)
+               goto out;
+
+       memcpy(&ctx->staging, &rxon, sizeof(rxon));
+       ret = iwlagn_commit_rxon(priv, ctx);
+       if (ret)
+               goto out;
+
+       ret = iwl_power_update_mode(priv, true);
+       if (ret)
+               goto out;
+
+       if (!iwlagn_mod_params.sw_crypto) {
+               /* mark all keys clear */
+               priv->ucode_key_table = 0;
+               ctx->key_mapping_keys = 0;
+
+               /*
+                * This needs to be unlocked due to lock ordering
+                * constraints. Since we're in the suspend path
+                * that isn't really a problem though.
+                */
+               mutex_unlock(&priv->shrd->mutex);
+               ieee80211_iter_keys(priv->hw, ctx->vif,
+                                   iwlagn_wowlan_program_keys,
+                                   &key_data);
+               mutex_lock(&priv->shrd->mutex);
+               if (key_data.error) {
+                       ret = -EIO;
+                       goto out;
+               }
+
+               if (key_data.use_rsc_tsc) {
+                       struct iwl_host_cmd rsc_tsc_cmd = {
+                               .id = REPLY_WOWLAN_TSC_RSC_PARAMS,
+                               .flags = CMD_SYNC,
+                               .data[0] = key_data.rsc_tsc,
+                               .dataflags[0] = IWL_HCMD_DFL_NOCOPY,
+                               .len[0] = sizeof(key_data.rsc_tsc),
+                       };
+
+                       ret = iwl_trans_send_cmd(trans(priv), &rsc_tsc_cmd);
+                       if (ret)
+                               goto out;
+               }
+
+               if (key_data.use_tkip) {
+                       ret = iwl_trans_send_cmd_pdu(trans(priv),
+                                                REPLY_WOWLAN_TKIP_PARAMS,
+                                                CMD_SYNC, sizeof(tkip_cmd),
+                                                &tkip_cmd);
+                       if (ret)
+                               goto out;
+               }
+
+               if (priv->have_rekey_data) {
+                       memset(&kek_kck_cmd, 0, sizeof(kek_kck_cmd));
+                       memcpy(kek_kck_cmd.kck, priv->kck, NL80211_KCK_LEN);
+                       kek_kck_cmd.kck_len = cpu_to_le16(NL80211_KCK_LEN);
+                       memcpy(kek_kck_cmd.kek, priv->kek, NL80211_KEK_LEN);
+                       kek_kck_cmd.kek_len = cpu_to_le16(NL80211_KEK_LEN);
+                       kek_kck_cmd.replay_ctr = priv->replay_ctr;
+
+                       ret = iwl_trans_send_cmd_pdu(trans(priv),
+                                                REPLY_WOWLAN_KEK_KCK_MATERIAL,
+                                                CMD_SYNC, sizeof(kek_kck_cmd),
+                                                &kek_kck_cmd);
+                       if (ret)
+                               goto out;
+               }
+       }
+
+       ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_D3_CONFIG, CMD_SYNC,
+                                    sizeof(d3_cfg_cmd), &d3_cfg_cmd);
+       if (ret)
+               goto out;
+
+       ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_WOWLAN_WAKEUP_FILTER,
+                                CMD_SYNC, sizeof(wakeup_filter_cmd),
+                                &wakeup_filter_cmd);
+       if (ret)
+               goto out;
+
+       ret = iwlagn_send_patterns(priv, wowlan);
+ out:
+       kfree(key_data.rsc_tsc);
+       return ret;
+}
+#endif
index 66118ce..359c47a 100644 (file)
@@ -1458,10 +1458,8 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
                break;
        case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
                /* avoid antenna B unless MIMO */
-               valid_tx_ant =
-                       first_antenna(hw_params(priv).valid_tx_ant);
                if (tbl->action == IWL_LEGACY_SWITCH_ANTENNA2)
-                       tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
+                       tbl->action = IWL_LEGACY_SWITCH_SISO;
                break;
        case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
        case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
@@ -1636,10 +1634,8 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
                break;
        case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
                /* avoid antenna B unless MIMO */
-               valid_tx_ant =
-                       first_antenna(hw_params(priv).valid_tx_ant);
                if (tbl->action == IWL_SISO_SWITCH_ANTENNA2)
-                       tbl->action = IWL_SISO_SWITCH_ANTENNA1;
+                       tbl->action = IWL_SISO_SWITCH_MIMO2_AB;
                break;
        case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
        case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
index 5af9e62..fdb4c37 100644 (file)
@@ -800,7 +800,8 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv,
                                               ctx->active.bssid_addr))
                                continue;
                        ctx->last_tx_rejected = false;
-                       iwl_trans_wake_any_queue(trans(priv), ctx->ctxid);
+                       iwl_trans_wake_any_queue(trans(priv), ctx->ctxid,
+                               "channel got active");
                }
        }
 
@@ -1032,6 +1033,50 @@ static int iwlagn_rx_reply_rx(struct iwl_priv *priv,
        return 0;
 }
 
+static int iwlagn_rx_noa_notification(struct iwl_priv *priv,
+                                     struct iwl_rx_mem_buffer *rxb,
+                                     struct iwl_device_cmd *cmd)
+{
+       struct iwl_wipan_noa_data *new_data, *old_data;
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_wipan_noa_notification *noa_notif = (void *)pkt->u.raw;
+
+       /* no condition -- we're in softirq */
+       old_data = rcu_dereference_protected(priv->noa_data, true);
+
+       if (noa_notif->noa_active) {
+               u32 len = le16_to_cpu(noa_notif->noa_attribute.length);
+               u32 copylen = len;
+
+               /* EID, len, OUI, subtype */
+               len += 1 + 1 + 3 + 1;
+               /* P2P id, P2P length */
+               len += 1 + 2;
+               copylen += 1 + 2;
+
+               new_data = kmalloc(sizeof(*new_data) + len, GFP_ATOMIC);
+               if (new_data) {
+                       new_data->length = len;
+                       new_data->data[0] = WLAN_EID_VENDOR_SPECIFIC;
+                       new_data->data[1] = len - 2; /* not counting EID, len */
+                       new_data->data[2] = (WLAN_OUI_WFA >> 16) & 0xff;
+                       new_data->data[3] = (WLAN_OUI_WFA >> 8) & 0xff;
+                       new_data->data[4] = (WLAN_OUI_WFA >> 0) & 0xff;
+                       new_data->data[5] = WLAN_OUI_TYPE_WFA_P2P;
+                       memcpy(&new_data->data[6], &noa_notif->noa_attribute,
+                              copylen);
+               }
+       } else
+               new_data = NULL;
+
+       rcu_assign_pointer(priv->noa_data, new_data);
+
+       if (old_data)
+               kfree_rcu(old_data, rcu_head);
+
+       return 0;
+}
+
 /**
  * iwl_setup_rx_handlers - Initialize Rx handler callbacks
  *
@@ -1055,6 +1100,8 @@ void iwl_setup_rx_handlers(struct iwl_priv *priv)
        handlers[BEACON_NOTIFICATION]           = iwlagn_rx_beacon_notif;
        handlers[REPLY_ADD_STA]                 = iwl_add_sta_callback;
 
+       handlers[REPLY_WIPAN_NOA_NOTIFICATION]  = iwlagn_rx_noa_notification;
+
        /*
         * The same handler is used for both the REPLY to a discrete
         * statistics request from the host as well as for the periodic
index 58a381c..8de97f5 100644 (file)
@@ -45,7 +45,8 @@ static int iwlagn_disable_bss(struct iwl_priv *priv,
        send->filter_flags = old_filter;
 
        if (ret)
-               IWL_ERR(priv, "Error clearing ASSOC_MSK on BSS (%d)\n", ret);
+               IWL_DEBUG_QUIET_RFKILL(priv,
+                       "Error clearing ASSOC_MSK on BSS (%d)\n", ret);
 
        return ret;
 }
@@ -116,7 +117,7 @@ static void iwlagn_update_qos(struct iwl_priv *priv,
        if (ctx->ht.enabled)
                ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;
 
-       IWL_DEBUG_QOS(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n",
+       IWL_DEBUG_INFO(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n",
                      ctx->qos_data.qos_active,
                      ctx->qos_data.def_qos_parm.qos_flags);
 
@@ -124,7 +125,7 @@ static void iwlagn_update_qos(struct iwl_priv *priv,
                               sizeof(struct iwl_qosparam_cmd),
                               &ctx->qos_data.def_qos_parm);
        if (ret)
-               IWL_ERR(priv, "Failed to update QoS\n");
+               IWL_DEBUG_QUIET_RFKILL(priv, "Failed to update QoS\n");
 }
 
 static int iwlagn_update_beacon(struct iwl_priv *priv,
@@ -541,6 +542,9 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
 
        mutex_lock(&priv->shrd->mutex);
 
+       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
+               goto out;
+
        if (unlikely(test_bit(STATUS_SCANNING, &priv->shrd->status))) {
                IWL_DEBUG_MAC80211(priv, "leave - scanning\n");
                goto out;
@@ -840,7 +844,8 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
                        if (ctx->last_tx_rejected) {
                                ctx->last_tx_rejected = false;
                                iwl_trans_wake_any_queue(trans(priv),
-                                                        ctx->ctxid);
+                                                        ctx->ctxid,
+                                                        "Disassoc: flush queue");
                        }
                        ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 
index ed62836..901fd94 100644 (file)
@@ -647,7 +647,7 @@ void iwl_reprogram_ap_sta(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
        int ret;
        struct iwl_addsta_cmd sta_cmd;
        struct iwl_link_quality_cmd lq;
-       bool active;
+       bool active, have_lq = false;
 
        spin_lock_irqsave(&priv->shrd->sta_lock, flags);
        if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) {
@@ -657,7 +657,10 @@ void iwl_reprogram_ap_sta(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
 
        memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(sta_cmd));
        sta_cmd.mode = 0;
-       memcpy(&lq, priv->stations[sta_id].lq, sizeof(lq));
+       if (priv->stations[sta_id].lq) {
+               memcpy(&lq, priv->stations[sta_id].lq, sizeof(lq));
+               have_lq = true;
+       }
 
        active = priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE;
        priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
@@ -679,7 +682,8 @@ void iwl_reprogram_ap_sta(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
        if (ret)
                IWL_ERR(priv, "failed to re-add STA %pM (%d)\n",
                        priv->stations[sta_id].sta.sta.addr, ret);
-       iwl_send_lq_cmd(priv, ctx, &lq, CMD_SYNC, true);
+       if (have_lq)
+               iwl_send_lq_cmd(priv, ctx, &lq, CMD_SYNC, true);
 }
 
 int iwl_get_free_ucode_key_offset(struct iwl_priv *priv)
@@ -825,28 +829,6 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
        return ret;
 }
 
-int iwlagn_mac_sta_remove(struct ieee80211_hw *hw,
-                      struct ieee80211_vif *vif,
-                      struct ieee80211_sta *sta)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
-       int ret;
-
-       IWL_DEBUG_MAC80211(priv, "enter: received request to remove "
-                          "station %pM\n", sta->addr);
-       mutex_lock(&priv->shrd->mutex);
-       IWL_DEBUG_INFO(priv, "proceeding to remove station %pM\n",
-                       sta->addr);
-       ret = iwl_remove_station(priv, sta_priv->sta_id, sta->addr);
-       if (ret)
-               IWL_ERR(priv, "Error removing station %pM\n",
-                       sta->addr);
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       return ret;
-}
 
 void iwl_sta_fill_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
                     u8 sta_id, struct iwl_link_quality_cmd *link_cmd)
@@ -1464,20 +1446,7 @@ int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta,
        return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
 }
 
-static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
-{
-       unsigned long flags;
 
-       spin_lock_irqsave(&priv->shrd->sta_lock, flags);
-       priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK;
-       priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK;
-       priv->stations[sta_id].sta.sta.modify_mask = 0;
-       priv->stations[sta_id].sta.sleep_tx_count = 0;
-       priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
-       iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
-       spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
-
-}
 
 void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt)
 {
@@ -1494,36 +1463,3 @@ void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt)
        spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
 
 }
-
-void iwlagn_mac_sta_notify(struct ieee80211_hw *hw,
-                          struct ieee80211_vif *vif,
-                          enum sta_notify_cmd cmd,
-                          struct ieee80211_sta *sta)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
-       int sta_id;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-
-       switch (cmd) {
-       case STA_NOTIFY_SLEEP:
-               WARN_ON(!sta_priv->client);
-               sta_priv->asleep = true;
-               if (atomic_read(&sta_priv->pending_frames) > 0)
-                       ieee80211_sta_block_awake(hw, sta, true);
-               break;
-       case STA_NOTIFY_AWAKE:
-               WARN_ON(!sta_priv->client);
-               if (!sta_priv->asleep)
-                       break;
-               sta_priv->asleep = false;
-               sta_id = iwl_sta_id(sta);
-               if (sta_id != IWL_INVALID_STATION)
-                       iwl_sta_modify_ps_wake(priv, sta_id);
-               break;
-       default:
-               break;
-       }
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-}
index 35a6b71..e6a02e0 100644 (file)
@@ -283,6 +283,19 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
                IWL_DEBUG_TX(priv, "Sending REASSOC frame\n");
 #endif
 
+       if (unlikely(ieee80211_is_probe_resp(fc))) {
+               struct iwl_wipan_noa_data *noa_data =
+                       rcu_dereference(priv->noa_data);
+
+               if (noa_data &&
+                   pskb_expand_head(skb, 0, noa_data->length,
+                                    GFP_ATOMIC) == 0) {
+                       memcpy(skb_put(skb, noa_data->length),
+                              noa_data->data, noa_data->length);
+                       hdr = (struct ieee80211_hdr *)skb->data;
+               }
+       }
+
        hdr_len = ieee80211_hdrlen(fc);
 
        /* For management frames use broadcast id to do not break aggregation */
@@ -800,7 +813,8 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
                            iwl_is_associated_ctx(ctx) && ctx->vif &&
                            ctx->vif->type == NL80211_IFTYPE_STATION) {
                                ctx->last_tx_rejected = true;
-                               iwl_trans_stop_queue(trans(priv), txq_id);
+                               iwl_trans_stop_queue(trans(priv), txq_id,
+                                       "Tx on passive channel");
 
                                IWL_DEBUG_TX_REPLY(priv,
                                           "TXQ %d status %s (0x%08x) "
index 8ba0dd5..9ec315b 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/sched.h>
+#include <linux/dma-mapping.h>
 
 #include "iwl-dev.h"
 #include "iwl-core.h"
@@ -72,51 +73,98 @@ static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = {
        {COEX_CU_RSRVD2_RP, COEX_CU_RSRVD2_WP, 0, COEX_RSRVD2_FLAGS}
 };
 
+/******************************************************************************
+ *
+ * uCode download functions
+ *
+ ******************************************************************************/
+
+static void iwl_free_fw_desc(struct iwl_bus *bus, struct fw_desc *desc)
+{
+       if (desc->v_addr)
+               dma_free_coherent(bus->dev, desc->len,
+                                 desc->v_addr, desc->p_addr);
+       desc->v_addr = NULL;
+       desc->len = 0;
+}
+
+static void iwl_free_fw_img(struct iwl_bus *bus, struct fw_img *img)
+{
+       iwl_free_fw_desc(bus, &img->code);
+       iwl_free_fw_desc(bus, &img->data);
+}
+
+void iwl_dealloc_ucode(struct iwl_trans *trans)
+{
+       iwl_free_fw_img(bus(trans), &trans->ucode_rt);
+       iwl_free_fw_img(bus(trans), &trans->ucode_init);
+       iwl_free_fw_img(bus(trans), &trans->ucode_wowlan);
+}
+
+int iwl_alloc_fw_desc(struct iwl_bus *bus, struct fw_desc *desc,
+                     const void *data, size_t len)
+{
+       if (!len) {
+               desc->v_addr = NULL;
+               return -EINVAL;
+       }
+
+       desc->v_addr = dma_alloc_coherent(bus->dev, len,
+                                         &desc->p_addr, GFP_KERNEL);
+       if (!desc->v_addr)
+               return -ENOMEM;
+
+       desc->len = len;
+       memcpy(desc->v_addr, data, len);
+       return 0;
+}
+
 /*
  * ucode
  */
-static int iwlagn_load_section(struct iwl_priv *priv, const char *name,
+static int iwlagn_load_section(struct iwl_trans *trans, const char *name,
                                struct fw_desc *image, u32 dst_addr)
 {
+       struct iwl_bus *bus = bus(trans);
        dma_addr_t phy_addr = image->p_addr;
        u32 byte_cnt = image->len;
        int ret;
 
-       priv->ucode_write_complete = 0;
+       trans->ucode_write_complete = 0;
 
-       iwl_write_direct32(bus(priv),
+       iwl_write_direct32(bus,
                FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
                FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE);
 
-       iwl_write_direct32(bus(priv),
+       iwl_write_direct32(bus,
                FH_SRVC_CHNL_SRAM_ADDR_REG(FH_SRVC_CHNL), dst_addr);
 
-       iwl_write_direct32(bus(priv),
+       iwl_write_direct32(bus,
                FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL),
                phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK);
 
-       iwl_write_direct32(bus(priv),
+       iwl_write_direct32(bus,
                FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL),
                (iwl_get_dma_hi_addr(phy_addr)
                        << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt);
 
-       iwl_write_direct32(bus(priv),
+       iwl_write_direct32(bus,
                FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL),
                1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM |
                1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX |
                FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID);
 
-       iwl_write_direct32(bus(priv),
+       iwl_write_direct32(bus,
                FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
                FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE       |
                FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE    |
                FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
 
-       IWL_DEBUG_FW(priv, "%s uCode section being loaded...\n", name);
-       ret = wait_event_timeout(priv->shrd->wait_command_queue,
-                                priv->ucode_write_complete, 5 * HZ);
+       IWL_DEBUG_FW(bus, "%s uCode section being loaded...\n", name);
+       ret = wait_event_timeout(trans->shrd->wait_command_queue,
+                                trans->ucode_write_complete, 5 * HZ);
        if (!ret) {
-               IWL_ERR(priv, "Could not load the %s uCode section\n",
+               IWL_ERR(trans, "Could not load the %s uCode section\n",
                        name);
                return -ETIMEDOUT;
        }
@@ -124,17 +172,41 @@ static int iwlagn_load_section(struct iwl_priv *priv, const char *name,
        return 0;
 }
 
-static int iwlagn_load_given_ucode(struct iwl_priv *priv,
-                                  struct fw_img *image)
+static inline struct fw_img *iwl_get_ucode_image(struct iwl_trans *trans,
+                                       enum iwl_ucode_type ucode_type)
+{
+       switch (ucode_type) {
+       case IWL_UCODE_INIT:
+               return &trans->ucode_init;
+       case IWL_UCODE_WOWLAN:
+               return &trans->ucode_wowlan;
+       case IWL_UCODE_REGULAR:
+               return &trans->ucode_rt;
+       case IWL_UCODE_NONE:
+               break;
+       }
+       return NULL;
+}
+
+static int iwlagn_load_given_ucode(struct iwl_trans *trans,
+                                  enum iwl_ucode_type ucode_type)
 {
        int ret = 0;
+       struct fw_img *image = iwl_get_ucode_image(trans, ucode_type);
+
+
+       if (!image) {
+               IWL_ERR(trans, "Invalid ucode requested (%d)\n",
+                       ucode_type);
+               return -EINVAL;
+       }
 
-       ret = iwlagn_load_section(priv, "INST", &image->code,
+       ret = iwlagn_load_section(trans, "INST", &image->code,
                                   IWLAGN_RTC_INST_LOWER_BOUND);
        if (ret)
                return ret;
 
-       return iwlagn_load_section(priv, "DATA", &image->data,
+       return iwlagn_load_section(trans, "DATA", &image->data,
                                    IWLAGN_RTC_DATA_LOWER_BOUND);
 }
 
@@ -418,7 +490,7 @@ static int iwlagn_alive_notify(struct iwl_priv *priv)
  *   using sample data 100 bytes apart.  If these sample points are good,
  *   it's a pretty good bet that everything between them is good, too.
  */
-static int iwl_verify_inst_sparse(struct iwl_priv *priv,
+static int iwl_verify_inst_sparse(struct iwl_bus *bus,
                                      struct fw_desc *fw_desc)
 {
        __le32 *image = (__le32 *)fw_desc->v_addr;
@@ -426,15 +498,15 @@ static int iwl_verify_inst_sparse(struct iwl_priv *priv,
        u32 val;
        u32 i;
 
-       IWL_DEBUG_FW(priv, "ucode inst image size is %u\n", len);
+       IWL_DEBUG_FW(bus, "ucode inst image size is %u\n", len);
 
        for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) {
                /* read data comes through single port, auto-incr addr */
                /* NOTE: Use the debugless read so we don't flood kernel log
                 * if IWL_DL_IO is set */
-               iwl_write_direct32(bus(priv), HBUS_TARG_MEM_RADDR,
+               iwl_write_direct32(bus, HBUS_TARG_MEM_RADDR,
                        i + IWLAGN_RTC_INST_LOWER_BOUND);
-               val = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT);
+               val = iwl_read32(bus, HBUS_TARG_MEM_RDAT);
                if (val != le32_to_cpu(*image))
                        return -EIO;
        }
@@ -442,7 +514,7 @@ static int iwl_verify_inst_sparse(struct iwl_priv *priv,
        return 0;
 }
 
-static void iwl_print_mismatch_inst(struct iwl_priv *priv,
+static void iwl_print_mismatch_inst(struct iwl_bus *bus,
                                    struct fw_desc *fw_desc)
 {
        __le32 *image = (__le32 *)fw_desc->v_addr;
@@ -451,18 +523,18 @@ static void iwl_print_mismatch_inst(struct iwl_priv *priv,
        u32 offs;
        int errors = 0;
 
-       IWL_DEBUG_FW(priv, "ucode inst image size is %u\n", len);
+       IWL_DEBUG_FW(bus, "ucode inst image size is %u\n", len);
 
-       iwl_write_direct32(bus(priv), HBUS_TARG_MEM_RADDR,
+       iwl_write_direct32(bus, HBUS_TARG_MEM_RADDR,
                           IWLAGN_RTC_INST_LOWER_BOUND);
 
        for (offs = 0;
             offs < len && errors < 20;
             offs += sizeof(u32), image++) {
                /* read data comes through single port, auto-incr addr */
-               val = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT);
+               val = iwl_read32(bus, HBUS_TARG_MEM_RDAT);
                if (val != le32_to_cpu(*image)) {
-                       IWL_ERR(priv, "uCode INST section at "
+                       IWL_ERR(bus, "uCode INST section at "
                                "offset 0x%x, is 0x%x, s/b 0x%x\n",
                                offs, val, le32_to_cpu(*image));
                        errors++;
@@ -474,16 +546,24 @@ static void iwl_print_mismatch_inst(struct iwl_priv *priv,
  * iwl_verify_ucode - determine which instruction image is in SRAM,
  *    and verify its contents
  */
-static int iwl_verify_ucode(struct iwl_priv *priv, struct fw_img *img)
+static int iwl_verify_ucode(struct iwl_trans *trans,
+                           enum iwl_ucode_type ucode_type)
 {
-       if (!iwl_verify_inst_sparse(priv, &img->code)) {
-               IWL_DEBUG_FW(priv, "uCode is good in inst SRAM\n");
+       struct fw_img *img = iwl_get_ucode_image(trans, ucode_type);
+
+       if (!img) {
+               IWL_ERR(trans, "Invalid ucode requested (%d)\n", ucode_type);
+               return -EINVAL;
+       }
+
+       if (!iwl_verify_inst_sparse(bus(trans), &img->code)) {
+               IWL_DEBUG_FW(trans, "uCode is good in inst SRAM\n");
                return 0;
        }
 
-       IWL_ERR(priv, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n");
+       IWL_ERR(trans, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n");
 
-       iwl_print_mismatch_inst(priv, &img->code);
+       iwl_print_mismatch_inst(bus(trans), &img->code);
        return -EIO;
 }
 
@@ -519,13 +599,12 @@ static void iwlagn_alive_fn(struct iwl_priv *priv,
 #define UCODE_CALIB_TIMEOUT    (2*HZ)
 
 int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv,
-                                struct fw_img *image,
-                                enum iwlagn_ucode_type ucode_type)
+                                enum iwl_ucode_type ucode_type)
 {
        struct iwl_notification_wait alive_wait;
        struct iwlagn_alive_data alive_data;
        int ret;
-       enum iwlagn_ucode_type old_type;
+       enum iwl_ucode_type old_type;
 
        ret = iwl_trans_start_device(trans(priv));
        if (ret)
@@ -537,7 +616,7 @@ int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv,
        old_type = priv->ucode_type;
        priv->ucode_type = ucode_type;
 
-       ret = iwlagn_load_given_ucode(priv, image);
+       ret = iwlagn_load_given_ucode(trans(priv), ucode_type);
        if (ret) {
                priv->ucode_type = old_type;
                iwlagn_remove_notification(priv, &alive_wait);
@@ -568,7 +647,7 @@ int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv,
         * skip it for WoWLAN.
         */
        if (ucode_type != IWL_UCODE_WOWLAN) {
-               ret = iwl_verify_ucode(priv, image);
+               ret = iwl_verify_ucode(trans(priv), ucode_type);
                if (ret) {
                        priv->ucode_type = old_type;
                        return ret;
@@ -597,7 +676,7 @@ int iwlagn_run_init_ucode(struct iwl_priv *priv)
        lockdep_assert_held(&priv->shrd->mutex);
 
        /* No init ucode required? Curious, but maybe ok */
-       if (!priv->ucode_init.code.len)
+       if (!trans(priv)->ucode_init.code.len)
                return 0;
 
        if (priv->ucode_type != IWL_UCODE_NONE)
@@ -608,8 +687,7 @@ int iwlagn_run_init_ucode(struct iwl_priv *priv)
                                      NULL, NULL);
 
        /* Will also start the device */
-       ret = iwlagn_load_ucode_wait_alive(priv, &priv->ucode_init,
-                                          IWL_UCODE_INIT);
+       ret = iwlagn_load_ucode_wait_alive(priv, IWL_UCODE_INIT);
        if (ret)
                goto error;
 
index ccba69b..e235e84 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/dma-mapping.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
 #include <linux/skbuff.h>
@@ -452,52 +451,6 @@ static void iwl_bg_tx_flush(struct work_struct *work)
        iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL);
 }
 
-/******************************************************************************
- *
- * uCode download functions
- *
- ******************************************************************************/
-
-static void iwl_free_fw_desc(struct iwl_priv *priv, struct fw_desc *desc)
-{
-       if (desc->v_addr)
-               dma_free_coherent(bus(priv)->dev, desc->len,
-                                 desc->v_addr, desc->p_addr);
-       desc->v_addr = NULL;
-       desc->len = 0;
-}
-
-static void iwl_free_fw_img(struct iwl_priv *priv, struct fw_img *img)
-{
-       iwl_free_fw_desc(priv, &img->code);
-       iwl_free_fw_desc(priv, &img->data);
-}
-
-static void iwl_dealloc_ucode(struct iwl_priv *priv)
-{
-       iwl_free_fw_img(priv, &priv->ucode_rt);
-       iwl_free_fw_img(priv, &priv->ucode_init);
-       iwl_free_fw_img(priv, &priv->ucode_wowlan);
-}
-
-static int iwl_alloc_fw_desc(struct iwl_priv *priv, struct fw_desc *desc,
-                            const void *data, size_t len)
-{
-       if (!len) {
-               desc->v_addr = NULL;
-               return -EINVAL;
-       }
-
-       desc->v_addr = dma_alloc_coherent(bus(priv)->dev, len,
-                                         &desc->p_addr, GFP_KERNEL);
-       if (!desc->v_addr)
-               return -ENOMEM;
-
-       desc->len = len;
-       memcpy(desc->v_addr, data, len);
-       return 0;
-}
-
 static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
 {
        int i;
@@ -555,16 +508,7 @@ static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
        BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
 }
 
-
-struct iwlagn_ucode_capabilities {
-       u32 max_probe_length;
-       u32 standard_phy_calibration_size;
-       u32 flags;
-};
-
 static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context);
-static int iwlagn_mac_setup_register(struct iwl_priv *priv,
-                                 struct iwlagn_ucode_capabilities *capa);
 
 #define UCODE_EXPERIMENTAL_INDEX       100
 #define UCODE_EXPERIMENTAL_TAG         "exp"
@@ -1040,30 +984,32 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
        /* Runtime instructions and 2 copies of data:
         * 1) unmodified from disk
         * 2) backup cache for save/restore during power-downs */
-       if (iwl_alloc_fw_desc(priv, &priv->ucode_rt.code,
+       if (iwl_alloc_fw_desc(bus(priv), &trans(priv)->ucode_rt.code,
                              pieces.inst, pieces.inst_size))
                goto err_pci_alloc;
-       if (iwl_alloc_fw_desc(priv, &priv->ucode_rt.data,
+       if (iwl_alloc_fw_desc(bus(priv), &trans(priv)->ucode_rt.data,
                              pieces.data, pieces.data_size))
                goto err_pci_alloc;
 
        /* Initialization instructions and data */
        if (pieces.init_size && pieces.init_data_size) {
-               if (iwl_alloc_fw_desc(priv, &priv->ucode_init.code,
+               if (iwl_alloc_fw_desc(bus(priv), &trans(priv)->ucode_init.code,
                                      pieces.init, pieces.init_size))
                        goto err_pci_alloc;
-               if (iwl_alloc_fw_desc(priv, &priv->ucode_init.data,
+               if (iwl_alloc_fw_desc(bus(priv), &trans(priv)->ucode_init.data,
                                      pieces.init_data, pieces.init_data_size))
                        goto err_pci_alloc;
        }
 
        /* WoWLAN instructions and data */
        if (pieces.wowlan_inst_size && pieces.wowlan_data_size) {
-               if (iwl_alloc_fw_desc(priv, &priv->ucode_wowlan.code,
+               if (iwl_alloc_fw_desc(bus(priv),
+                                     &trans(priv)->ucode_wowlan.code,
                                      pieces.wowlan_inst,
                                      pieces.wowlan_inst_size))
                        goto err_pci_alloc;
-               if (iwl_alloc_fw_desc(priv, &priv->ucode_wowlan.data,
+               if (iwl_alloc_fw_desc(bus(priv),
+                                     &trans(priv)->ucode_wowlan.data,
                                      pieces.wowlan_data,
                                      pieces.wowlan_data_size))
                        goto err_pci_alloc;
@@ -1156,7 +1102,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
 
  err_pci_alloc:
        IWL_ERR(priv, "failed to allocate pci memory\n");
-       iwl_dealloc_ucode(priv);
+       iwl_dealloc_ucode(trans(priv));
  out_unbind:
        complete(&priv->firmware_loading_complete);
        device_release_driver(bus(priv)->dev);
@@ -1352,7 +1298,7 @@ int iwl_alive_start(struct iwl_priv *priv)
 
 static void iwl_cancel_deferred_work(struct iwl_priv *priv);
 
-static void __iwl_down(struct iwl_priv *priv)
+void __iwl_down(struct iwl_priv *priv)
 {
        int exit_pending;
 
@@ -1415,7 +1361,7 @@ static void __iwl_down(struct iwl_priv *priv)
        priv->beacon_skb = NULL;
 }
 
-static void iwl_down(struct iwl_priv *priv)
+void iwl_down(struct iwl_priv *priv)
 {
        mutex_lock(&priv->shrd->mutex);
        __iwl_down(priv);
@@ -1424,57 +1370,6 @@ static void iwl_down(struct iwl_priv *priv)
        iwl_cancel_deferred_work(priv);
 }
 
-#define MAX_HW_RESTARTS 5
-
-static int __iwl_up(struct iwl_priv *priv)
-{
-       struct iwl_rxon_context *ctx;
-       int ret;
-
-       lockdep_assert_held(&priv->shrd->mutex);
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) {
-               IWL_WARN(priv, "Exit pending; will not bring the NIC up\n");
-               return -EIO;
-       }
-
-       for_each_context(priv, ctx) {
-               ret = iwlagn_alloc_bcast_station(priv, ctx);
-               if (ret) {
-                       iwl_dealloc_bcast_stations(priv);
-                       return ret;
-               }
-       }
-
-       ret = iwlagn_run_init_ucode(priv);
-       if (ret) {
-               IWL_ERR(priv, "Failed to run INIT ucode: %d\n", ret);
-               goto error;
-       }
-
-       ret = iwlagn_load_ucode_wait_alive(priv,
-                                          &priv->ucode_rt,
-                                          IWL_UCODE_REGULAR);
-       if (ret) {
-               IWL_ERR(priv, "Failed to start RT ucode: %d\n", ret);
-               goto error;
-       }
-
-       ret = iwl_alive_start(priv);
-       if (ret)
-               goto error;
-       return 0;
-
- error:
-       set_bit(STATUS_EXIT_PENDING, &priv->shrd->status);
-       __iwl_down(priv);
-       clear_bit(STATUS_EXIT_PENDING, &priv->shrd->status);
-
-       IWL_ERR(priv, "Unable to initialize device.\n");
-       return ret;
-}
-
-
 /*****************************************************************************
  *
  * Workqueue callbacks
@@ -1502,7 +1397,7 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work)
        mutex_unlock(&priv->shrd->mutex);
 }
 
-static void iwlagn_prepare_restart(struct iwl_priv *priv)
+void iwlagn_prepare_restart(struct iwl_priv *priv)
 {
        struct iwl_rxon_context *ctx;
        bool bt_full_concurrent;
@@ -1559,1499 +1454,180 @@ static void iwl_bg_restart(struct work_struct *data)
        }
 }
 
-/*****************************************************************************
- *
- * mac80211 entry point functions
- *
- *****************************************************************************/
-
-static const struct ieee80211_iface_limit iwlagn_sta_ap_limits[] = {
-       {
-               .max = 1,
-               .types = BIT(NL80211_IFTYPE_STATION),
-       },
-       {
-               .max = 1,
-               .types = BIT(NL80211_IFTYPE_AP),
-       },
-};
-
-static const struct ieee80211_iface_limit iwlagn_2sta_limits[] = {
-       {
-               .max = 2,
-               .types = BIT(NL80211_IFTYPE_STATION),
-       },
-};
-
-static const struct ieee80211_iface_limit iwlagn_p2p_sta_go_limits[] = {
-       {
-               .max = 1,
-               .types = BIT(NL80211_IFTYPE_STATION),
-       },
-       {
-               .max = 1,
-               .types = BIT(NL80211_IFTYPE_P2P_GO) |
-                        BIT(NL80211_IFTYPE_AP),
-       },
-};
-
-static const struct ieee80211_iface_limit iwlagn_p2p_2sta_limits[] = {
-       {
-               .max = 2,
-               .types = BIT(NL80211_IFTYPE_STATION),
-       },
-       {
-               .max = 1,
-               .types = BIT(NL80211_IFTYPE_P2P_CLIENT),
-       },
-};
 
-static const struct ieee80211_iface_combination
-iwlagn_iface_combinations_dualmode[] = {
-       { .num_different_channels = 1,
-         .max_interfaces = 2,
-         .beacon_int_infra_match = true,
-         .limits = iwlagn_sta_ap_limits,
-         .n_limits = ARRAY_SIZE(iwlagn_sta_ap_limits),
-       },
-       { .num_different_channels = 1,
-         .max_interfaces = 2,
-         .limits = iwlagn_2sta_limits,
-         .n_limits = ARRAY_SIZE(iwlagn_2sta_limits),
-       },
-};
 
-static const struct ieee80211_iface_combination
-iwlagn_iface_combinations_p2p[] = {
-       { .num_different_channels = 1,
-         .max_interfaces = 2,
-         .beacon_int_infra_match = true,
-         .limits = iwlagn_p2p_sta_go_limits,
-         .n_limits = ARRAY_SIZE(iwlagn_p2p_sta_go_limits),
-       },
-       { .num_different_channels = 1,
-         .max_interfaces = 2,
-         .limits = iwlagn_p2p_2sta_limits,
-         .n_limits = ARRAY_SIZE(iwlagn_p2p_2sta_limits),
-       },
-};
 
-/*
- * Not a mac80211 entry point function, but it fits in with all the
- * other mac80211 functions grouped here.
- */
-static int iwlagn_mac_setup_register(struct iwl_priv *priv,
-                                 struct iwlagn_ucode_capabilities *capa)
+void iwlagn_disable_roc(struct iwl_priv *priv)
 {
-       int ret;
-       struct ieee80211_hw *hw = priv->hw;
-       struct iwl_rxon_context *ctx;
-
-       hw->rate_control_algorithm = "iwl-agn-rs";
-
-       /* Tell mac80211 our characteristics */
-       hw->flags = IEEE80211_HW_SIGNAL_DBM |
-                   IEEE80211_HW_AMPDU_AGGREGATION |
-                   IEEE80211_HW_NEED_DTIM_PERIOD |
-                   IEEE80211_HW_SPECTRUM_MGMT |
-                   IEEE80211_HW_REPORTS_TX_ACK_STATUS;
-
-       /*
-        * Including the following line will crash some AP's.  This
-        * workaround removes the stimulus which causes the crash until
-        * the AP software can be fixed.
-       hw->max_tx_aggregation_subframes = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
-        */
-
-       hw->flags |= IEEE80211_HW_SUPPORTS_PS |
-                    IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
-
-       if (priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE)
-               hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
-                            IEEE80211_HW_SUPPORTS_STATIC_SMPS;
-
-       if (capa->flags & IWL_UCODE_TLV_FLAGS_MFP)
-               hw->flags |= IEEE80211_HW_MFP_CAPABLE;
-
-       hw->sta_data_size = sizeof(struct iwl_station_priv);
-       hw->vif_data_size = sizeof(struct iwl_vif_priv);
-
-       for_each_context(priv, ctx) {
-               hw->wiphy->interface_modes |= ctx->interface_modes;
-               hw->wiphy->interface_modes |= ctx->exclusive_interface_modes;
-       }
-
-       BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
-
-       if (hw->wiphy->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)) {
-               hw->wiphy->iface_combinations = iwlagn_iface_combinations_p2p;
-               hw->wiphy->n_iface_combinations =
-                       ARRAY_SIZE(iwlagn_iface_combinations_p2p);
-       } else if (hw->wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) {
-               hw->wiphy->iface_combinations = iwlagn_iface_combinations_dualmode;
-               hw->wiphy->n_iface_combinations =
-                       ARRAY_SIZE(iwlagn_iface_combinations_dualmode);
-       }
-
-       hw->wiphy->max_remain_on_channel_duration = 1000;
-
-       hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
-                           WIPHY_FLAG_DISABLE_BEACON_HINTS |
-                           WIPHY_FLAG_IBSS_RSN;
-
-       if (priv->ucode_wowlan.code.len && device_can_wakeup(bus(priv)->dev)) {
-               hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
-                                         WIPHY_WOWLAN_DISCONNECT |
-                                         WIPHY_WOWLAN_EAP_IDENTITY_REQ |
-                                         WIPHY_WOWLAN_RFKILL_RELEASE;
-               if (!iwlagn_mod_params.sw_crypto)
-                       hw->wiphy->wowlan.flags |=
-                               WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
-                               WIPHY_WOWLAN_GTK_REKEY_FAILURE;
-
-               hw->wiphy->wowlan.n_patterns = IWLAGN_WOWLAN_MAX_PATTERNS;
-               hw->wiphy->wowlan.pattern_min_len =
-                                       IWLAGN_WOWLAN_MIN_PATTERN_LEN;
-               hw->wiphy->wowlan.pattern_max_len =
-                                       IWLAGN_WOWLAN_MAX_PATTERN_LEN;
-       }
-
-       if (iwlagn_mod_params.power_save)
-               hw->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
-       else
-               hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
 
-       hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
-       /* we create the 802.11 header and a zero-length SSID element */
-       hw->wiphy->max_scan_ie_len = capa->max_probe_length - 24 - 2;
+       lockdep_assert_held(&priv->shrd->mutex);
 
-       /* Default value; 4 EDCA QOS priorities */
-       hw->queues = 4;
+       if (!priv->hw_roc_setup)
+               return;
 
-       hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL;
+       ctx->staging.dev_type = RXON_DEV_TYPE_P2P;
+       ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 
-       if (priv->bands[IEEE80211_BAND_2GHZ].n_channels)
-               priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
-                       &priv->bands[IEEE80211_BAND_2GHZ];
-       if (priv->bands[IEEE80211_BAND_5GHZ].n_channels)
-               priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
-                       &priv->bands[IEEE80211_BAND_5GHZ];
+       priv->hw_roc_channel = NULL;
 
-       iwl_leds_init(priv);
+       memset(ctx->staging.node_addr, 0, ETH_ALEN);
 
-       ret = ieee80211_register_hw(priv->hw);
-       if (ret) {
-               IWL_ERR(priv, "Failed to register hw (error %d)\n", ret);
-               return ret;
-       }
-       priv->mac80211_registered = 1;
+       iwlagn_commit_rxon(priv, ctx);
 
-       return 0;
+       ctx->is_active = false;
+       priv->hw_roc_setup = false;
 }
 
-
-static int iwlagn_mac_start(struct ieee80211_hw *hw)
+static void iwlagn_disable_roc_work(struct work_struct *work)
 {
-       struct iwl_priv *priv = hw->priv;
-       int ret;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
+       struct iwl_priv *priv = container_of(work, struct iwl_priv,
+                                            hw_roc_disable_work.work);
 
-       /* we should be verifying the device is ready to be opened */
        mutex_lock(&priv->shrd->mutex);
-       ret = __iwl_up(priv);
+       iwlagn_disable_roc(priv);
        mutex_unlock(&priv->shrd->mutex);
-       if (ret)
-               return ret;
-
-       IWL_DEBUG_INFO(priv, "Start UP work done.\n");
-
-       /* Now we should be done, and the READY bit should be set. */
-       if (WARN_ON(!test_bit(STATUS_READY, &priv->shrd->status)))
-               ret = -EIO;
-
-       iwlagn_led_enable(priv);
-
-       priv->is_open = 1;
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-       return 0;
 }
 
-static void iwlagn_mac_stop(struct ieee80211_hw *hw)
+/*****************************************************************************
+ *
+ * driver setup and teardown
+ *
+ *****************************************************************************/
+
+static void iwl_setup_deferred_work(struct iwl_priv *priv)
 {
-       struct iwl_priv *priv = hw->priv;
+       priv->shrd->workqueue = create_singlethread_workqueue(DRV_NAME);
 
-       IWL_DEBUG_MAC80211(priv, "enter\n");
+       init_waitqueue_head(&priv->shrd->wait_command_queue);
 
-       if (!priv->is_open)
-               return;
+       INIT_WORK(&priv->restart, iwl_bg_restart);
+       INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
+       INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work);
+       INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush);
+       INIT_WORK(&priv->bt_full_concurrency, iwl_bg_bt_full_concurrency);
+       INIT_WORK(&priv->bt_runtime_config, iwl_bg_bt_runtime_config);
+       INIT_DELAYED_WORK(&priv->hw_roc_disable_work,
+                         iwlagn_disable_roc_work);
 
-       priv->is_open = 0;
+       iwl_setup_scan_deferred_work(priv);
 
-       iwl_down(priv);
+       if (priv->cfg->lib->bt_setup_deferred_work)
+               priv->cfg->lib->bt_setup_deferred_work(priv);
 
-       flush_workqueue(priv->shrd->workqueue);
+       init_timer(&priv->statistics_periodic);
+       priv->statistics_periodic.data = (unsigned long)priv;
+       priv->statistics_periodic.function = iwl_bg_statistics_periodic;
 
-       /* User space software may expect getting rfkill changes
-        * even if interface is down */
-       iwl_write32(bus(priv), CSR_INT, 0xFFFFFFFF);
-       iwl_enable_rfkill_int(priv);
+       init_timer(&priv->ucode_trace);
+       priv->ucode_trace.data = (unsigned long)priv;
+       priv->ucode_trace.function = iwl_bg_ucode_trace;
 
-       IWL_DEBUG_MAC80211(priv, "leave\n");
+       init_timer(&priv->watchdog);
+       priv->watchdog.data = (unsigned long)priv;
+       priv->watchdog.function = iwl_bg_watchdog;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int iwlagn_send_patterns(struct iwl_priv *priv,
-                               struct cfg80211_wowlan *wowlan)
+static void iwl_cancel_deferred_work(struct iwl_priv *priv)
 {
-       struct iwlagn_wowlan_patterns_cmd *pattern_cmd;
-       struct iwl_host_cmd cmd = {
-               .id = REPLY_WOWLAN_PATTERNS,
-               .dataflags[0] = IWL_HCMD_DFL_NOCOPY,
-               .flags = CMD_SYNC,
-       };
-       int i, err;
+       if (priv->cfg->lib->cancel_deferred_work)
+               priv->cfg->lib->cancel_deferred_work(priv);
 
-       if (!wowlan->n_patterns)
-               return 0;
+       cancel_work_sync(&priv->run_time_calib_work);
+       cancel_work_sync(&priv->beacon_update);
 
-       cmd.len[0] = sizeof(*pattern_cmd) +
-                       wowlan->n_patterns * sizeof(struct iwlagn_wowlan_pattern);
+       iwl_cancel_scan_deferred_work(priv);
 
-       pattern_cmd = kmalloc(cmd.len[0], GFP_KERNEL);
-       if (!pattern_cmd)
-               return -ENOMEM;
+       cancel_work_sync(&priv->bt_full_concurrency);
+       cancel_work_sync(&priv->bt_runtime_config);
+       cancel_delayed_work_sync(&priv->hw_roc_disable_work);
 
-       pattern_cmd->n_patterns = cpu_to_le32(wowlan->n_patterns);
+       del_timer_sync(&priv->statistics_periodic);
+       del_timer_sync(&priv->ucode_trace);
+}
 
-       for (i = 0; i < wowlan->n_patterns; i++) {
-               int mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8);
+static void iwl_init_hw_rates(struct iwl_priv *priv,
+                             struct ieee80211_rate *rates)
+{
+       int i;
 
-               memcpy(&pattern_cmd->patterns[i].mask,
-                       wowlan->patterns[i].mask, mask_len);
-               memcpy(&pattern_cmd->patterns[i].pattern,
-                       wowlan->patterns[i].pattern,
-                       wowlan->patterns[i].pattern_len);
-               pattern_cmd->patterns[i].mask_size = mask_len;
-               pattern_cmd->patterns[i].pattern_size =
-                       wowlan->patterns[i].pattern_len;
+       for (i = 0; i < IWL_RATE_COUNT_LEGACY; i++) {
+               rates[i].bitrate = iwl_rates[i].ieee * 5;
+               rates[i].hw_value = i; /* Rate scaling will work on indexes */
+               rates[i].hw_value_short = i;
+               rates[i].flags = 0;
+               if ((i >= IWL_FIRST_CCK_RATE) && (i <= IWL_LAST_CCK_RATE)) {
+                       /*
+                        * If CCK != 1M then set short preamble rate flag.
+                        */
+                       rates[i].flags |=
+                               (iwl_rates[i].plcp == IWL_RATE_1M_PLCP) ?
+                                       0 : IEEE80211_RATE_SHORT_PREAMBLE;
+               }
        }
-
-       cmd.data[0] = pattern_cmd;
-       err = iwl_trans_send_cmd(trans(priv), &cmd);
-       kfree(pattern_cmd);
-       return err;
 }
-#endif
 
-static void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw,
-                                     struct ieee80211_vif *vif,
-                                     struct cfg80211_gtk_rekey_data *data)
+static int iwl_init_drv(struct iwl_priv *priv)
 {
-       struct iwl_priv *priv = hw->priv;
-
-       if (iwlagn_mod_params.sw_crypto)
-               return;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->shrd->mutex);
+       int ret;
 
-       if (priv->contexts[IWL_RXON_CTX_BSS].vif != vif)
-               goto out;
+       spin_lock_init(&priv->shrd->sta_lock);
 
-       memcpy(priv->kek, data->kek, NL80211_KEK_LEN);
-       memcpy(priv->kck, data->kck, NL80211_KCK_LEN);
-       priv->replay_ctr = cpu_to_le64(be64_to_cpup((__be64 *)&data->replay_ctr));
-       priv->have_rekey_data = true;
+       mutex_init(&priv->shrd->mutex);
 
- out:
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-}
+       priv->ieee_channels = NULL;
+       priv->ieee_rates = NULL;
+       priv->band = IEEE80211_BAND_2GHZ;
 
-struct wowlan_key_data {
-       struct iwl_rxon_context *ctx;
-       struct iwlagn_wowlan_rsc_tsc_params_cmd *rsc_tsc;
-       struct iwlagn_wowlan_tkip_params_cmd *tkip;
-       const u8 *bssid;
-       bool error, use_rsc_tsc, use_tkip;
-};
+       priv->iw_mode = NL80211_IFTYPE_STATION;
+       priv->current_ht_config.smps = IEEE80211_SMPS_STATIC;
+       priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF;
+       priv->agg_tids_count = 0;
 
-#ifdef CONFIG_PM_SLEEP
-static void iwlagn_convert_p1k(u16 *p1k, __le16 *out)
-{
-       int i;
+       /* initialize force reset */
+       priv->force_reset[IWL_RF_RESET].reset_duration =
+               IWL_DELAY_NEXT_FORCE_RF_RESET;
+       priv->force_reset[IWL_FW_RESET].reset_duration =
+               IWL_DELAY_NEXT_FORCE_FW_RELOAD;
 
-       for (i = 0; i < IWLAGN_P1K_SIZE; i++)
-               out[i] = cpu_to_le16(p1k[i]);
-}
+       priv->rx_statistics_jiffies = jiffies;
 
-static void iwlagn_wowlan_program_keys(struct ieee80211_hw *hw,
-                                      struct ieee80211_vif *vif,
-                                      struct ieee80211_sta *sta,
-                                      struct ieee80211_key_conf *key,
-                                      void *_data)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct wowlan_key_data *data = _data;
-       struct iwl_rxon_context *ctx = data->ctx;
-       struct aes_sc *aes_sc, *aes_tx_sc = NULL;
-       struct tkip_sc *tkip_sc, *tkip_tx_sc = NULL;
-       struct iwlagn_p1k_cache *rx_p1ks;
-       u8 *rx_mic_key;
-       struct ieee80211_key_seq seq;
-       u32 cur_rx_iv32 = 0;
-       u16 p1k[IWLAGN_P1K_SIZE];
-       int ret, i;
+       /* Choose which receivers/antennas to use */
+       iwlagn_set_rxon_chain(priv, &priv->contexts[IWL_RXON_CTX_BSS]);
 
-       mutex_lock(&priv->shrd->mutex);
+       iwl_init_scan_params(priv);
 
-       if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
-            key->cipher == WLAN_CIPHER_SUITE_WEP104) &&
-            !sta && !ctx->key_mapping_keys)
-               ret = iwl_set_default_wep_key(priv, ctx, key);
-       else
-               ret = iwl_set_dynamic_key(priv, ctx, key, sta);
+       /* init bt coex */
+       if (priv->cfg->bt_params &&
+           priv->cfg->bt_params->advanced_bt_coexist) {
+               priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT;
+               priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT;
+               priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK;
+               priv->bt_on_thresh = BT_ON_THRESHOLD_DEF;
+               priv->bt_duration = BT_DURATION_LIMIT_DEF;
+               priv->dynamic_frag_thresh = BT_FRAG_THRESHOLD_DEF;
+       }
 
+       ret = iwl_init_channel_map(priv);
        if (ret) {
-               IWL_ERR(priv, "Error setting key during suspend!\n");
-               data->error = true;
+               IWL_ERR(priv, "initializing regulatory failed: %d\n", ret);
+               goto err;
        }
 
-       switch (key->cipher) {
-       case WLAN_CIPHER_SUITE_TKIP:
-               if (sta) {
-                       tkip_sc = data->rsc_tsc->all_tsc_rsc.tkip.unicast_rsc;
-                       tkip_tx_sc = &data->rsc_tsc->all_tsc_rsc.tkip.tsc;
-
-                       rx_p1ks = data->tkip->rx_uni;
+       ret = iwl_init_geos(priv);
+       if (ret) {
+               IWL_ERR(priv, "initializing geos failed: %d\n", ret);
+               goto err_free_channel_map;
+       }
+       iwl_init_hw_rates(priv, priv->ieee_rates);
 
-                       ieee80211_get_key_tx_seq(key, &seq);
-                       tkip_tx_sc->iv16 = cpu_to_le16(seq.tkip.iv16);
-                       tkip_tx_sc->iv32 = cpu_to_le32(seq.tkip.iv32);
+       return 0;
 
-                       ieee80211_get_tkip_p1k_iv(key, seq.tkip.iv32, p1k);
-                       iwlagn_convert_p1k(p1k, data->tkip->tx.p1k);
-
-                       memcpy(data->tkip->mic_keys.tx,
-                              &key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY],
-                              IWLAGN_MIC_KEY_SIZE);
-
-                       rx_mic_key = data->tkip->mic_keys.rx_unicast;
-               } else {
-                       tkip_sc = data->rsc_tsc->all_tsc_rsc.tkip.multicast_rsc;
-                       rx_p1ks = data->tkip->rx_multi;
-                       rx_mic_key = data->tkip->mic_keys.rx_mcast;
-               }
-
-               /*
-                * For non-QoS this relies on the fact that both the uCode and
-                * mac80211 use TID 0 (as they need to to avoid replay attacks)
-                * for checking the IV in the frames.
-                */
-               for (i = 0; i < IWLAGN_NUM_RSC; i++) {
-                       ieee80211_get_key_rx_seq(key, i, &seq);
-                       tkip_sc[i].iv16 = cpu_to_le16(seq.tkip.iv16);
-                       tkip_sc[i].iv32 = cpu_to_le32(seq.tkip.iv32);
-                       /* wrapping isn't allowed, AP must rekey */
-                       if (seq.tkip.iv32 > cur_rx_iv32)
-                               cur_rx_iv32 = seq.tkip.iv32;
-               }
-
-               ieee80211_get_tkip_rx_p1k(key, data->bssid, cur_rx_iv32, p1k);
-               iwlagn_convert_p1k(p1k, rx_p1ks[0].p1k);
-               ieee80211_get_tkip_rx_p1k(key, data->bssid,
-                                         cur_rx_iv32 + 1, p1k);
-               iwlagn_convert_p1k(p1k, rx_p1ks[1].p1k);
-
-               memcpy(rx_mic_key,
-                      &key->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY],
-                      IWLAGN_MIC_KEY_SIZE);
-
-               data->use_tkip = true;
-               data->use_rsc_tsc = true;
-               break;
-       case WLAN_CIPHER_SUITE_CCMP:
-               if (sta) {
-                       u8 *pn = seq.ccmp.pn;
-
-                       aes_sc = data->rsc_tsc->all_tsc_rsc.aes.unicast_rsc;
-                       aes_tx_sc = &data->rsc_tsc->all_tsc_rsc.aes.tsc;
-
-                       ieee80211_get_key_tx_seq(key, &seq);
-                       aes_tx_sc->pn = cpu_to_le64(
-                                       (u64)pn[5] |
-                                       ((u64)pn[4] << 8) |
-                                       ((u64)pn[3] << 16) |
-                                       ((u64)pn[2] << 24) |
-                                       ((u64)pn[1] << 32) |
-                                       ((u64)pn[0] << 40));
-               } else
-                       aes_sc = data->rsc_tsc->all_tsc_rsc.aes.multicast_rsc;
-
-               /*
-                * For non-QoS this relies on the fact that both the uCode and
-                * mac80211 use TID 0 for checking the IV in the frames.
-                */
-               for (i = 0; i < IWLAGN_NUM_RSC; i++) {
-                       u8 *pn = seq.ccmp.pn;
-
-                       ieee80211_get_key_rx_seq(key, i, &seq);
-                       aes_sc->pn = cpu_to_le64(
-                                       (u64)pn[5] |
-                                       ((u64)pn[4] << 8) |
-                                       ((u64)pn[3] << 16) |
-                                       ((u64)pn[2] << 24) |
-                                       ((u64)pn[1] << 32) |
-                                       ((u64)pn[0] << 40));
-               }
-               data->use_rsc_tsc = true;
-               break;
-       }
-
-       mutex_unlock(&priv->shrd->mutex);
-}
-
-static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
-                             struct cfg80211_wowlan *wowlan)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwlagn_wowlan_wakeup_filter_cmd wakeup_filter_cmd;
-       struct iwl_rxon_cmd rxon;
-       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-       struct iwlagn_wowlan_kek_kck_material_cmd kek_kck_cmd;
-       struct iwlagn_wowlan_tkip_params_cmd tkip_cmd = {};
-       struct wowlan_key_data key_data = {
-               .ctx = ctx,
-               .bssid = ctx->active.bssid_addr,
-               .use_rsc_tsc = false,
-               .tkip = &tkip_cmd,
-               .use_tkip = false,
-       };
-       int ret, i;
-       u16 seq;
-
-       if (WARN_ON(!wowlan))
-               return -EINVAL;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->shrd->mutex);
-
-       /* Don't attempt WoWLAN when not associated, tear down instead. */
-       if (!ctx->vif || ctx->vif->type != NL80211_IFTYPE_STATION ||
-           !iwl_is_associated_ctx(ctx)) {
-               ret = 1;
-               goto out;
-       }
-
-       key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL);
-       if (!key_data.rsc_tsc) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       memset(&wakeup_filter_cmd, 0, sizeof(wakeup_filter_cmd));
-
-       /*
-        * We know the last used seqno, and the uCode expects to know that
-        * one, it will increment before TX.
-        */
-       seq = le16_to_cpu(priv->last_seq_ctl) & IEEE80211_SCTL_SEQ;
-       wakeup_filter_cmd.non_qos_seq = cpu_to_le16(seq);
-
-       /*
-        * For QoS counters, we store the one to use next, so subtract 0x10
-        * since the uCode will add 0x10 before using the value.
-        */
-       for (i = 0; i < 8; i++) {
-               seq = priv->shrd->tid_data[IWL_AP_ID][i].seq_number;
-               seq -= 0x10;
-               wakeup_filter_cmd.qos_seq[i] = cpu_to_le16(seq);
-       }
-
-       if (wowlan->disconnect)
-               wakeup_filter_cmd.enabled |=
-                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_BEACON_MISS |
-                                   IWLAGN_WOWLAN_WAKEUP_LINK_CHANGE);
-       if (wowlan->magic_pkt)
-               wakeup_filter_cmd.enabled |=
-                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_MAGIC_PACKET);
-       if (wowlan->gtk_rekey_failure)
-               wakeup_filter_cmd.enabled |=
-                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_GTK_REKEY_FAIL);
-       if (wowlan->eap_identity_req)
-               wakeup_filter_cmd.enabled |=
-                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_EAP_IDENT_REQ);
-       if (wowlan->four_way_handshake)
-               wakeup_filter_cmd.enabled |=
-                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_4WAY_HANDSHAKE);
-       if (wowlan->rfkill_release)
-               wakeup_filter_cmd.enabled |=
-                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_RFKILL);
-       if (wowlan->n_patterns)
-               wakeup_filter_cmd.enabled |=
-                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_PATTERN_MATCH);
-
-       iwl_scan_cancel_timeout(priv, 200);
-
-       memcpy(&rxon, &ctx->active, sizeof(rxon));
-
-       iwl_trans_stop_device(trans(priv));
-
-       priv->shrd->wowlan = true;
-
-       ret = iwlagn_load_ucode_wait_alive(priv, &priv->ucode_wowlan,
-                                          IWL_UCODE_WOWLAN);
-       if (ret)
-               goto error;
-
-       /* now configure WoWLAN ucode */
-       ret = iwl_alive_start(priv);
-       if (ret)
-               goto error;
-
-       memcpy(&ctx->staging, &rxon, sizeof(rxon));
-       ret = iwlagn_commit_rxon(priv, ctx);
-       if (ret)
-               goto error;
-
-       ret = iwl_power_update_mode(priv, true);
-       if (ret)
-               goto error;
-
-       if (!iwlagn_mod_params.sw_crypto) {
-               /* mark all keys clear */
-               priv->ucode_key_table = 0;
-               ctx->key_mapping_keys = 0;
-
-               /*
-                * This needs to be unlocked due to lock ordering
-                * constraints. Since we're in the suspend path
-                * that isn't really a problem though.
-                */
-               mutex_unlock(&priv->shrd->mutex);
-               ieee80211_iter_keys(priv->hw, ctx->vif,
-                                   iwlagn_wowlan_program_keys,
-                                   &key_data);
-               mutex_lock(&priv->shrd->mutex);
-               if (key_data.error) {
-                       ret = -EIO;
-                       goto error;
-               }
-
-               if (key_data.use_rsc_tsc) {
-                       struct iwl_host_cmd rsc_tsc_cmd = {
-                               .id = REPLY_WOWLAN_TSC_RSC_PARAMS,
-                               .flags = CMD_SYNC,
-                               .data[0] = key_data.rsc_tsc,
-                               .dataflags[0] = IWL_HCMD_DFL_NOCOPY,
-                               .len[0] = sizeof(*key_data.rsc_tsc),
-                       };
-
-                       ret = iwl_trans_send_cmd(trans(priv), &rsc_tsc_cmd);
-                       if (ret)
-                               goto error;
-               }
-
-               if (key_data.use_tkip) {
-                       ret = iwl_trans_send_cmd_pdu(trans(priv),
-                                                REPLY_WOWLAN_TKIP_PARAMS,
-                                                CMD_SYNC, sizeof(tkip_cmd),
-                                                &tkip_cmd);
-                       if (ret)
-                               goto error;
-               }
-
-               if (priv->have_rekey_data) {
-                       memset(&kek_kck_cmd, 0, sizeof(kek_kck_cmd));
-                       memcpy(kek_kck_cmd.kck, priv->kck, NL80211_KCK_LEN);
-                       kek_kck_cmd.kck_len = cpu_to_le16(NL80211_KCK_LEN);
-                       memcpy(kek_kck_cmd.kek, priv->kek, NL80211_KEK_LEN);
-                       kek_kck_cmd.kek_len = cpu_to_le16(NL80211_KEK_LEN);
-                       kek_kck_cmd.replay_ctr = priv->replay_ctr;
-
-                       ret = iwl_trans_send_cmd_pdu(trans(priv),
-                                                REPLY_WOWLAN_KEK_KCK_MATERIAL,
-                                                CMD_SYNC, sizeof(kek_kck_cmd),
-                                                &kek_kck_cmd);
-                       if (ret)
-                               goto error;
-               }
-       }
-
-       ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_WOWLAN_WAKEUP_FILTER,
-                                CMD_SYNC, sizeof(wakeup_filter_cmd),
-                                &wakeup_filter_cmd);
-       if (ret)
-               goto error;
-
-       ret = iwlagn_send_patterns(priv, wowlan);
-       if (ret)
-               goto error;
-
-       device_set_wakeup_enable(bus(priv)->dev, true);
-
-       /* Now let the ucode operate on its own */
-       iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_SET,
-                         CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
-
-       goto out;
-
- error:
-       priv->shrd->wowlan = false;
-       iwlagn_prepare_restart(priv);
-       ieee80211_restart_hw(priv->hw);
- out:
-       mutex_unlock(&priv->shrd->mutex);
-       kfree(key_data.rsc_tsc);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       return ret;
-}
-
-static int iwlagn_mac_resume(struct ieee80211_hw *hw)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-       struct ieee80211_vif *vif;
-       unsigned long flags;
-       u32 base, status = 0xffffffff;
-       int ret = -EIO;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->shrd->mutex);
-
-       iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_CLR,
-                         CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
-
-       base = priv->device_pointers.error_event_table;
-       if (iwlagn_hw_valid_rtc_data_addr(base)) {
-               spin_lock_irqsave(&bus(priv)->reg_lock, flags);
-               ret = iwl_grab_nic_access_silent(bus(priv));
-               if (ret == 0) {
-                       iwl_write32(bus(priv), HBUS_TARG_MEM_RADDR, base);
-                       status = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT);
-                       iwl_release_nic_access(bus(priv));
-               }
-               spin_unlock_irqrestore(&bus(priv)->reg_lock, flags);
-
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-               if (ret == 0) {
-                       if (!priv->wowlan_sram)
-                               priv->wowlan_sram =
-                                       kzalloc(priv->ucode_wowlan.data.len,
-                                               GFP_KERNEL);
-
-                       if (priv->wowlan_sram)
-                               _iwl_read_targ_mem_words(
-                                       bus(priv), 0x800000, priv->wowlan_sram,
-                                       priv->ucode_wowlan.data.len / 4);
-               }
-#endif
-       }
-
-       /* we'll clear ctx->vif during iwlagn_prepare_restart() */
-       vif = ctx->vif;
-
-       priv->shrd->wowlan = false;
-
-       device_set_wakeup_enable(bus(priv)->dev, false);
-
-       iwlagn_prepare_restart(priv);
-
-       memset((void *)&ctx->active, 0, sizeof(ctx->active));
-       iwl_connection_init_rx_config(priv, ctx);
-       iwlagn_set_rxon_chain(priv, ctx);
-
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       ieee80211_resume_disconnect(vif);
-
-       return 1;
-}
-#endif
-
-static void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
-{
-       struct iwl_priv *priv = hw->priv;
-
-       IWL_DEBUG_MACDUMP(priv, "enter\n");
-
-       IWL_DEBUG_TX(priv, "dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
-                    ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate);
-
-       if (iwlagn_tx_skb(priv, skb))
-               dev_kfree_skb_any(skb);
-
-       IWL_DEBUG_MACDUMP(priv, "leave\n");
-}
-
-static void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw,
-                                      struct ieee80211_vif *vif,
-                                      struct ieee80211_key_conf *keyconf,
-                                      struct ieee80211_sta *sta,
-                                      u32 iv32, u16 *phase1key)
-{
-       struct iwl_priv *priv = hw->priv;
-
-       iwl_update_tkip_key(priv, vif, keyconf, sta, iv32, phase1key);
-}
-
-static int iwlagn_mac_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 iwl_priv *priv = hw->priv;
-       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
-       struct iwl_rxon_context *ctx = vif_priv->ctx;
-       int ret;
-       bool is_default_wep_key = false;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-
-       if (iwlagn_mod_params.sw_crypto) {
-               IWL_DEBUG_MAC80211(priv, "leave - hwcrypto disabled\n");
-               return -EOPNOTSUPP;
-       }
-
-       /*
-        * We could program these keys into the hardware as well, but we
-        * don't expect much multicast traffic in IBSS and having keys
-        * for more stations is probably more useful.
-        *
-        * Mark key TX-only and return 0.
-        */
-       if (vif->type == NL80211_IFTYPE_ADHOC &&
-           !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
-               key->hw_key_idx = WEP_INVALID_OFFSET;
-               return 0;
-       }
-
-       /* If they key was TX-only, accept deletion */
-       if (cmd == DISABLE_KEY && key->hw_key_idx == WEP_INVALID_OFFSET)
-               return 0;
-
-       mutex_lock(&priv->shrd->mutex);
-       iwl_scan_cancel_timeout(priv, 100);
-
-       BUILD_BUG_ON(WEP_INVALID_OFFSET == IWLAGN_HW_KEY_DEFAULT);
-
-       /*
-        * If we are getting WEP group key and we didn't receive any key mapping
-        * so far, we are in legacy wep mode (group key only), otherwise we are
-        * in 1X mode.
-        * In legacy wep mode, we use another host command to the uCode.
-        */
-       if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
-            key->cipher == WLAN_CIPHER_SUITE_WEP104) && !sta) {
-               if (cmd == SET_KEY)
-                       is_default_wep_key = !ctx->key_mapping_keys;
-               else
-                       is_default_wep_key =
-                               key->hw_key_idx == IWLAGN_HW_KEY_DEFAULT;
-       }
-
-
-       switch (cmd) {
-       case SET_KEY:
-               if (is_default_wep_key) {
-                       ret = iwl_set_default_wep_key(priv, vif_priv->ctx, key);
-                       break;
-               }
-               ret = iwl_set_dynamic_key(priv, vif_priv->ctx, key, sta);
-               if (ret) {
-                       /*
-                        * can't add key for RX, but we don't need it
-                        * in the device for TX so still return 0
-                        */
-                       ret = 0;
-                       key->hw_key_idx = WEP_INVALID_OFFSET;
-               }
-
-               IWL_DEBUG_MAC80211(priv, "enable hwcrypto key\n");
-               break;
-       case DISABLE_KEY:
-               if (is_default_wep_key)
-                       ret = iwl_remove_default_wep_key(priv, ctx, key);
-               else
-                       ret = iwl_remove_dynamic_key(priv, ctx, key, sta);
-
-               IWL_DEBUG_MAC80211(priv, "disable hwcrypto key\n");
-               break;
-       default:
-               ret = -EINVAL;
-       }
-
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       return ret;
-}
-
-static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
-                                  struct ieee80211_vif *vif,
-                                  enum ieee80211_ampdu_mlme_action action,
-                                  struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                                  u8 buf_size)
-{
-       struct iwl_priv *priv = hw->priv;
-       int ret = -EINVAL;
-       struct iwl_station_priv *sta_priv = (void *) sta->drv_priv;
-       struct iwl_rxon_context *ctx =  iwl_rxon_ctx_from_vif(vif);
-
-       IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n",
-                    sta->addr, tid);
-
-       if (!(priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE))
-               return -EACCES;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->shrd->mutex);
-
-       switch (action) {
-       case IEEE80211_AMPDU_RX_START:
-               IWL_DEBUG_HT(priv, "start Rx\n");
-               ret = iwl_sta_rx_agg_start(priv, sta, tid, *ssn);
-               break;
-       case IEEE80211_AMPDU_RX_STOP:
-               IWL_DEBUG_HT(priv, "stop Rx\n");
-               ret = iwl_sta_rx_agg_stop(priv, sta, tid);
-               if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
-                       ret = 0;
-               break;
-       case IEEE80211_AMPDU_TX_START:
-               IWL_DEBUG_HT(priv, "start Tx\n");
-               ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn);
-               break;
-       case IEEE80211_AMPDU_TX_STOP:
-               IWL_DEBUG_HT(priv, "stop Tx\n");
-               ret = iwlagn_tx_agg_stop(priv, vif, sta, tid);
-               if ((ret == 0) && (priv->agg_tids_count > 0)) {
-                       priv->agg_tids_count--;
-                       IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n",
-                                    priv->agg_tids_count);
-               }
-               if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
-                       ret = 0;
-               if (!priv->agg_tids_count && priv->cfg->ht_params &&
-                   priv->cfg->ht_params->use_rts_for_aggregation) {
-                       /*
-                        * switch off RTS/CTS if it was previously enabled
-                        */
-                       sta_priv->lq_sta.lq.general_params.flags &=
-                               ~LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK;
-                       iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif),
-                                       &sta_priv->lq_sta.lq, CMD_ASYNC, false);
-               }
-               break;
-       case IEEE80211_AMPDU_TX_OPERATIONAL:
-               buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF);
-
-               iwl_trans_tx_agg_setup(trans(priv), ctx->ctxid, iwl_sta_id(sta),
-                               tid, buf_size);
-
-               /*
-                * If the limit is 0, then it wasn't initialised yet,
-                * use the default. We can do that since we take the
-                * minimum below, and we don't want to go above our
-                * default due to hardware restrictions.
-                */
-               if (sta_priv->max_agg_bufsize == 0)
-                       sta_priv->max_agg_bufsize =
-                               LINK_QUAL_AGG_FRAME_LIMIT_DEF;
-
-               /*
-                * Even though in theory the peer could have different
-                * aggregation reorder buffer sizes for different sessions,
-                * our ucode doesn't allow for that and has a global limit
-                * for each station. Therefore, use the minimum of all the
-                * aggregation sessions and our default value.
-                */
-               sta_priv->max_agg_bufsize =
-                       min(sta_priv->max_agg_bufsize, buf_size);
-
-               if (priv->cfg->ht_params &&
-                   priv->cfg->ht_params->use_rts_for_aggregation) {
-                       /*
-                        * switch to RTS/CTS if it is the prefer protection
-                        * method for HT traffic
-                        */
-
-                       sta_priv->lq_sta.lq.general_params.flags |=
-                               LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK;
-               }
-               priv->agg_tids_count++;
-               IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n",
-                            priv->agg_tids_count);
-
-               sta_priv->lq_sta.lq.agg_params.agg_frame_cnt_limit =
-                       sta_priv->max_agg_bufsize;
-
-               iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif),
-                               &sta_priv->lq_sta.lq, CMD_ASYNC, false);
-
-               IWL_INFO(priv, "Tx aggregation enabled on ra = %pM tid = %d\n",
-                        sta->addr, tid);
-               ret = 0;
-               break;
-       }
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-       return ret;
-}
-
-static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
-                             struct ieee80211_vif *vif,
-                             struct ieee80211_sta *sta)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
-       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
-       bool is_ap = vif->type == NL80211_IFTYPE_STATION;
-       int ret = 0;
-       u8 sta_id;
-
-       IWL_DEBUG_MAC80211(priv, "received request to add station %pM\n",
-                       sta->addr);
-       mutex_lock(&priv->shrd->mutex);
-       IWL_DEBUG_INFO(priv, "proceeding to add station %pM\n",
-                       sta->addr);
-       sta_priv->sta_id = IWL_INVALID_STATION;
-
-       atomic_set(&sta_priv->pending_frames, 0);
-       if (vif->type == NL80211_IFTYPE_AP)
-               sta_priv->client = true;
-
-       ret = iwl_add_station_common(priv, vif_priv->ctx, sta->addr,
-                                    is_ap, sta, &sta_id);
-       if (ret) {
-               IWL_ERR(priv, "Unable to add station %pM (%d)\n",
-                       sta->addr, ret);
-               /* Should we return success if return code is EEXIST ? */
-               goto out;
-       }
-
-       sta_priv->sta_id = sta_id;
-
-       /* Initialize rate scaling */
-       IWL_DEBUG_INFO(priv, "Initializing rate scaling for station %pM\n",
-                      sta->addr);
-       iwl_rs_rate_init(priv, sta, sta_id);
- out:
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       return ret;
-}
-
-static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
-                               struct ieee80211_channel_switch *ch_switch)
-{
-       struct iwl_priv *priv = hw->priv;
-       const struct iwl_channel_info *ch_info;
-       struct ieee80211_conf *conf = &hw->conf;
-       struct ieee80211_channel *channel = ch_switch->channel;
-       struct iwl_ht_config *ht_conf = &priv->current_ht_config;
-       /*
-        * MULTI-FIXME
-        * When we add support for multiple interfaces, we need to
-        * revisit this. The channel switch command in the device
-        * only affects the BSS context, but what does that really
-        * mean? And what if we get a CSA on the second interface?
-        * This needs a lot of work.
-        */
-       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-       u16 ch;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-
-       mutex_lock(&priv->shrd->mutex);
-
-       if (iwl_is_rfkill(priv->shrd))
-               goto out;
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status) ||
-           test_bit(STATUS_SCANNING, &priv->shrd->status) ||
-           test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status))
-               goto out;
-
-       if (!iwl_is_associated_ctx(ctx))
-               goto out;
-
-       if (!priv->cfg->lib->set_channel_switch)
-               goto out;
-
-       ch = channel->hw_value;
-       if (le16_to_cpu(ctx->active.channel) == ch)
-               goto out;
-
-       ch_info = iwl_get_channel_info(priv, channel->band, ch);
-       if (!is_channel_valid(ch_info)) {
-               IWL_DEBUG_MAC80211(priv, "invalid channel\n");
-               goto out;
-       }
-
-       spin_lock_irq(&priv->shrd->lock);
-
-       priv->current_ht_config.smps = conf->smps_mode;
-
-       /* Configure HT40 channels */
-       ctx->ht.enabled = conf_is_ht(conf);
-       if (ctx->ht.enabled) {
-               if (conf_is_ht40_minus(conf)) {
-                       ctx->ht.extension_chan_offset =
-                               IEEE80211_HT_PARAM_CHA_SEC_BELOW;
-                       ctx->ht.is_40mhz = true;
-               } else if (conf_is_ht40_plus(conf)) {
-                       ctx->ht.extension_chan_offset =
-                               IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
-                       ctx->ht.is_40mhz = true;
-               } else {
-                       ctx->ht.extension_chan_offset =
-                               IEEE80211_HT_PARAM_CHA_SEC_NONE;
-                       ctx->ht.is_40mhz = false;
-               }
-       } else
-               ctx->ht.is_40mhz = false;
-
-       if ((le16_to_cpu(ctx->staging.channel) != ch))
-               ctx->staging.flags = 0;
-
-       iwl_set_rxon_channel(priv, channel, ctx);
-       iwl_set_rxon_ht(priv, ht_conf);
-       iwl_set_flags_for_band(priv, ctx, channel->band, ctx->vif);
-
-       spin_unlock_irq(&priv->shrd->lock);
-
-       iwl_set_rate(priv);
-       /*
-        * at this point, staging_rxon has the
-        * configuration for channel switch
-        */
-       set_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status);
-       priv->switch_channel = cpu_to_le16(ch);
-       if (priv->cfg->lib->set_channel_switch(priv, ch_switch)) {
-               clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status);
-               priv->switch_channel = 0;
-               ieee80211_chswitch_done(ctx->vif, false);
-       }
-
-out:
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-}
-
-static void iwlagn_configure_filter(struct ieee80211_hw *hw,
-                                   unsigned int changed_flags,
-                                   unsigned int *total_flags,
-                                   u64 multicast)
-{
-       struct iwl_priv *priv = hw->priv;
-       __le32 filter_or = 0, filter_nand = 0;
-       struct iwl_rxon_context *ctx;
-
-#define CHK(test, flag)        do { \
-       if (*total_flags & (test))              \
-               filter_or |= (flag);            \
-       else                                    \
-               filter_nand |= (flag);          \
-       } while (0)
-
-       IWL_DEBUG_MAC80211(priv, "Enter: changed: 0x%x, total: 0x%x\n",
-                       changed_flags, *total_flags);
-
-       CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK);
-       /* Setting _just_ RXON_FILTER_CTL2HOST_MSK causes FH errors */
-       CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_PROMISC_MSK);
-       CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK);
-
-#undef CHK
-
-       mutex_lock(&priv->shrd->mutex);
-
-       for_each_context(priv, ctx) {
-               ctx->staging.filter_flags &= ~filter_nand;
-               ctx->staging.filter_flags |= filter_or;
-
-               /*
-                * Not committing directly because hardware can perform a scan,
-                * but we'll eventually commit the filter flags change anyway.
-                */
-       }
-
-       mutex_unlock(&priv->shrd->mutex);
-
-       /*
-        * Receiving all multicast frames is always enabled by the
-        * default flags setup in iwl_connection_init_rx_config()
-        * since we currently do not support programming multicast
-        * filters into the device.
-        */
-       *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS |
-                       FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
-}
-
-static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop)
-{
-       struct iwl_priv *priv = hw->priv;
-
-       mutex_lock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) {
-               IWL_DEBUG_TX(priv, "Aborting flush due to device shutdown\n");
-               goto done;
-       }
-       if (iwl_is_rfkill(priv->shrd)) {
-               IWL_DEBUG_TX(priv, "Aborting flush due to RF Kill\n");
-               goto done;
-       }
-
-       /*
-        * mac80211 will not push any more frames for transmit
-        * until the flush is completed
-        */
-       if (drop) {
-               IWL_DEBUG_MAC80211(priv, "send flush command\n");
-               if (iwlagn_txfifo_flush(priv, IWL_DROP_ALL)) {
-                       IWL_ERR(priv, "flush request fail\n");
-                       goto done;
-               }
-       }
-       IWL_DEBUG_MAC80211(priv, "wait transmit/flush all frames\n");
-       iwl_trans_wait_tx_queue_empty(trans(priv));
-done:
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-}
-
-void iwlagn_disable_roc(struct iwl_priv *priv)
-{
-       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
-
-       lockdep_assert_held(&priv->shrd->mutex);
-
-       if (!priv->hw_roc_setup)
-               return;
-
-       ctx->staging.dev_type = RXON_DEV_TYPE_P2P;
-       ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-
-       priv->hw_roc_channel = NULL;
-
-       memset(ctx->staging.node_addr, 0, ETH_ALEN);
-
-       iwlagn_commit_rxon(priv, ctx);
-
-       ctx->is_active = false;
-       priv->hw_roc_setup = false;
-}
-
-static void iwlagn_disable_roc_work(struct work_struct *work)
-{
-       struct iwl_priv *priv = container_of(work, struct iwl_priv,
-                                            hw_roc_disable_work.work);
-
-       mutex_lock(&priv->shrd->mutex);
-       iwlagn_disable_roc(priv);
-       mutex_unlock(&priv->shrd->mutex);
-}
-
-static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw,
-                                    struct ieee80211_channel *channel,
-                                    enum nl80211_channel_type channel_type,
-                                    int duration)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
-       int err = 0;
-
-       if (!(priv->shrd->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
-               return -EOPNOTSUPP;
-
-       if (!(ctx->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)))
-               return -EOPNOTSUPP;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->shrd->mutex);
-
-       if (test_bit(STATUS_SCAN_HW, &priv->shrd->status)) {
-               err = -EBUSY;
-               goto out;
-       }
-
-       priv->hw_roc_channel = channel;
-       priv->hw_roc_chantype = channel_type;
-       priv->hw_roc_duration = duration;
-       priv->hw_roc_start_notified = false;
-       cancel_delayed_work(&priv->hw_roc_disable_work);
-
-       if (!ctx->is_active) {
-               ctx->is_active = true;
-               ctx->staging.dev_type = RXON_DEV_TYPE_P2P;
-               memcpy(ctx->staging.node_addr,
-                      priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr,
-                      ETH_ALEN);
-               memcpy(ctx->staging.bssid_addr,
-                      priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr,
-                      ETH_ALEN);
-               err = iwlagn_commit_rxon(priv, ctx);
-               if (err)
-                       goto out;
-               ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK |
-                                            RXON_FILTER_PROMISC_MSK |
-                                            RXON_FILTER_CTL2HOST_MSK;
-
-               err = iwlagn_commit_rxon(priv, ctx);
-               if (err) {
-                       iwlagn_disable_roc(priv);
-                       goto out;
-               }
-               priv->hw_roc_setup = true;
-       }
-
-       err = iwl_scan_initiate(priv, ctx->vif, IWL_SCAN_ROC, channel->band);
-       if (err)
-               iwlagn_disable_roc(priv);
-
- out:
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       return err;
-}
-
-static int iwlagn_mac_cancel_remain_on_channel(struct ieee80211_hw *hw)
-{
-       struct iwl_priv *priv = hw->priv;
-
-       if (!(priv->shrd->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
-               return -EOPNOTSUPP;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->shrd->mutex);
-       iwl_scan_cancel_timeout(priv, priv->hw_roc_duration);
-       iwlagn_disable_roc(priv);
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       return 0;
-}
-
-static int iwlagn_mac_tx_sync(struct ieee80211_hw *hw,
-                             struct ieee80211_vif *vif,
-                             const u8 *bssid,
-                             enum ieee80211_tx_sync_type type)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
-       struct iwl_rxon_context *ctx = vif_priv->ctx;
-       int ret;
-       u8 sta_id;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->shrd->mutex);
-
-       if (iwl_is_associated_ctx(ctx)) {
-               ret = 0;
-               goto out;
-       }
-
-       if (ctx->preauth_bssid || test_bit(STATUS_SCAN_HW, &priv->shrd->status)) {
-               ret = -EBUSY;
-               goto out;
-       }
-
-       ret = iwl_add_station_common(priv, ctx, bssid, true, NULL, &sta_id);
-       if (ret)
-               goto out;
-
-       if (WARN_ON(sta_id != ctx->ap_sta_id)) {
-               ret = -EIO;
-               goto out_remove_sta;
-       }
-
-       memcpy(ctx->bssid, bssid, ETH_ALEN);
-       ctx->preauth_bssid = true;
-
-       ret = iwlagn_commit_rxon(priv, ctx);
-
-       if (ret == 0)
-               goto out;
-
- out_remove_sta:
-       iwl_remove_station(priv, sta_id, bssid);
- out:
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       return ret;
-}
-
-static void iwlagn_mac_finish_tx_sync(struct ieee80211_hw *hw,
-                                  struct ieee80211_vif *vif,
-                                  const u8 *bssid,
-                                  enum ieee80211_tx_sync_type type)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
-       struct iwl_rxon_context *ctx = vif_priv->ctx;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->shrd->mutex);
-
-       if (iwl_is_associated_ctx(ctx))
-               goto out;
-
-       iwl_remove_station(priv, ctx->ap_sta_id, bssid);
-       ctx->preauth_bssid = false;
-       /* no need to commit */
- out:
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-}
-
-/*****************************************************************************
- *
- * driver setup and teardown
- *
- *****************************************************************************/
-
-static void iwl_setup_deferred_work(struct iwl_priv *priv)
-{
-       priv->shrd->workqueue = create_singlethread_workqueue(DRV_NAME);
-
-       init_waitqueue_head(&priv->shrd->wait_command_queue);
-
-       INIT_WORK(&priv->restart, iwl_bg_restart);
-       INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
-       INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work);
-       INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush);
-       INIT_WORK(&priv->bt_full_concurrency, iwl_bg_bt_full_concurrency);
-       INIT_WORK(&priv->bt_runtime_config, iwl_bg_bt_runtime_config);
-       INIT_DELAYED_WORK(&priv->hw_roc_disable_work,
-                         iwlagn_disable_roc_work);
-
-       iwl_setup_scan_deferred_work(priv);
-
-       if (priv->cfg->lib->bt_setup_deferred_work)
-               priv->cfg->lib->bt_setup_deferred_work(priv);
-
-       init_timer(&priv->statistics_periodic);
-       priv->statistics_periodic.data = (unsigned long)priv;
-       priv->statistics_periodic.function = iwl_bg_statistics_periodic;
-
-       init_timer(&priv->ucode_trace);
-       priv->ucode_trace.data = (unsigned long)priv;
-       priv->ucode_trace.function = iwl_bg_ucode_trace;
-
-       init_timer(&priv->watchdog);
-       priv->watchdog.data = (unsigned long)priv;
-       priv->watchdog.function = iwl_bg_watchdog;
-}
-
-static void iwl_cancel_deferred_work(struct iwl_priv *priv)
-{
-       if (priv->cfg->lib->cancel_deferred_work)
-               priv->cfg->lib->cancel_deferred_work(priv);
-
-       cancel_work_sync(&priv->run_time_calib_work);
-       cancel_work_sync(&priv->beacon_update);
-
-       iwl_cancel_scan_deferred_work(priv);
-
-       cancel_work_sync(&priv->bt_full_concurrency);
-       cancel_work_sync(&priv->bt_runtime_config);
-       cancel_delayed_work_sync(&priv->hw_roc_disable_work);
-
-       del_timer_sync(&priv->statistics_periodic);
-       del_timer_sync(&priv->ucode_trace);
-}
-
-static void iwl_init_hw_rates(struct iwl_priv *priv,
-                             struct ieee80211_rate *rates)
-{
-       int i;
-
-       for (i = 0; i < IWL_RATE_COUNT_LEGACY; i++) {
-               rates[i].bitrate = iwl_rates[i].ieee * 5;
-               rates[i].hw_value = i; /* Rate scaling will work on indexes */
-               rates[i].hw_value_short = i;
-               rates[i].flags = 0;
-               if ((i >= IWL_FIRST_CCK_RATE) && (i <= IWL_LAST_CCK_RATE)) {
-                       /*
-                        * If CCK != 1M then set short preamble rate flag.
-                        */
-                       rates[i].flags |=
-                               (iwl_rates[i].plcp == IWL_RATE_1M_PLCP) ?
-                                       0 : IEEE80211_RATE_SHORT_PREAMBLE;
-               }
-       }
-}
-
-static int iwl_init_drv(struct iwl_priv *priv)
-{
-       int ret;
-
-       spin_lock_init(&priv->shrd->sta_lock);
-
-       mutex_init(&priv->shrd->mutex);
-
-       priv->ieee_channels = NULL;
-       priv->ieee_rates = NULL;
-       priv->band = IEEE80211_BAND_2GHZ;
-
-       priv->iw_mode = NL80211_IFTYPE_STATION;
-       priv->current_ht_config.smps = IEEE80211_SMPS_STATIC;
-       priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF;
-       priv->agg_tids_count = 0;
-
-       /* initialize force reset */
-       priv->force_reset[IWL_RF_RESET].reset_duration =
-               IWL_DELAY_NEXT_FORCE_RF_RESET;
-       priv->force_reset[IWL_FW_RESET].reset_duration =
-               IWL_DELAY_NEXT_FORCE_FW_RELOAD;
-
-       priv->rx_statistics_jiffies = jiffies;
-
-       /* Choose which receivers/antennas to use */
-       iwlagn_set_rxon_chain(priv, &priv->contexts[IWL_RXON_CTX_BSS]);
-
-       iwl_init_scan_params(priv);
-
-       /* init bt coex */
-       if (priv->cfg->bt_params &&
-           priv->cfg->bt_params->advanced_bt_coexist) {
-               priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT;
-               priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT;
-               priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK;
-               priv->bt_on_thresh = BT_ON_THRESHOLD_DEF;
-               priv->bt_duration = BT_DURATION_LIMIT_DEF;
-               priv->dynamic_frag_thresh = BT_FRAG_THRESHOLD_DEF;
-       }
-
-       ret = iwl_init_channel_map(priv);
-       if (ret) {
-               IWL_ERR(priv, "initializing regulatory failed: %d\n", ret);
-               goto err;
-       }
-
-       ret = iwl_init_geos(priv);
-       if (ret) {
-               IWL_ERR(priv, "initializing geos failed: %d\n", ret);
-               goto err_free_channel_map;
-       }
-       iwl_init_hw_rates(priv, priv->ieee_rates);
-
-       return 0;
-
-err_free_channel_map:
-       iwl_free_channel_map(priv);
-err:
-       return ret;
-}
+err_free_channel_map:
+       iwl_free_channel_map(priv);
+err:
+       return ret;
+}
 
 static void iwl_uninit_drv(struct iwl_priv *priv)
 {
@@ -3062,81 +1638,13 @@ static void iwl_uninit_drv(struct iwl_priv *priv)
                kmem_cache_destroy(priv->tx_cmd_pool);
        kfree(priv->scan_cmd);
        kfree(priv->beacon_cmd);
+       kfree(rcu_dereference_raw(priv->noa_data));
 #ifdef CONFIG_IWLWIFI_DEBUGFS
        kfree(priv->wowlan_sram);
 #endif
 }
 
-static void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw,
-                          enum ieee80211_rssi_event rssi_event)
-{
-       struct iwl_priv *priv = hw->priv;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->shrd->mutex);
-
-       if (priv->cfg->bt_params &&
-                       priv->cfg->bt_params->advanced_bt_coexist) {
-               if (rssi_event == RSSI_EVENT_LOW)
-                       priv->bt_enable_pspoll = true;
-               else if (rssi_event == RSSI_EVENT_HIGH)
-                       priv->bt_enable_pspoll = false;
-
-               iwlagn_send_advance_bt_config(priv);
-       } else {
-               IWL_DEBUG_MAC80211(priv, "Advanced BT coex disabled,"
-                               "ignoring RSSI callback\n");
-       }
-
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-}
-
-static int iwlagn_mac_set_tim(struct ieee80211_hw *hw,
-                          struct ieee80211_sta *sta, bool set)
-{
-       struct iwl_priv *priv = hw->priv;
 
-       queue_work(priv->shrd->workqueue, &priv->beacon_update);
-
-       return 0;
-}
-
-struct ieee80211_ops iwlagn_hw_ops = {
-       .tx = iwlagn_mac_tx,
-       .start = iwlagn_mac_start,
-       .stop = iwlagn_mac_stop,
-#ifdef CONFIG_PM_SLEEP
-       .suspend = iwlagn_mac_suspend,
-       .resume = iwlagn_mac_resume,
-#endif
-       .add_interface = iwlagn_mac_add_interface,
-       .remove_interface = iwlagn_mac_remove_interface,
-       .change_interface = iwlagn_mac_change_interface,
-       .config = iwlagn_mac_config,
-       .configure_filter = iwlagn_configure_filter,
-       .set_key = iwlagn_mac_set_key,
-       .update_tkip_key = iwlagn_mac_update_tkip_key,
-       .set_rekey_data = iwlagn_mac_set_rekey_data,
-       .conf_tx = iwlagn_mac_conf_tx,
-       .bss_info_changed = iwlagn_bss_info_changed,
-       .ampdu_action = iwlagn_mac_ampdu_action,
-       .hw_scan = iwlagn_mac_hw_scan,
-       .sta_notify = iwlagn_mac_sta_notify,
-       .sta_add = iwlagn_mac_sta_add,
-       .sta_remove = iwlagn_mac_sta_remove,
-       .channel_switch = iwlagn_mac_channel_switch,
-       .flush = iwlagn_mac_flush,
-       .tx_last_beacon = iwlagn_mac_tx_last_beacon,
-       .remain_on_channel = iwlagn_mac_remain_on_channel,
-       .cancel_remain_on_channel = iwlagn_mac_cancel_remain_on_channel,
-       .rssi_callback = iwlagn_mac_rssi_callback,
-       CFG80211_TESTMODE_CMD(iwlagn_mac_testmode_cmd)
-       CFG80211_TESTMODE_DUMP(iwlagn_mac_testmode_dump)
-       .tx_sync = iwlagn_mac_tx_sync,
-       .finish_tx_sync = iwlagn_mac_finish_tx_sync,
-       .set_tim = iwlagn_mac_set_tim,
-};
 
 static u32 iwl_hw_detect(struct iwl_priv *priv)
 {
@@ -3170,27 +1678,7 @@ static int iwl_set_hw_params(struct iwl_priv *priv)
        return priv->cfg->lib->set_hw_params(priv);
 }
 
-/* This function both allocates and initializes hw and priv. */
-static struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg)
-{
-       struct iwl_priv *priv;
-       /* mac80211 allocates memory for this device instance, including
-        *   space for this driver's private structure */
-       struct ieee80211_hw *hw;
-
-       hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), &iwlagn_hw_ops);
-       if (hw == NULL) {
-               pr_err("%s: Can not allocate network device\n",
-                      cfg->name);
-               goto out;
-       }
-
-       priv = hw->priv;
-       priv->hw = hw;
 
-out:
-       return hw;
-}
 
 int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops,
                struct iwl_cfg *cfg)
@@ -3204,8 +1692,9 @@ int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops,
        /************************
         * 1. Allocating HW data
         ************************/
-       hw = iwl_alloc_all(cfg);
+       hw = iwl_alloc_all();
        if (!hw) {
+               pr_err("%s: Cannot allocate network device\n", cfg->name);
                err = -ENOMEM;
                goto out;
        }
@@ -3397,7 +1886,7 @@ void __devexit iwl_remove(struct iwl_priv * priv)
        /*This will stop the queues, move the device to low power state */
        iwl_trans_stop_device(trans(priv));
 
-       iwl_dealloc_ucode(priv);
+       iwl_dealloc_ucode(trans(priv));
 
        iwl_eeprom_free(priv);
 
index 5b936ec..5d8d2f4 100644 (file)
 
 #include "iwl-dev.h"
 
+struct iwlagn_ucode_capabilities {
+       u32 max_probe_length;
+       u32 standard_phy_calibration_size;
+       u32 flags;
+};
+
 extern struct ieee80211_ops iwlagn_hw_ops;
 
 int iwl_reset_ict(struct iwl_trans *trans);
@@ -77,6 +83,15 @@ static inline void iwl_set_calib_hdr(struct iwl_calib_hdr *hdr, u8 cmd)
        hdr->data_valid = 1;
 }
 
+void __iwl_down(struct iwl_priv *priv);
+void iwl_down(struct iwl_priv *priv);
+void iwlagn_prepare_restart(struct iwl_priv *priv);
+
+/* MAC80211 */
+struct ieee80211_hw *iwl_alloc_all(void);
+int iwlagn_mac_setup_register(struct iwl_priv *priv,
+                             struct iwlagn_ucode_capabilities *capa);
+
 /* RXON */
 int iwlagn_set_pan_params(struct iwl_priv *priv);
 int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
@@ -95,8 +110,7 @@ int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type);
 void iwlagn_send_prio_tbl(struct iwl_priv *priv);
 int iwlagn_run_init_ucode(struct iwl_priv *priv);
 int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv,
-                                struct fw_img *image,
-                                enum iwlagn_ucode_type ucode_type);
+                                enum iwl_ucode_type ucode_type);
 
 /* lib */
 int iwlagn_send_tx_power(struct iwl_priv *priv);
@@ -105,6 +119,12 @@ u16 iwlagn_eeprom_calib_version(struct iwl_priv *priv);
 int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control);
 void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control);
 int iwlagn_send_beacon_cmd(struct iwl_priv *priv);
+#ifdef CONFIG_PM_SLEEP
+int iwlagn_send_patterns(struct iwl_priv *priv,
+                        struct cfg80211_wowlan *wowlan);
+int iwlagn_suspend(struct iwl_priv *priv,
+                  struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan);
+#endif
 
 /* rx */
 int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band);
@@ -196,9 +216,6 @@ int iwl_add_station_common(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
                           struct ieee80211_sta *sta, u8 *sta_id_r);
 int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
                       const u8 *addr);
-int iwlagn_mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
-                      struct ieee80211_sta *sta);
-
 u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
                    const u8 *addr, bool is_ap, struct ieee80211_sta *sta);
 
@@ -316,10 +333,6 @@ void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt);
 int iwl_update_bcast_station(struct iwl_priv *priv,
                             struct iwl_rxon_context *ctx);
 int iwl_update_bcast_stations(struct iwl_priv *priv);
-void iwlagn_mac_sta_notify(struct ieee80211_hw *hw,
-                          struct ieee80211_vif *vif,
-                          enum sta_notify_cmd cmd,
-                          struct ieee80211_sta *sta);
 
 /* rate */
 static inline u32 iwl_ant_idx_to_flags(u8 ant_idx)
index 2a2dc45..e1d7825 100644 (file)
@@ -101,17 +101,11 @@ extern struct iwl_cfg iwl100_bg_cfg;
 extern struct iwl_cfg iwl130_bgn_cfg;
 extern struct iwl_cfg iwl130_bg_cfg;
 extern struct iwl_cfg iwl2000_2bgn_cfg;
-extern struct iwl_cfg iwl2000_2bg_cfg;
 extern struct iwl_cfg iwl2000_2bgn_d_cfg;
 extern struct iwl_cfg iwl2030_2bgn_cfg;
-extern struct iwl_cfg iwl2030_2bg_cfg;
 extern struct iwl_cfg iwl6035_2agn_cfg;
-extern struct iwl_cfg iwl6035_2abg_cfg;
-extern struct iwl_cfg iwl6035_2bg_cfg;
-extern struct iwl_cfg iwl105_bg_cfg;
 extern struct iwl_cfg iwl105_bgn_cfg;
 extern struct iwl_cfg iwl105_bgn_d_cfg;
-extern struct iwl_cfg iwl135_bg_cfg;
 extern struct iwl_cfg iwl135_bgn_cfg;
 
 #endif /* __iwl_pci_h__ */
index 69d5f85..f4eccf5 100644 (file)
@@ -198,6 +198,7 @@ enum {
        REPLY_WOWLAN_TKIP_PARAMS = 0xe3,
        REPLY_WOWLAN_KEK_KCK_MATERIAL = 0xe4,
        REPLY_WOWLAN_GET_STATUS = 0xe5,
+       REPLY_D3_CONFIG = 0xd3,
 
        REPLY_MAX = 0xff
 };
@@ -3801,6 +3802,19 @@ struct iwl_bt_coex_prot_env_cmd {
 } __attribute__((packed));
 
 /*
+ * REPLY_D3_CONFIG
+ */
+enum iwlagn_d3_wakeup_filters {
+       IWLAGN_D3_WAKEUP_RFKILL         = BIT(0),
+       IWLAGN_D3_WAKEUP_SYSASSERT      = BIT(1),
+};
+
+struct iwlagn_d3_config_cmd {
+       __le32 min_sleep_time;
+       __le32 wakeup_flags;
+} __packed;
+
+/*
  * REPLY_WOWLAN_PATTERNS
  */
 #define IWLAGN_WOWLAN_MIN_PATTERN_LEN  16
@@ -3830,19 +3844,16 @@ enum iwlagn_wowlan_wakeup_filters {
        IWLAGN_WOWLAN_WAKEUP_BEACON_MISS        = BIT(2),
        IWLAGN_WOWLAN_WAKEUP_LINK_CHANGE        = BIT(3),
        IWLAGN_WOWLAN_WAKEUP_GTK_REKEY_FAIL     = BIT(4),
-       IWLAGN_WOWLAN_WAKEUP_RFKILL             = BIT(5),
-       IWLAGN_WOWLAN_WAKEUP_UCODE_ERROR        = BIT(6),
-       IWLAGN_WOWLAN_WAKEUP_EAP_IDENT_REQ      = BIT(7),
-       IWLAGN_WOWLAN_WAKEUP_4WAY_HANDSHAKE     = BIT(8),
-       IWLAGN_WOWLAN_WAKEUP_ALWAYS             = BIT(9),
-       IWLAGN_WOWLAN_WAKEUP_ENABLE_NET_DETECT  = BIT(10),
+       IWLAGN_WOWLAN_WAKEUP_EAP_IDENT_REQ      = BIT(5),
+       IWLAGN_WOWLAN_WAKEUP_4WAY_HANDSHAKE     = BIT(6),
+       IWLAGN_WOWLAN_WAKEUP_ALWAYS             = BIT(7),
+       IWLAGN_WOWLAN_WAKEUP_ENABLE_NET_DETECT  = BIT(8),
 };
 
 struct iwlagn_wowlan_wakeup_filter_cmd {
        __le32 enabled;
        __le16 non_qos_seq;
-       u8 min_sleep_seconds;
-       u8 reserved;
+       __le16 reserved;
        __le16 qos_seq[8];
 };
 
index 001fdf1..f9e9170 100644 (file)
@@ -1120,229 +1120,8 @@ int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear)
                                        &statistics_cmd);
 }
 
-int iwlagn_mac_conf_tx(struct ieee80211_hw *hw,
-                   struct ieee80211_vif *vif, u16 queue,
-                   const struct ieee80211_tx_queue_params *params)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwl_rxon_context *ctx;
-       unsigned long flags;
-       int q;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-
-       if (!iwl_is_ready_rf(priv->shrd)) {
-               IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
-               return -EIO;
-       }
-
-       if (queue >= AC_NUM) {
-               IWL_DEBUG_MAC80211(priv, "leave - queue >= AC_NUM %d\n", queue);
-               return 0;
-       }
-
-       q = AC_NUM - 1 - queue;
-
-       spin_lock_irqsave(&priv->shrd->lock, flags);
-
-       /*
-        * MULTI-FIXME
-        * This may need to be done per interface in nl80211/cfg80211/mac80211.
-        */
-       for_each_context(priv, ctx) {
-               ctx->qos_data.def_qos_parm.ac[q].cw_min =
-                       cpu_to_le16(params->cw_min);
-               ctx->qos_data.def_qos_parm.ac[q].cw_max =
-                       cpu_to_le16(params->cw_max);
-               ctx->qos_data.def_qos_parm.ac[q].aifsn = params->aifs;
-               ctx->qos_data.def_qos_parm.ac[q].edca_txop =
-                               cpu_to_le16((params->txop * 32));
-
-               ctx->qos_data.def_qos_parm.ac[q].reserved1 = 0;
-       }
-
-       spin_unlock_irqrestore(&priv->shrd->lock, flags);
-
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-       return 0;
-}
-
-int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw)
-{
-       struct iwl_priv *priv = hw->priv;
-
-       return priv->ibss_manager == IWL_IBSS_MANAGER;
-}
-
-static int iwl_set_mode(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
-{
-       iwl_connection_init_rx_config(priv, ctx);
-
-       iwlagn_set_rxon_chain(priv, ctx);
-
-       return iwlagn_commit_rxon(priv, ctx);
-}
-
-static int iwl_setup_interface(struct iwl_priv *priv,
-                              struct iwl_rxon_context *ctx)
-{
-       struct ieee80211_vif *vif = ctx->vif;
-       int err;
-
-       lockdep_assert_held(&priv->shrd->mutex);
-
-       /*
-        * This variable will be correct only when there's just
-        * a single context, but all code using it is for hardware
-        * that supports only one context.
-        */
-       priv->iw_mode = vif->type;
-
-       ctx->is_active = true;
-
-       err = iwl_set_mode(priv, ctx);
-       if (err) {
-               if (!ctx->always_active)
-                       ctx->is_active = false;
-               return err;
-       }
-
-       if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist &&
-           vif->type == NL80211_IFTYPE_ADHOC) {
-               /*
-                * pretend to have high BT traffic as long as we
-                * are operating in IBSS mode, as this will cause
-                * the rate scaling etc. to behave as intended.
-                */
-               priv->bt_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
-       }
-
-       return 0;
-}
-
-int iwlagn_mac_add_interface(struct ieee80211_hw *hw,
-                            struct ieee80211_vif *vif)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
-       struct iwl_rxon_context *tmp, *ctx = NULL;
-       int err;
-       enum nl80211_iftype viftype = ieee80211_vif_type_p2p(vif);
-
-       IWL_DEBUG_MAC80211(priv, "enter: type %d, addr %pM\n",
-                          viftype, vif->addr);
-
-       cancel_delayed_work_sync(&priv->hw_roc_disable_work);
-
-       mutex_lock(&priv->shrd->mutex);
-
-       iwlagn_disable_roc(priv);
-
-       if (!iwl_is_ready_rf(priv->shrd)) {
-               IWL_WARN(priv, "Try to add interface when device not ready\n");
-               err = -EINVAL;
-               goto out;
-       }
-
-       for_each_context(priv, tmp) {
-               u32 possible_modes =
-                       tmp->interface_modes | tmp->exclusive_interface_modes;
-
-               if (tmp->vif) {
-                       /* check if this busy context is exclusive */
-                       if (tmp->exclusive_interface_modes &
-                                               BIT(tmp->vif->type)) {
-                               err = -EINVAL;
-                               goto out;
-                       }
-                       continue;
-               }
-
-               if (!(possible_modes & BIT(viftype)))
-                       continue;
 
-               /* have maybe usable context w/o interface */
-               ctx = tmp;
-               break;
-       }
-
-       if (!ctx) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       vif_priv->ctx = ctx;
-       ctx->vif = vif;
-
-       err = iwl_setup_interface(priv, ctx);
-       if (!err)
-               goto out;
 
-       ctx->vif = NULL;
-       priv->iw_mode = NL80211_IFTYPE_STATION;
- out:
-       mutex_unlock(&priv->shrd->mutex);
-
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-       return err;
-}
-
-static void iwl_teardown_interface(struct iwl_priv *priv,
-                                  struct ieee80211_vif *vif,
-                                  bool mode_change)
-{
-       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
-
-       lockdep_assert_held(&priv->shrd->mutex);
-
-       if (priv->scan_vif == vif) {
-               iwl_scan_cancel_timeout(priv, 200);
-               iwl_force_scan_end(priv);
-       }
-
-       if (!mode_change) {
-               iwl_set_mode(priv, ctx);
-               if (!ctx->always_active)
-                       ctx->is_active = false;
-       }
-
-       /*
-        * When removing the IBSS interface, overwrite the
-        * BT traffic load with the stored one from the last
-        * notification, if any. If this is a device that
-        * doesn't implement this, this has no effect since
-        * both values are the same and zero.
-        */
-       if (vif->type == NL80211_IFTYPE_ADHOC)
-               priv->bt_traffic_load = priv->last_bt_traffic_load;
-}
-
-void iwlagn_mac_remove_interface(struct ieee80211_hw *hw,
-                             struct ieee80211_vif *vif)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-
-       mutex_lock(&priv->shrd->mutex);
-
-       if (WARN_ON(ctx->vif != vif)) {
-               struct iwl_rxon_context *tmp;
-               IWL_ERR(priv, "ctx->vif = %p, vif = %p\n", ctx->vif, vif);
-               for_each_context(priv, tmp)
-                       IWL_ERR(priv, "\tID = %d:\tctx = %p\tctx->vif = %p\n",
-                               tmp->ctxid, tmp, tmp->vif);
-       }
-       ctx->vif = NULL;
-
-       iwl_teardown_interface(priv, vif, false);
-
-       mutex_unlock(&priv->shrd->mutex);
-
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-}
 
 #ifdef CONFIG_IWLWIFI_DEBUGFS
 
@@ -1649,97 +1428,13 @@ int iwl_force_reset(struct iwl_priv *priv, int mode, bool external)
        return 0;
 }
 
-int iwlagn_mac_change_interface(struct ieee80211_hw *hw,
-                               struct ieee80211_vif *vif,
-                               enum nl80211_iftype newtype, bool newp2p)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
-       struct iwl_rxon_context *bss_ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-       struct iwl_rxon_context *tmp;
-       enum nl80211_iftype newviftype = newtype;
-       u32 interface_modes;
-       int err;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-
-       newtype = ieee80211_iftype_p2p(newtype, newp2p);
-
-       mutex_lock(&priv->shrd->mutex);
-
-       if (!ctx->vif || !iwl_is_ready_rf(priv->shrd)) {
-               /*
-                * Huh? But wait ... this can maybe happen when
-                * we're in the middle of a firmware restart!
-                */
-               err = -EBUSY;
-               goto out;
-       }
-
-       interface_modes = ctx->interface_modes | ctx->exclusive_interface_modes;
-
-       if (!(interface_modes & BIT(newtype))) {
-               err = -EBUSY;
-               goto out;
-       }
-
-       /*
-        * Refuse a change that should be done by moving from the PAN
-        * context to the BSS context instead, if the BSS context is
-        * available and can support the new interface type.
-        */
-       if (ctx->ctxid == IWL_RXON_CTX_PAN && !bss_ctx->vif &&
-           (bss_ctx->interface_modes & BIT(newtype) ||
-            bss_ctx->exclusive_interface_modes & BIT(newtype))) {
-               BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
-               err = -EBUSY;
-               goto out;
-       }
-
-       if (ctx->exclusive_interface_modes & BIT(newtype)) {
-               for_each_context(priv, tmp) {
-                       if (ctx == tmp)
-                               continue;
-
-                       if (!tmp->vif)
-                               continue;
-
-                       /*
-                        * The current mode switch would be exclusive, but
-                        * another context is active ... refuse the switch.
-                        */
-                       err = -EBUSY;
-                       goto out;
-               }
-       }
-
-       /* success */
-       iwl_teardown_interface(priv, vif, true);
-       vif->type = newviftype;
-       vif->p2p = newp2p;
-       err = iwl_setup_interface(priv, ctx);
-       WARN_ON(err);
-       /*
-        * We've switched internally, but submitting to the
-        * device may have failed for some reason. Mask this
-        * error, because otherwise mac80211 will not switch
-        * (and set the interface type back) and we'll be
-        * out of sync with it.
-        */
-       err = 0;
-
- out:
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       return err;
-}
 
 int iwl_cmd_echo_test(struct iwl_priv *priv)
 {
        int ret;
        struct iwl_host_cmd cmd = {
                .id = REPLY_ECHO,
+               .len = { 0 },
                .flags = CMD_SYNC,
        };
 
index 137da33..fa47f75 100644 (file)
@@ -237,10 +237,6 @@ struct iwl_cfg {
  *   L i b                 *
  ***************************/
 
-int iwlagn_mac_conf_tx(struct ieee80211_hw *hw,
-                   struct ieee80211_vif *vif, u16 queue,
-                   const struct ieee80211_tx_queue_params *params);
-int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw);
 void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
                           int hw_decrypt);
 int iwl_check_rxon_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
@@ -260,13 +256,6 @@ bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
 void iwl_connection_init_rx_config(struct iwl_priv *priv,
                                   struct iwl_rxon_context *ctx);
 void iwl_set_rate(struct iwl_priv *priv);
-int iwlagn_mac_add_interface(struct ieee80211_hw *hw,
-                         struct ieee80211_vif *vif);
-void iwlagn_mac_remove_interface(struct ieee80211_hw *hw,
-                             struct ieee80211_vif *vif);
-int iwlagn_mac_change_interface(struct ieee80211_hw *hw,
-                            struct ieee80211_vif *vif,
-                            enum nl80211_iftype newtype, bool newp2p);
 int iwl_cmd_echo_test(struct iwl_priv *priv);
 #ifdef CONFIG_IWLWIFI_DEBUGFS
 int iwl_alloc_traffic_mem(struct iwl_priv *priv);
@@ -323,9 +312,6 @@ void iwl_init_scan_params(struct iwl_priv *priv);
 int iwl_scan_cancel(struct iwl_priv *priv);
 void iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
 void iwl_force_scan_end(struct iwl_priv *priv);
-int iwlagn_mac_hw_scan(struct ieee80211_hw *hw,
-                   struct ieee80211_vif *vif,
-                   struct cfg80211_scan_request *req);
 void iwl_internal_short_hw_scan(struct iwl_priv *priv);
 int iwl_force_reset(struct iwl_priv *priv, int mode, bool external);
 u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
index b9f3267..fbc3095 100644 (file)
 #define CSR_HW_REV_TYPE_6x35          CSR_HW_REV_TYPE_6x05
 #define CSR_HW_REV_TYPE_2x30          (0x00000C0)
 #define CSR_HW_REV_TYPE_2x00          (0x0000100)
-#define CSR_HW_REV_TYPE_200           (0x0000110)
-#define CSR_HW_REV_TYPE_230           (0x0000120)
+#define CSR_HW_REV_TYPE_105           (0x0000110)
+#define CSR_HW_REV_TYPE_135           (0x0000120)
 #define CSR_HW_REV_TYPE_NONE           (0x00001F0)
 
 /* EEPROM REG */
index 69a77e2..40ef97b 100644 (file)
@@ -70,10 +70,25 @@ do {                                                                \
                               DUMP_PREFIX_OFFSET, 16, 1, p, len, 1);   \
 } while (0)
 
+#define IWL_DEBUG_QUIET_RFKILL(p, fmt, args...)                        \
+do {                                                                   \
+       if (!iwl_is_rfkill(p->shrd))                            \
+               dev_printk(KERN_ERR, bus(p)->dev, "%c %s " fmt, \
+               (in_interrupt() ? 'I' : 'U'), __func__ , ##args);       \
+       else if (iwl_get_debug_level(p->shrd) & IWL_DL_RADIO)   \
+               dev_printk(KERN_ERR, bus(p)->dev, "(RFKILL) %c %s " fmt, \
+               (in_interrupt() ? 'I' : 'U'), __func__ , ##args);       \
+} while (0)
+
 #else
 #define IWL_DEBUG(m, level, fmt, args...)
 #define IWL_DEBUG_LIMIT(m, level, fmt, args...)
 #define iwl_print_hex_dump(m, level, p, len)
+#define IWL_DEBUG_QUIET_RFKILL(p, fmt, args...)        \
+do {                                                   \
+       if (!iwl_is_rfkill(p->shrd))                    \
+               IWL_ERR(p, fmt, ##args);                \
+} while (0)
 #endif                         /* CONFIG_IWLWIFI_DEBUG */
 
 #ifdef CONFIG_IWLWIFI_DEBUGFS
@@ -151,7 +166,7 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv)
 #define IWL_DL_11H             (1 << 28)
 #define IWL_DL_STATS           (1 << 29)
 #define IWL_DL_TX_REPLY                (1 << 30)
-#define IWL_DL_QOS             (1 << 31)
+#define IWL_DL_TX_QUEUES       (1 << 31)
 
 #define IWL_DEBUG_INFO(p, f, a...)     IWL_DEBUG(p, IWL_DL_INFO, f, ## a)
 #define IWL_DEBUG_MAC80211(p, f, a...) IWL_DEBUG(p, IWL_DL_MAC80211, f, ## a)
@@ -188,7 +203,7 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv)
 #define IWL_DEBUG_TX_REPLY(p, f, a...) IWL_DEBUG(p, IWL_DL_TX_REPLY, f, ## a)
 #define IWL_DEBUG_TX_REPLY_LIMIT(p, f, a...) \
                IWL_DEBUG_LIMIT(p, IWL_DL_TX_REPLY, f, ## a)
-#define IWL_DEBUG_QOS(p, f, a...)      IWL_DEBUG(p, IWL_DL_QOS, f, ## a)
+#define IWL_DEBUG_TX_QUEUES(p, f, a...)        IWL_DEBUG(p, IWL_DL_TX_QUEUES, f, ## a)
 #define IWL_DEBUG_RADIO(p, f, a...)    IWL_DEBUG(p, IWL_DL_RADIO, f, ## a)
 #define IWL_DEBUG_POWER(p, f, a...)    IWL_DEBUG(p, IWL_DL_POWER, f, ## a)
 #define IWL_DEBUG_11H(p, f, a...)      IWL_DEBUG(p, IWL_DL_11H, f, ## a)
index a1670e3..68b04f5 100644 (file)
@@ -236,9 +236,9 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
        if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) {
                priv->dbgfs_sram_offset = 0x800000;
                if (priv->ucode_type == IWL_UCODE_INIT)
-                       priv->dbgfs_sram_len = priv->ucode_init.data.len;
+                       priv->dbgfs_sram_len = trans(priv)->ucode_init.data.len;
                else
-                       priv->dbgfs_sram_len = priv->ucode_rt.data.len;
+                       priv->dbgfs_sram_len = trans(priv)->ucode_rt.data.len;
        }
        len = priv->dbgfs_sram_len;
 
@@ -341,7 +341,7 @@ static ssize_t iwl_dbgfs_wowlan_sram_read(struct file *file,
 
        return simple_read_from_buffer(user_buf, count, ppos,
                                       priv->wowlan_sram,
-                                      priv->ucode_wowlan.data.len);
+                                      trans(priv)->ucode_wowlan.data.len);
 }
 static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
                                        size_t count, loff_t *ppos)
@@ -430,7 +430,7 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file,
        eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
        pos += scnprintf(buf + pos, buf_size - pos, "NVM Type: %s, "
                        "version: 0x%x\n",
-                       (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
+                       (trans(priv)->nvm_device_type == NVM_DEVICE_TYPE_OTP)
                         ? "OTP" : "EEPROM", eeprom_ver);
        for (ofs = 0 ; ofs < eeprom_len ; ofs += 16) {
                pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x ", ofs);
index 6c00a44..556e4a2 100644 (file)
@@ -230,17 +230,6 @@ struct iwl_vif_priv {
        u8 ibss_bssid_sta_id;
 };
 
-/* one for each uCode image (inst/data, boot/init/runtime) */
-struct fw_desc {
-       void *v_addr;           /* access by driver */
-       dma_addr_t p_addr;      /* access by card's busmaster DMA */
-       u32 len;                /* bytes */
-};
-
-struct fw_img {
-       struct fw_desc code, data;
-};
-
 /* v1/v2 uCode file layout */
 struct iwl_ucode_header {
        __le32 ver;     /* major/minor/API/serial */
@@ -805,13 +794,6 @@ enum iwl_scan_type {
        IWL_SCAN_ROC,
 };
 
-enum iwlagn_ucode_type {
-       IWL_UCODE_NONE,
-       IWL_UCODE_REGULAR,
-       IWL_UCODE_INIT,
-       IWL_UCODE_WOWLAN,
-};
-
 #ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL
 struct iwl_testmode_trace {
        u32 buff_size;
@@ -824,6 +806,12 @@ struct iwl_testmode_trace {
 };
 #endif
 
+struct iwl_wipan_noa_data {
+       struct rcu_head rcu_head;
+       u32 length;
+       u8 data[];
+};
+
 struct iwl_priv {
 
        /*data shared among all the driver's layers */
@@ -883,6 +871,8 @@ struct iwl_priv {
        /* init calibration results */
        struct iwl_calib_result calib_results[IWL_CALIB_MAX];
 
+       struct iwl_wipan_noa_data __rcu *noa_data;
+
        /* Scan related variables */
        unsigned long scan_start;
        unsigned long scan_start_tsf;
@@ -907,12 +897,7 @@ struct iwl_priv {
        u32 ucode_ver;                  /* version of ucode, copy of
                                           iwl_ucode.ver */
 
-       struct fw_img ucode_rt;
-       struct fw_img ucode_init;
-       struct fw_img ucode_wowlan;
-
-       enum iwlagn_ucode_type ucode_type;
-       u8 ucode_write_complete;        /* the image write is complete */
+       enum iwl_ucode_type ucode_type;
        char firmware_name[25];
 
        struct iwl_rxon_context contexts[NUM_IWL_RXON_CTX];
@@ -959,7 +944,6 @@ struct iwl_priv {
 
        /* eeprom -- this is in the card's little endian byte order */
        u8 *eeprom;
-       int    nvm_device_type;
        struct iwl_eeprom_calib_info *calib_info;
 
        enum nl80211_iftype iw_mode;
index a635a7e..2a2c8de 100644 (file)
@@ -28,7 +28,7 @@
 
 /* sparse doesn't like tracepoint macros */
 #ifndef __CHECKER__
-#include "iwl-dev.h"
+#include "iwl-trans.h"
 
 #define CREATE_TRACE_POINTS
 #include "iwl-devtrace.h"
index 8a51c5c..f9d3319 100644 (file)
@@ -29,7 +29,6 @@
 
 #include <linux/tracepoint.h>
 
-struct iwl_priv;
 
 #if !defined(CONFIG_IWLWIFI_DEVICE_TRACING) || defined(__CHECKER__)
 #undef TRACE_EVENT
@@ -37,14 +36,14 @@ struct iwl_priv;
 static inline void trace_ ## name(proto) {}
 #endif
 
-#define PRIV_ENTRY     __field(struct iwl_priv *, priv)
+#define PRIV_ENTRY     __field(void *, priv)
 #define PRIV_ASSIGN    __entry->priv = priv
 
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM iwlwifi_io
 
 TRACE_EVENT(iwlwifi_dev_ioread32,
-       TP_PROTO(struct iwl_priv *priv, u32 offs, u32 val),
+       TP_PROTO(void *priv, u32 offs, u32 val),
        TP_ARGS(priv, offs, val),
        TP_STRUCT__entry(
                PRIV_ENTRY
@@ -60,7 +59,7 @@ TRACE_EVENT(iwlwifi_dev_ioread32,
 );
 
 TRACE_EVENT(iwlwifi_dev_iowrite8,
-       TP_PROTO(struct iwl_priv *priv, u32 offs, u8 val),
+       TP_PROTO(void *priv, u32 offs, u8 val),
        TP_ARGS(priv, offs, val),
        TP_STRUCT__entry(
                PRIV_ENTRY
@@ -76,7 +75,7 @@ TRACE_EVENT(iwlwifi_dev_iowrite8,
 );
 
 TRACE_EVENT(iwlwifi_dev_iowrite32,
-       TP_PROTO(struct iwl_priv *priv, u32 offs, u32 val),
+       TP_PROTO(void *priv, u32 offs, u32 val),
        TP_ARGS(priv, offs, val),
        TP_STRUCT__entry(
                PRIV_ENTRY
@@ -95,7 +94,7 @@ TRACE_EVENT(iwlwifi_dev_iowrite32,
 #define TRACE_SYSTEM iwlwifi_ucode
 
 TRACE_EVENT(iwlwifi_dev_ucode_cont_event,
-       TP_PROTO(struct iwl_priv *priv, u32 time, u32 data, u32 ev),
+       TP_PROTO(void *priv, u32 time, u32 data, u32 ev),
        TP_ARGS(priv, time, data, ev),
        TP_STRUCT__entry(
                PRIV_ENTRY
@@ -115,7 +114,7 @@ TRACE_EVENT(iwlwifi_dev_ucode_cont_event,
 );
 
 TRACE_EVENT(iwlwifi_dev_ucode_wrap_event,
-       TP_PROTO(struct iwl_priv *priv, u32 wraps, u32 n_entry, u32 p_entry),
+       TP_PROTO(void *priv, u32 wraps, u32 n_entry, u32 p_entry),
        TP_ARGS(priv, wraps, n_entry, p_entry),
        TP_STRUCT__entry(
                PRIV_ENTRY
@@ -139,7 +138,7 @@ TRACE_EVENT(iwlwifi_dev_ucode_wrap_event,
 #define TRACE_SYSTEM iwlwifi
 
 TRACE_EVENT(iwlwifi_dev_hcmd,
-       TP_PROTO(struct iwl_priv *priv, u32 flags,
+       TP_PROTO(void *priv, u32 flags,
                 const void *hcmd0, size_t len0,
                 const void *hcmd1, size_t len1,
                 const void *hcmd2, size_t len2),
@@ -164,7 +163,7 @@ TRACE_EVENT(iwlwifi_dev_hcmd,
 );
 
 TRACE_EVENT(iwlwifi_dev_rx,
-       TP_PROTO(struct iwl_priv *priv, void *rxbuf, size_t len),
+       TP_PROTO(void *priv, void *rxbuf, size_t len),
        TP_ARGS(priv, rxbuf, len),
        TP_STRUCT__entry(
                PRIV_ENTRY
@@ -179,7 +178,7 @@ TRACE_EVENT(iwlwifi_dev_rx,
 );
 
 TRACE_EVENT(iwlwifi_dev_tx,
-       TP_PROTO(struct iwl_priv *priv, void *tfd, size_t tfdlen,
+       TP_PROTO(void *priv, void *tfd, size_t tfdlen,
                 void *buf0, size_t buf0_len,
                 void *buf1, size_t buf1_len),
        TP_ARGS(priv, tfd, tfdlen, buf0, buf0_len, buf1, buf1_len),
@@ -211,7 +210,7 @@ TRACE_EVENT(iwlwifi_dev_tx,
 );
 
 TRACE_EVENT(iwlwifi_dev_ucode_error,
-       TP_PROTO(struct iwl_priv *priv, u32 desc, u32 tsf_low,
+       TP_PROTO(void *priv, u32 desc, u32 tsf_low,
                 u32 data1, u32 data2, u32 line, u32 blink1,
                 u32 blink2, u32 ilink1, u32 ilink2, u32 bcon_time,
                 u32 gp1, u32 gp2, u32 gp3, u32 ucode_ver, u32 hw_ver,
@@ -271,7 +270,7 @@ TRACE_EVENT(iwlwifi_dev_ucode_error,
 );
 
 TRACE_EVENT(iwlwifi_dev_ucode_event,
-       TP_PROTO(struct iwl_priv *priv, u32 time, u32 data, u32 ev),
+       TP_PROTO(void *priv, u32 time, u32 data, u32 ev),
        TP_ARGS(priv, time, data, ev),
        TP_STRUCT__entry(
                PRIV_ENTRY
index a4e43bd..dcada08 100644 (file)
@@ -149,23 +149,23 @@ static const u8 iwl_eeprom_band_7[] = {       /* 5.2 ht40 channel */
  * EEPROM chip, not a single event, so even reads could conflict if they
  * weren't arbitrated by the semaphore.
  */
-static int iwl_eeprom_acquire_semaphore(struct iwl_priv *priv)
+static int iwl_eeprom_acquire_semaphore(struct iwl_bus *bus)
 {
        u16 count;
        int ret;
 
        for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) {
                /* Request semaphore */
-               iwl_set_bit(bus(priv), CSR_HW_IF_CONFIG_REG,
+               iwl_set_bit(bus, CSR_HW_IF_CONFIG_REG,
                            CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
 
                /* See if we got it */
-               ret = iwl_poll_bit(bus(priv), CSR_HW_IF_CONFIG_REG,
+               ret = iwl_poll_bit(bus, CSR_HW_IF_CONFIG_REG,
                                CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
                                CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
                                EEPROM_SEM_TIMEOUT);
                if (ret >= 0) {
-                       IWL_DEBUG_EEPROM(priv,
+                       IWL_DEBUG_EEPROM(bus,
                                "Acquired semaphore after %d tries.\n",
                                count+1);
                        return ret;
@@ -175,39 +175,39 @@ static int iwl_eeprom_acquire_semaphore(struct iwl_priv *priv)
        return ret;
 }
 
-static void iwl_eeprom_release_semaphore(struct iwl_priv *priv)
+static void iwl_eeprom_release_semaphore(struct iwl_bus *bus)
 {
-       iwl_clear_bit(bus(priv), CSR_HW_IF_CONFIG_REG,
+       iwl_clear_bit(bus, CSR_HW_IF_CONFIG_REG,
                CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
 
 }
 
-static int iwl_eeprom_verify_signature(struct iwl_priv *priv)
+static int iwl_eeprom_verify_signature(struct iwl_trans *trans)
 {
-       u32 gp = iwl_read32(bus(priv), CSR_EEPROM_GP) & CSR_EEPROM_GP_VALID_MSK;
+       u32 gp = iwl_read32(bus(trans), CSR_EEPROM_GP) & CSR_EEPROM_GP_VALID_MSK;
        int ret = 0;
 
-       IWL_DEBUG_EEPROM(priv, "EEPROM signature=0x%08x\n", gp);
+       IWL_DEBUG_EEPROM(trans, "EEPROM signature=0x%08x\n", gp);
        switch (gp) {
        case CSR_EEPROM_GP_BAD_SIG_EEP_GOOD_SIG_OTP:
-               if (priv->nvm_device_type != NVM_DEVICE_TYPE_OTP) {
-                       IWL_ERR(priv, "EEPROM with bad signature: 0x%08x\n",
+               if (trans->nvm_device_type != NVM_DEVICE_TYPE_OTP) {
+                       IWL_ERR(trans, "EEPROM with bad signature: 0x%08x\n",
                                gp);
                        ret = -ENOENT;
                }
                break;
        case CSR_EEPROM_GP_GOOD_SIG_EEP_LESS_THAN_4K:
        case CSR_EEPROM_GP_GOOD_SIG_EEP_MORE_THAN_4K:
-               if (priv->nvm_device_type != NVM_DEVICE_TYPE_EEPROM) {
-                       IWL_ERR(priv, "OTP with bad signature: 0x%08x\n", gp);
+               if (trans->nvm_device_type != NVM_DEVICE_TYPE_EEPROM) {
+                       IWL_ERR(trans, "OTP with bad signature: 0x%08x\n", gp);
                        ret = -ENOENT;
                }
                break;
        case CSR_EEPROM_GP_BAD_SIGNATURE_BOTH_EEP_AND_OTP:
        default:
-               IWL_ERR(priv, "bad EEPROM/OTP signature, type=%s, "
+               IWL_ERR(trans, "bad EEPROM/OTP signature, type=%s, "
                        "EEPROM_GP=0x%08x\n",
-                       (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
+                       (trans->nvm_device_type == NVM_DEVICE_TYPE_OTP)
                        ? "OTP" : "EEPROM", gp);
                ret = -ENOENT;
                break;
@@ -302,19 +302,19 @@ void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac)
  *
 ******************************************************************************/
 
-static void iwl_set_otp_access(struct iwl_priv *priv, enum iwl_access_mode mode)
+static void iwl_set_otp_access(struct iwl_bus *bus, enum iwl_access_mode mode)
 {
-       iwl_read32(bus(priv), CSR_OTP_GP_REG);
+       iwl_read32(bus, CSR_OTP_GP_REG);
 
        if (mode == IWL_OTP_ACCESS_ABSOLUTE)
-               iwl_clear_bit(bus(priv), CSR_OTP_GP_REG,
+               iwl_clear_bit(bus, CSR_OTP_GP_REG,
                              CSR_OTP_GP_REG_OTP_ACCESS_MODE);
        else
-               iwl_set_bit(bus(priv), CSR_OTP_GP_REG,
+               iwl_set_bit(bus, CSR_OTP_GP_REG,
                            CSR_OTP_GP_REG_OTP_ACCESS_MODE);
 }
 
-static int iwl_get_nvm_type(struct iwl_priv *priv, u32 hw_rev)
+static int iwl_get_nvm_type(struct iwl_bus *bus, u32 hw_rev)
 {
        u32 otpgp;
        int nvm_type;
@@ -322,7 +322,7 @@ static int iwl_get_nvm_type(struct iwl_priv *priv, u32 hw_rev)
        /* OTP only valid for CP/PP and after */
        switch (hw_rev & CSR_HW_REV_TYPE_MSK) {
        case CSR_HW_REV_TYPE_NONE:
-               IWL_ERR(priv, "Unknown hardware type\n");
+               IWL_ERR(bus, "Unknown hardware type\n");
                return -ENOENT;
        case CSR_HW_REV_TYPE_5300:
        case CSR_HW_REV_TYPE_5350:
@@ -331,7 +331,7 @@ static int iwl_get_nvm_type(struct iwl_priv *priv, u32 hw_rev)
                nvm_type = NVM_DEVICE_TYPE_EEPROM;
                break;
        default:
-               otpgp = iwl_read32(bus(priv), CSR_OTP_GP_REG);
+               otpgp = iwl_read32(bus, CSR_OTP_GP_REG);
                if (otpgp & CSR_OTP_GP_REG_DEVICE_SELECT)
                        nvm_type = NVM_DEVICE_TYPE_OTP;
                else
@@ -341,73 +341,73 @@ static int iwl_get_nvm_type(struct iwl_priv *priv, u32 hw_rev)
        return  nvm_type;
 }
 
-static int iwl_init_otp_access(struct iwl_priv *priv)
+static int iwl_init_otp_access(struct iwl_bus *bus)
 {
        int ret;
 
        /* Enable 40MHz radio clock */
-       iwl_write32(bus(priv), CSR_GP_CNTRL,
-                   iwl_read32(bus(priv), CSR_GP_CNTRL) |
+       iwl_write32(bus, CSR_GP_CNTRL,
+                   iwl_read32(bus, CSR_GP_CNTRL) |
                    CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
 
        /* wait for clock to be ready */
-       ret = iwl_poll_bit(bus(priv), CSR_GP_CNTRL,
+       ret = iwl_poll_bit(bus, CSR_GP_CNTRL,
                                 CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
                                 CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
                                 25000);
        if (ret < 0)
-               IWL_ERR(priv, "Time out access OTP\n");
+               IWL_ERR(bus, "Time out access OTP\n");
        else {
-               iwl_set_bits_prph(bus(priv), APMG_PS_CTRL_REG,
+               iwl_set_bits_prph(bus, APMG_PS_CTRL_REG,
                                  APMG_PS_CTRL_VAL_RESET_REQ);
                udelay(5);
-               iwl_clear_bits_prph(bus(priv), APMG_PS_CTRL_REG,
+               iwl_clear_bits_prph(bus, APMG_PS_CTRL_REG,
                                    APMG_PS_CTRL_VAL_RESET_REQ);
 
                /*
                 * CSR auto clock gate disable bit -
                 * this is only applicable for HW with OTP shadow RAM
                 */
-               if (priv->cfg->base_params->shadow_ram_support)
-                       iwl_set_bit(bus(priv), CSR_DBG_LINK_PWR_MGMT_REG,
+               if (priv(bus)->cfg->base_params->shadow_ram_support)
+                       iwl_set_bit(bus, CSR_DBG_LINK_PWR_MGMT_REG,
                                CSR_RESET_LINK_PWR_MGMT_DISABLED);
        }
        return ret;
 }
 
-static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, __le16 *eeprom_data)
+static int iwl_read_otp_word(struct iwl_bus *bus, u16 addr, __le16 *eeprom_data)
 {
        int ret = 0;
        u32 r;
        u32 otpgp;
 
-       iwl_write32(bus(priv), CSR_EEPROM_REG,
+       iwl_write32(bus, CSR_EEPROM_REG,
                    CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
-       ret = iwl_poll_bit(bus(priv), CSR_EEPROM_REG,
+       ret = iwl_poll_bit(bus, CSR_EEPROM_REG,
                                 CSR_EEPROM_REG_READ_VALID_MSK,
                                 CSR_EEPROM_REG_READ_VALID_MSK,
                                 IWL_EEPROM_ACCESS_TIMEOUT);
        if (ret < 0) {
-               IWL_ERR(priv, "Time out reading OTP[%d]\n", addr);
+               IWL_ERR(bus, "Time out reading OTP[%d]\n", addr);
                return ret;
        }
-       r = iwl_read32(bus(priv), CSR_EEPROM_REG);
+       r = iwl_read32(bus, CSR_EEPROM_REG);
        /* check for ECC errors: */
-       otpgp = iwl_read32(bus(priv), CSR_OTP_GP_REG);
+       otpgp = iwl_read32(bus, CSR_OTP_GP_REG);
        if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) {
                /* stop in this case */
                /* set the uncorrectable OTP ECC bit for acknowledgement */
-               iwl_set_bit(bus(priv), CSR_OTP_GP_REG,
+               iwl_set_bit(bus, CSR_OTP_GP_REG,
                        CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
-               IWL_ERR(priv, "Uncorrectable OTP ECC error, abort OTP read\n");
+               IWL_ERR(bus, "Uncorrectable OTP ECC error, abort OTP read\n");
                return -EINVAL;
        }
        if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) {
                /* continue in this case */
                /* set the correctable OTP ECC bit for acknowledgement */
-               iwl_set_bit(bus(priv), CSR_OTP_GP_REG,
+               iwl_set_bit(bus, CSR_OTP_GP_REG,
                                CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK);
-               IWL_ERR(priv, "Correctable OTP ECC error, continue read\n");
+               IWL_ERR(bus, "Correctable OTP ECC error, continue read\n");
        }
        *eeprom_data = cpu_to_le16(r >> 16);
        return 0;
@@ -416,20 +416,20 @@ static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, __le16 *eeprom_dat
 /*
  * iwl_is_otp_empty: check for empty OTP
  */
-static bool iwl_is_otp_empty(struct iwl_priv *priv)
+static bool iwl_is_otp_empty(struct iwl_bus *bus)
 {
        u16 next_link_addr = 0;
        __le16 link_value;
        bool is_empty = false;
 
        /* locate the beginning of OTP link list */
-       if (!iwl_read_otp_word(priv, next_link_addr, &link_value)) {
+       if (!iwl_read_otp_word(bus, next_link_addr, &link_value)) {
                if (!link_value) {
-                       IWL_ERR(priv, "OTP is empty\n");
+                       IWL_ERR(bus, "OTP is empty\n");
                        is_empty = true;
                }
        } else {
-               IWL_ERR(priv, "Unable to read first block of OTP list.\n");
+               IWL_ERR(bus, "Unable to read first block of OTP list.\n");
                is_empty = true;
        }
 
@@ -446,7 +446,7 @@ static bool iwl_is_otp_empty(struct iwl_priv *priv)
  *   we should read and used to configure the device.
  *   only perform this operation if shadow RAM is disabled
  */
-static int iwl_find_otp_image(struct iwl_priv *priv,
+static int iwl_find_otp_image(struct iwl_bus *bus,
                                        u16 *validblockaddr)
 {
        u16 next_link_addr = 0, valid_addr;
@@ -454,10 +454,10 @@ static int iwl_find_otp_image(struct iwl_priv *priv,
        int usedblocks = 0;
 
        /* set addressing mode to absolute to traverse the link list */
-       iwl_set_otp_access(priv, IWL_OTP_ACCESS_ABSOLUTE);
+       iwl_set_otp_access(bus, IWL_OTP_ACCESS_ABSOLUTE);
 
        /* checking for empty OTP or error */
-       if (iwl_is_otp_empty(priv))
+       if (iwl_is_otp_empty(bus))
                return -EINVAL;
 
        /*
@@ -471,9 +471,9 @@ static int iwl_find_otp_image(struct iwl_priv *priv,
                 */
                valid_addr = next_link_addr;
                next_link_addr = le16_to_cpu(link_value) * sizeof(u16);
-               IWL_DEBUG_EEPROM(priv, "OTP blocks %d addr 0x%x\n",
+               IWL_DEBUG_EEPROM(bus, "OTP blocks %d addr 0x%x\n",
                               usedblocks, next_link_addr);
-               if (iwl_read_otp_word(priv, next_link_addr, &link_value))
+               if (iwl_read_otp_word(bus, next_link_addr, &link_value))
                        return -EINVAL;
                if (!link_value) {
                        /*
@@ -488,10 +488,10 @@ static int iwl_find_otp_image(struct iwl_priv *priv,
                }
                /* more in the link list, continue */
                usedblocks++;
-       } while (usedblocks <= priv->cfg->base_params->max_ll_items);
+       } while (usedblocks <= priv(bus)->cfg->base_params->max_ll_items);
 
        /* OTP has no valid blocks */
-       IWL_DEBUG_EEPROM(priv, "OTP has no valid blocks\n");
+       IWL_DEBUG_EEPROM(bus, "OTP has no valid blocks\n");
        return -EINVAL;
 }
 
@@ -504,28 +504,28 @@ static int iwl_find_otp_image(struct iwl_priv *priv,
  * iwl_get_max_txpower_avg - get the highest tx power from all chains.
  *     find the highest tx power from all chains for the channel
  */
-static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv,
+static s8 iwl_get_max_txpower_avg(struct iwl_cfg *cfg,
                struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
                int element, s8 *max_txpower_in_half_dbm)
 {
        s8 max_txpower_avg = 0; /* (dBm) */
 
        /* Take the highest tx power from any valid chains */
-       if ((priv->cfg->valid_tx_ant & ANT_A) &&
+       if ((cfg->valid_tx_ant & ANT_A) &&
            (enhanced_txpower[element].chain_a_max > max_txpower_avg))
                max_txpower_avg = enhanced_txpower[element].chain_a_max;
-       if ((priv->cfg->valid_tx_ant & ANT_B) &&
+       if ((cfg->valid_tx_ant & ANT_B) &&
            (enhanced_txpower[element].chain_b_max > max_txpower_avg))
                max_txpower_avg = enhanced_txpower[element].chain_b_max;
-       if ((priv->cfg->valid_tx_ant & ANT_C) &&
+       if ((cfg->valid_tx_ant & ANT_C) &&
            (enhanced_txpower[element].chain_c_max > max_txpower_avg))
                max_txpower_avg = enhanced_txpower[element].chain_c_max;
-       if (((priv->cfg->valid_tx_ant == ANT_AB) |
-           (priv->cfg->valid_tx_ant == ANT_BC) |
-           (priv->cfg->valid_tx_ant == ANT_AC)) &&
+       if (((cfg->valid_tx_ant == ANT_AB) |
+           (cfg->valid_tx_ant == ANT_BC) |
+           (cfg->valid_tx_ant == ANT_AC)) &&
            (enhanced_txpower[element].mimo2_max > max_txpower_avg))
                max_txpower_avg =  enhanced_txpower[element].mimo2_max;
-       if ((priv->cfg->valid_tx_ant == ANT_ABC) &&
+       if ((cfg->valid_tx_ant == ANT_ABC) &&
            (enhanced_txpower[element].mimo3_max > max_txpower_avg))
                max_txpower_avg = enhanced_txpower[element].mimo3_max;
 
@@ -627,7 +627,7 @@ void iwl_eeprom_enhanced_txpower(struct iwl_priv *priv)
                                 ((txp->delta_20_in_40 & 0xf0) >> 4),
                                 (txp->delta_20_in_40 & 0x0f));
 
-               max_txp_avg = iwl_get_max_txpower_avg(priv, txp_array, idx,
+               max_txp_avg = iwl_get_max_txpower_avg(priv->cfg, txp_array, idx,
                                                      &max_txp_avg_halfdbm);
 
                /*
@@ -660,8 +660,8 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev)
        u16 validblockaddr = 0;
        u16 cache_addr = 0;
 
-       priv->nvm_device_type = iwl_get_nvm_type(priv, hw_rev);
-       if (priv->nvm_device_type == -ENOENT)
+       trans(priv)->nvm_device_type = iwl_get_nvm_type(bus(priv), hw_rev);
+       if (trans(priv)->nvm_device_type == -ENOENT)
                return -ENOENT;
        /* allocate eeprom */
        sz = priv->cfg->base_params->eeprom_size;
@@ -675,7 +675,7 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev)
 
        iwl_apm_init(priv);
 
-       ret = iwl_eeprom_verify_signature(priv);
+       ret = iwl_eeprom_verify_signature(trans(priv));
        if (ret < 0) {
                IWL_ERR(priv, "EEPROM not found, EEPROM_GP=0x%08x\n", gp);
                ret = -ENOENT;
@@ -683,16 +683,16 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev)
        }
 
        /* Make sure driver (instead of uCode) is allowed to read EEPROM */
-       ret = iwl_eeprom_acquire_semaphore(priv);
+       ret = iwl_eeprom_acquire_semaphore(bus(priv));
        if (ret < 0) {
                IWL_ERR(priv, "Failed to acquire EEPROM semaphore.\n");
                ret = -ENOENT;
                goto err;
        }
 
-       if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) {
+       if (trans(priv)->nvm_device_type == NVM_DEVICE_TYPE_OTP) {
 
-               ret = iwl_init_otp_access(priv);
+               ret = iwl_init_otp_access(bus(priv));
                if (ret) {
                        IWL_ERR(priv, "Failed to initialize OTP access.\n");
                        ret = -ENOENT;
@@ -707,7 +707,7 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev)
                             CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
                /* traversing the linked list if no shadow ram supported */
                if (!priv->cfg->base_params->shadow_ram_support) {
-                       if (iwl_find_otp_image(priv, &validblockaddr)) {
+                       if (iwl_find_otp_image(bus(priv), &validblockaddr)) {
                                ret = -ENOENT;
                                goto done;
                        }
@@ -716,7 +716,7 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev)
                     addr += sizeof(u16)) {
                        __le16 eeprom_data;
 
-                       ret = iwl_read_otp_word(priv, addr, &eeprom_data);
+                       ret = iwl_read_otp_word(bus(priv), addr, &eeprom_data);
                        if (ret)
                                goto done;
                        e[cache_addr / 2] = eeprom_data;
@@ -744,13 +744,13 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev)
        }
 
        IWL_DEBUG_EEPROM(priv, "NVM Type: %s, version: 0x%x\n",
-                      (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
+                      (trans(priv)->nvm_device_type == NVM_DEVICE_TYPE_OTP)
                       ? "OTP" : "EEPROM",
                       iwl_eeprom_query16(priv, EEPROM_VERSION));
 
        ret = 0;
 done:
-       iwl_eeprom_release_semaphore(priv);
+       iwl_eeprom_release_semaphore(bus(priv));
 
 err:
        if (ret)
diff --git a/drivers/net/wireless/iwlwifi/iwl-mac80211.c b/drivers/net/wireless/iwlwifi/iwl-mac80211.c
new file mode 100644 (file)
index 0000000..05b1f0d
--- /dev/null
@@ -0,0 +1,1632 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+
+#include <net/mac80211.h>
+
+#include <asm/div64.h>
+
+#include "iwl-eeprom.h"
+#include "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-io.h"
+#include "iwl-agn-calib.h"
+#include "iwl-agn.h"
+#include "iwl-shared.h"
+#include "iwl-bus.h"
+#include "iwl-trans.h"
+
+/*****************************************************************************
+ *
+ * mac80211 entry point functions
+ *
+ *****************************************************************************/
+
+static const struct ieee80211_iface_limit iwlagn_sta_ap_limits[] = {
+       {
+               .max = 1,
+               .types = BIT(NL80211_IFTYPE_STATION),
+       },
+       {
+               .max = 1,
+               .types = BIT(NL80211_IFTYPE_AP),
+       },
+};
+
+static const struct ieee80211_iface_limit iwlagn_2sta_limits[] = {
+       {
+               .max = 2,
+               .types = BIT(NL80211_IFTYPE_STATION),
+       },
+};
+
+static const struct ieee80211_iface_limit iwlagn_p2p_sta_go_limits[] = {
+       {
+               .max = 1,
+               .types = BIT(NL80211_IFTYPE_STATION),
+       },
+       {
+               .max = 1,
+               .types = BIT(NL80211_IFTYPE_P2P_GO) |
+                        BIT(NL80211_IFTYPE_AP),
+       },
+};
+
+static const struct ieee80211_iface_limit iwlagn_p2p_2sta_limits[] = {
+       {
+               .max = 2,
+               .types = BIT(NL80211_IFTYPE_STATION),
+       },
+       {
+               .max = 1,
+               .types = BIT(NL80211_IFTYPE_P2P_CLIENT),
+       },
+};
+
+static const struct ieee80211_iface_combination
+iwlagn_iface_combinations_dualmode[] = {
+       { .num_different_channels = 1,
+         .max_interfaces = 2,
+         .beacon_int_infra_match = true,
+         .limits = iwlagn_sta_ap_limits,
+         .n_limits = ARRAY_SIZE(iwlagn_sta_ap_limits),
+       },
+       { .num_different_channels = 1,
+         .max_interfaces = 2,
+         .limits = iwlagn_2sta_limits,
+         .n_limits = ARRAY_SIZE(iwlagn_2sta_limits),
+       },
+};
+
+static const struct ieee80211_iface_combination
+iwlagn_iface_combinations_p2p[] = {
+       { .num_different_channels = 1,
+         .max_interfaces = 2,
+         .beacon_int_infra_match = true,
+         .limits = iwlagn_p2p_sta_go_limits,
+         .n_limits = ARRAY_SIZE(iwlagn_p2p_sta_go_limits),
+       },
+       { .num_different_channels = 1,
+         .max_interfaces = 2,
+         .limits = iwlagn_p2p_2sta_limits,
+         .n_limits = ARRAY_SIZE(iwlagn_p2p_2sta_limits),
+       },
+};
+
+/*
+ * Not a mac80211 entry point function, but it fits in with all the
+ * other mac80211 functions grouped here.
+ */
+int iwlagn_mac_setup_register(struct iwl_priv *priv,
+                                 struct iwlagn_ucode_capabilities *capa)
+{
+       int ret;
+       struct ieee80211_hw *hw = priv->hw;
+       struct iwl_rxon_context *ctx;
+
+       hw->rate_control_algorithm = "iwl-agn-rs";
+
+       /* Tell mac80211 our characteristics */
+       hw->flags = IEEE80211_HW_SIGNAL_DBM |
+                   IEEE80211_HW_AMPDU_AGGREGATION |
+                   IEEE80211_HW_NEED_DTIM_PERIOD |
+                   IEEE80211_HW_SPECTRUM_MGMT |
+                   IEEE80211_HW_REPORTS_TX_ACK_STATUS;
+
+       /*
+        * Including the following line will crash some AP's.  This
+        * workaround removes the stimulus which causes the crash until
+        * the AP software can be fixed.
+       hw->max_tx_aggregation_subframes = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
+        */
+
+       hw->flags |= IEEE80211_HW_SUPPORTS_PS |
+                    IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
+
+       if (priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE)
+               hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
+                            IEEE80211_HW_SUPPORTS_STATIC_SMPS;
+
+       if (capa->flags & IWL_UCODE_TLV_FLAGS_MFP)
+               hw->flags |= IEEE80211_HW_MFP_CAPABLE;
+
+       hw->sta_data_size = sizeof(struct iwl_station_priv);
+       hw->vif_data_size = sizeof(struct iwl_vif_priv);
+
+       for_each_context(priv, ctx) {
+               hw->wiphy->interface_modes |= ctx->interface_modes;
+               hw->wiphy->interface_modes |= ctx->exclusive_interface_modes;
+       }
+
+       BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
+
+       if (hw->wiphy->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)) {
+               hw->wiphy->iface_combinations = iwlagn_iface_combinations_p2p;
+               hw->wiphy->n_iface_combinations =
+                       ARRAY_SIZE(iwlagn_iface_combinations_p2p);
+       } else if (hw->wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) {
+               hw->wiphy->iface_combinations =
+                       iwlagn_iface_combinations_dualmode;
+               hw->wiphy->n_iface_combinations =
+                       ARRAY_SIZE(iwlagn_iface_combinations_dualmode);
+       }
+
+       hw->wiphy->max_remain_on_channel_duration = 1000;
+
+       hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
+                           WIPHY_FLAG_DISABLE_BEACON_HINTS |
+                           WIPHY_FLAG_IBSS_RSN;
+
+       if (trans(priv)->ucode_wowlan.code.len &&
+           device_can_wakeup(bus(priv)->dev)) {
+               hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
+                                         WIPHY_WOWLAN_DISCONNECT |
+                                         WIPHY_WOWLAN_EAP_IDENTITY_REQ |
+                                         WIPHY_WOWLAN_RFKILL_RELEASE;
+               if (!iwlagn_mod_params.sw_crypto)
+                       hw->wiphy->wowlan.flags |=
+                               WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
+                               WIPHY_WOWLAN_GTK_REKEY_FAILURE;
+
+               hw->wiphy->wowlan.n_patterns = IWLAGN_WOWLAN_MAX_PATTERNS;
+               hw->wiphy->wowlan.pattern_min_len =
+                                       IWLAGN_WOWLAN_MIN_PATTERN_LEN;
+               hw->wiphy->wowlan.pattern_max_len =
+                                       IWLAGN_WOWLAN_MAX_PATTERN_LEN;
+       }
+
+       if (iwlagn_mod_params.power_save)
+               hw->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
+       else
+               hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
+
+       hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
+       /* we create the 802.11 header and a zero-length SSID element */
+       hw->wiphy->max_scan_ie_len = capa->max_probe_length - 24 - 2;
+
+       /* Default value; 4 EDCA QOS priorities */
+       hw->queues = 4;
+
+       hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL;
+
+       if (priv->bands[IEEE80211_BAND_2GHZ].n_channels)
+               priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
+                       &priv->bands[IEEE80211_BAND_2GHZ];
+       if (priv->bands[IEEE80211_BAND_5GHZ].n_channels)
+               priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
+                       &priv->bands[IEEE80211_BAND_5GHZ];
+
+       iwl_leds_init(priv);
+
+       ret = ieee80211_register_hw(priv->hw);
+       if (ret) {
+               IWL_ERR(priv, "Failed to register hw (error %d)\n", ret);
+               return ret;
+       }
+       priv->mac80211_registered = 1;
+
+       return 0;
+}
+
+static int __iwl_up(struct iwl_priv *priv)
+{
+       struct iwl_rxon_context *ctx;
+       int ret;
+
+       lockdep_assert_held(&priv->shrd->mutex);
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) {
+               IWL_WARN(priv, "Exit pending; will not bring the NIC up\n");
+               return -EIO;
+       }
+
+       for_each_context(priv, ctx) {
+               ret = iwlagn_alloc_bcast_station(priv, ctx);
+               if (ret) {
+                       iwl_dealloc_bcast_stations(priv);
+                       return ret;
+               }
+       }
+
+       ret = iwlagn_run_init_ucode(priv);
+       if (ret) {
+               IWL_ERR(priv, "Failed to run INIT ucode: %d\n", ret);
+               goto error;
+       }
+
+       ret = iwlagn_load_ucode_wait_alive(priv, IWL_UCODE_REGULAR);
+       if (ret) {
+               IWL_ERR(priv, "Failed to start RT ucode: %d\n", ret);
+               goto error;
+       }
+
+       ret = iwl_alive_start(priv);
+       if (ret)
+               goto error;
+       return 0;
+
+ error:
+       set_bit(STATUS_EXIT_PENDING, &priv->shrd->status);
+       __iwl_down(priv);
+       clear_bit(STATUS_EXIT_PENDING, &priv->shrd->status);
+
+       IWL_ERR(priv, "Unable to initialize device.\n");
+       return ret;
+}
+
+static int iwlagn_mac_start(struct ieee80211_hw *hw)
+{
+       struct iwl_priv *priv = hw->priv;
+       int ret;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       /* we should be verifying the device is ready to be opened */
+       mutex_lock(&priv->shrd->mutex);
+       ret = __iwl_up(priv);
+       mutex_unlock(&priv->shrd->mutex);
+       if (ret)
+               return ret;
+
+       IWL_DEBUG_INFO(priv, "Start UP work done.\n");
+
+       /* Now we should be done, and the READY bit should be set. */
+       if (WARN_ON(!test_bit(STATUS_READY, &priv->shrd->status)))
+               ret = -EIO;
+
+       iwlagn_led_enable(priv);
+
+       priv->is_open = 1;
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+       return 0;
+}
+
+static void iwlagn_mac_stop(struct ieee80211_hw *hw)
+{
+       struct iwl_priv *priv = hw->priv;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       if (!priv->is_open)
+               return;
+
+       priv->is_open = 0;
+
+       iwl_down(priv);
+
+       flush_workqueue(priv->shrd->workqueue);
+
+       /* User space software may expect getting rfkill changes
+        * even if interface is down */
+       iwl_write32(bus(priv), CSR_INT, 0xFFFFFFFF);
+       iwl_enable_rfkill_int(priv);
+
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+static void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw,
+                                     struct ieee80211_vif *vif,
+                                     struct cfg80211_gtk_rekey_data *data)
+{
+       struct iwl_priv *priv = hw->priv;
+
+       if (iwlagn_mod_params.sw_crypto)
+               return;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+       mutex_lock(&priv->shrd->mutex);
+
+       if (priv->contexts[IWL_RXON_CTX_BSS].vif != vif)
+               goto out;
+
+       memcpy(priv->kek, data->kek, NL80211_KEK_LEN);
+       memcpy(priv->kck, data->kck, NL80211_KCK_LEN);
+       priv->replay_ctr =
+               cpu_to_le64(be64_to_cpup((__be64 *)&data->replay_ctr));
+       priv->have_rekey_data = true;
+
+ out:
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+#ifdef CONFIG_PM_SLEEP
+
+static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
+                             struct cfg80211_wowlan *wowlan)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+       int ret;
+
+       if (WARN_ON(!wowlan))
+               return -EINVAL;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+       mutex_lock(&priv->shrd->mutex);
+
+       /* Don't attempt WoWLAN when not associated, tear down instead. */
+       if (!ctx->vif || ctx->vif->type != NL80211_IFTYPE_STATION ||
+           !iwl_is_associated_ctx(ctx)) {
+               ret = 1;
+               goto out;
+       }
+
+       ret = iwlagn_suspend(priv, hw, wowlan);
+       if (ret)
+               goto error;
+
+       device_set_wakeup_enable(bus(priv)->dev, true);
+
+       /* Now let the ucode operate on its own */
+       iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_SET,
+                         CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
+
+       goto out;
+
+ error:
+       priv->shrd->wowlan = false;
+       iwlagn_prepare_restart(priv);
+       ieee80211_restart_hw(priv->hw);
+ out:
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       return ret;
+}
+
+static int iwlagn_mac_resume(struct ieee80211_hw *hw)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+       struct ieee80211_vif *vif;
+       unsigned long flags;
+       u32 base, status = 0xffffffff;
+       int ret = -EIO;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+       mutex_lock(&priv->shrd->mutex);
+
+       iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_CLR,
+                         CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
+
+       base = priv->device_pointers.error_event_table;
+       if (iwlagn_hw_valid_rtc_data_addr(base)) {
+               spin_lock_irqsave(&bus(priv)->reg_lock, flags);
+               ret = iwl_grab_nic_access_silent(bus(priv));
+               if (ret == 0) {
+                       iwl_write32(bus(priv), HBUS_TARG_MEM_RADDR, base);
+                       status = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT);
+                       iwl_release_nic_access(bus(priv));
+               }
+               spin_unlock_irqrestore(&bus(priv)->reg_lock, flags);
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+               if (ret == 0) {
+                       struct iwl_trans *trans = trans(priv);
+                       if (!priv->wowlan_sram)
+                               priv->wowlan_sram =
+                                       kzalloc(trans->ucode_wowlan.data.len,
+                                               GFP_KERNEL);
+
+                       if (priv->wowlan_sram)
+                               _iwl_read_targ_mem_words(
+                                       bus(priv), 0x800000, priv->wowlan_sram,
+                                       trans->ucode_wowlan.data.len / 4);
+               }
+#endif
+       }
+
+       /* we'll clear ctx->vif during iwlagn_prepare_restart() */
+       vif = ctx->vif;
+
+       priv->shrd->wowlan = false;
+
+       device_set_wakeup_enable(bus(priv)->dev, false);
+
+       iwlagn_prepare_restart(priv);
+
+       memset((void *)&ctx->active, 0, sizeof(ctx->active));
+       iwl_connection_init_rx_config(priv, ctx);
+       iwlagn_set_rxon_chain(priv, ctx);
+
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       ieee80211_resume_disconnect(vif);
+
+       return 1;
+}
+
+#endif
+
+static void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+       struct iwl_priv *priv = hw->priv;
+
+       IWL_DEBUG_MACDUMP(priv, "enter\n");
+
+       IWL_DEBUG_TX(priv, "dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
+                    ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate);
+
+       if (iwlagn_tx_skb(priv, skb))
+               dev_kfree_skb_any(skb);
+
+       IWL_DEBUG_MACDUMP(priv, "leave\n");
+}
+
+static void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw,
+                                      struct ieee80211_vif *vif,
+                                      struct ieee80211_key_conf *keyconf,
+                                      struct ieee80211_sta *sta,
+                                      u32 iv32, u16 *phase1key)
+{
+       struct iwl_priv *priv = hw->priv;
+
+       iwl_update_tkip_key(priv, vif, keyconf, sta, iv32, phase1key);
+}
+
+static int iwlagn_mac_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 iwl_priv *priv = hw->priv;
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+       struct iwl_rxon_context *ctx = vif_priv->ctx;
+       int ret;
+       bool is_default_wep_key = false;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       if (iwlagn_mod_params.sw_crypto) {
+               IWL_DEBUG_MAC80211(priv, "leave - hwcrypto disabled\n");
+               return -EOPNOTSUPP;
+       }
+
+       /*
+        * We could program these keys into the hardware as well, but we
+        * don't expect much multicast traffic in IBSS and having keys
+        * for more stations is probably more useful.
+        *
+        * Mark key TX-only and return 0.
+        */
+       if (vif->type == NL80211_IFTYPE_ADHOC &&
+           !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
+               key->hw_key_idx = WEP_INVALID_OFFSET;
+               return 0;
+       }
+
+       /* If they key was TX-only, accept deletion */
+       if (cmd == DISABLE_KEY && key->hw_key_idx == WEP_INVALID_OFFSET)
+               return 0;
+
+       mutex_lock(&priv->shrd->mutex);
+       iwl_scan_cancel_timeout(priv, 100);
+
+       BUILD_BUG_ON(WEP_INVALID_OFFSET == IWLAGN_HW_KEY_DEFAULT);
+
+       /*
+        * If we are getting WEP group key and we didn't receive any key mapping
+        * so far, we are in legacy wep mode (group key only), otherwise we are
+        * in 1X mode.
+        * In legacy wep mode, we use another host command to the uCode.
+        */
+       if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
+            key->cipher == WLAN_CIPHER_SUITE_WEP104) && !sta) {
+               if (cmd == SET_KEY)
+                       is_default_wep_key = !ctx->key_mapping_keys;
+               else
+                       is_default_wep_key =
+                               key->hw_key_idx == IWLAGN_HW_KEY_DEFAULT;
+       }
+
+
+       switch (cmd) {
+       case SET_KEY:
+               if (is_default_wep_key) {
+                       ret = iwl_set_default_wep_key(priv, vif_priv->ctx, key);
+                       break;
+               }
+               ret = iwl_set_dynamic_key(priv, vif_priv->ctx, key, sta);
+               if (ret) {
+                       /*
+                        * can't add key for RX, but we don't need it
+                        * in the device for TX so still return 0
+                        */
+                       ret = 0;
+                       key->hw_key_idx = WEP_INVALID_OFFSET;
+               }
+
+               IWL_DEBUG_MAC80211(priv, "enable hwcrypto key\n");
+               break;
+       case DISABLE_KEY:
+               if (is_default_wep_key)
+                       ret = iwl_remove_default_wep_key(priv, ctx, key);
+               else
+                       ret = iwl_remove_dynamic_key(priv, ctx, key, sta);
+
+               IWL_DEBUG_MAC80211(priv, "disable hwcrypto key\n");
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       return ret;
+}
+
+static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
+                                  struct ieee80211_vif *vif,
+                                  enum ieee80211_ampdu_mlme_action action,
+                                  struct ieee80211_sta *sta, u16 tid, u16 *ssn,
+                                  u8 buf_size)
+{
+       struct iwl_priv *priv = hw->priv;
+       int ret = -EINVAL;
+       struct iwl_station_priv *sta_priv = (void *) sta->drv_priv;
+       struct iwl_rxon_context *ctx =  iwl_rxon_ctx_from_vif(vif);
+
+       IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n",
+                    sta->addr, tid);
+
+       if (!(priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE))
+               return -EACCES;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+       mutex_lock(&priv->shrd->mutex);
+
+       switch (action) {
+       case IEEE80211_AMPDU_RX_START:
+               IWL_DEBUG_HT(priv, "start Rx\n");
+               ret = iwl_sta_rx_agg_start(priv, sta, tid, *ssn);
+               break;
+       case IEEE80211_AMPDU_RX_STOP:
+               IWL_DEBUG_HT(priv, "stop Rx\n");
+               ret = iwl_sta_rx_agg_stop(priv, sta, tid);
+               if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
+                       ret = 0;
+               break;
+       case IEEE80211_AMPDU_TX_START:
+               IWL_DEBUG_HT(priv, "start Tx\n");
+               ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn);
+               break;
+       case IEEE80211_AMPDU_TX_STOP:
+               IWL_DEBUG_HT(priv, "stop Tx\n");
+               ret = iwlagn_tx_agg_stop(priv, vif, sta, tid);
+               if ((ret == 0) && (priv->agg_tids_count > 0)) {
+                       priv->agg_tids_count--;
+                       IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n",
+                                    priv->agg_tids_count);
+               }
+               if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
+                       ret = 0;
+               if (!priv->agg_tids_count && priv->cfg->ht_params &&
+                   priv->cfg->ht_params->use_rts_for_aggregation) {
+                       /*
+                        * switch off RTS/CTS if it was previously enabled
+                        */
+                       sta_priv->lq_sta.lq.general_params.flags &=
+                               ~LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK;
+                       iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif),
+                                       &sta_priv->lq_sta.lq, CMD_ASYNC, false);
+               }
+               break;
+       case IEEE80211_AMPDU_TX_OPERATIONAL:
+               buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF);
+
+               iwl_trans_tx_agg_setup(trans(priv), ctx->ctxid, iwl_sta_id(sta),
+                               tid, buf_size);
+
+               /*
+                * If the limit is 0, then it wasn't initialised yet,
+                * use the default. We can do that since we take the
+                * minimum below, and we don't want to go above our
+                * default due to hardware restrictions.
+                */
+               if (sta_priv->max_agg_bufsize == 0)
+                       sta_priv->max_agg_bufsize =
+                               LINK_QUAL_AGG_FRAME_LIMIT_DEF;
+
+               /*
+                * Even though in theory the peer could have different
+                * aggregation reorder buffer sizes for different sessions,
+                * our ucode doesn't allow for that and has a global limit
+                * for each station. Therefore, use the minimum of all the
+                * aggregation sessions and our default value.
+                */
+               sta_priv->max_agg_bufsize =
+                       min(sta_priv->max_agg_bufsize, buf_size);
+
+               if (priv->cfg->ht_params &&
+                   priv->cfg->ht_params->use_rts_for_aggregation) {
+                       /*
+                        * switch to RTS/CTS if it is the prefer protection
+                        * method for HT traffic
+                        */
+
+                       sta_priv->lq_sta.lq.general_params.flags |=
+                               LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK;
+               }
+               priv->agg_tids_count++;
+               IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n",
+                            priv->agg_tids_count);
+
+               sta_priv->lq_sta.lq.agg_params.agg_frame_cnt_limit =
+                       sta_priv->max_agg_bufsize;
+
+               iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif),
+                               &sta_priv->lq_sta.lq, CMD_ASYNC, false);
+
+               IWL_INFO(priv, "Tx aggregation enabled on ra = %pM tid = %d\n",
+                        sta->addr, tid);
+               ret = 0;
+               break;
+       }
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+       return ret;
+}
+
+static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
+                             struct ieee80211_vif *vif,
+                             struct ieee80211_sta *sta)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+       bool is_ap = vif->type == NL80211_IFTYPE_STATION;
+       int ret = 0;
+       u8 sta_id;
+
+       IWL_DEBUG_MAC80211(priv, "received request to add station %pM\n",
+                       sta->addr);
+       mutex_lock(&priv->shrd->mutex);
+       IWL_DEBUG_INFO(priv, "proceeding to add station %pM\n",
+                       sta->addr);
+       sta_priv->sta_id = IWL_INVALID_STATION;
+
+       atomic_set(&sta_priv->pending_frames, 0);
+       if (vif->type == NL80211_IFTYPE_AP)
+               sta_priv->client = true;
+
+       ret = iwl_add_station_common(priv, vif_priv->ctx, sta->addr,
+                                    is_ap, sta, &sta_id);
+       if (ret) {
+               IWL_ERR(priv, "Unable to add station %pM (%d)\n",
+                       sta->addr, ret);
+               /* Should we return success if return code is EEXIST ? */
+               goto out;
+       }
+
+       sta_priv->sta_id = sta_id;
+
+       /* Initialize rate scaling */
+       IWL_DEBUG_INFO(priv, "Initializing rate scaling for station %pM\n",
+                      sta->addr);
+       iwl_rs_rate_init(priv, sta, sta_id);
+ out:
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       return ret;
+}
+
+static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
+                               struct ieee80211_channel_switch *ch_switch)
+{
+       struct iwl_priv *priv = hw->priv;
+       const struct iwl_channel_info *ch_info;
+       struct ieee80211_conf *conf = &hw->conf;
+       struct ieee80211_channel *channel = ch_switch->channel;
+       struct iwl_ht_config *ht_conf = &priv->current_ht_config;
+       /*
+        * MULTI-FIXME
+        * When we add support for multiple interfaces, we need to
+        * revisit this. The channel switch command in the device
+        * only affects the BSS context, but what does that really
+        * mean? And what if we get a CSA on the second interface?
+        * This needs a lot of work.
+        */
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+       u16 ch;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       mutex_lock(&priv->shrd->mutex);
+
+       if (iwl_is_rfkill(priv->shrd))
+               goto out;
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status) ||
+           test_bit(STATUS_SCANNING, &priv->shrd->status) ||
+           test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status))
+               goto out;
+
+       if (!iwl_is_associated_ctx(ctx))
+               goto out;
+
+       if (!priv->cfg->lib->set_channel_switch)
+               goto out;
+
+       ch = channel->hw_value;
+       if (le16_to_cpu(ctx->active.channel) == ch)
+               goto out;
+
+       ch_info = iwl_get_channel_info(priv, channel->band, ch);
+       if (!is_channel_valid(ch_info)) {
+               IWL_DEBUG_MAC80211(priv, "invalid channel\n");
+               goto out;
+       }
+
+       spin_lock_irq(&priv->shrd->lock);
+
+       priv->current_ht_config.smps = conf->smps_mode;
+
+       /* Configure HT40 channels */
+       ctx->ht.enabled = conf_is_ht(conf);
+       if (ctx->ht.enabled) {
+               if (conf_is_ht40_minus(conf)) {
+                       ctx->ht.extension_chan_offset =
+                               IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+                       ctx->ht.is_40mhz = true;
+               } else if (conf_is_ht40_plus(conf)) {
+                       ctx->ht.extension_chan_offset =
+                               IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+                       ctx->ht.is_40mhz = true;
+               } else {
+                       ctx->ht.extension_chan_offset =
+                               IEEE80211_HT_PARAM_CHA_SEC_NONE;
+                       ctx->ht.is_40mhz = false;
+               }
+       } else
+               ctx->ht.is_40mhz = false;
+
+       if ((le16_to_cpu(ctx->staging.channel) != ch))
+               ctx->staging.flags = 0;
+
+       iwl_set_rxon_channel(priv, channel, ctx);
+       iwl_set_rxon_ht(priv, ht_conf);
+       iwl_set_flags_for_band(priv, ctx, channel->band, ctx->vif);
+
+       spin_unlock_irq(&priv->shrd->lock);
+
+       iwl_set_rate(priv);
+       /*
+        * at this point, staging_rxon has the
+        * configuration for channel switch
+        */
+       set_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status);
+       priv->switch_channel = cpu_to_le16(ch);
+       if (priv->cfg->lib->set_channel_switch(priv, ch_switch)) {
+               clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status);
+               priv->switch_channel = 0;
+               ieee80211_chswitch_done(ctx->vif, false);
+       }
+
+out:
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+static void iwlagn_configure_filter(struct ieee80211_hw *hw,
+                                   unsigned int changed_flags,
+                                   unsigned int *total_flags,
+                                   u64 multicast)
+{
+       struct iwl_priv *priv = hw->priv;
+       __le32 filter_or = 0, filter_nand = 0;
+       struct iwl_rxon_context *ctx;
+
+#define CHK(test, flag)        do { \
+       if (*total_flags & (test))              \
+               filter_or |= (flag);            \
+       else                                    \
+               filter_nand |= (flag);          \
+       } while (0)
+
+       IWL_DEBUG_MAC80211(priv, "Enter: changed: 0x%x, total: 0x%x\n",
+                       changed_flags, *total_flags);
+
+       CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK);
+       /* Setting _just_ RXON_FILTER_CTL2HOST_MSK causes FH errors */
+       CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_PROMISC_MSK);
+       CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK);
+
+#undef CHK
+
+       mutex_lock(&priv->shrd->mutex);
+
+       for_each_context(priv, ctx) {
+               ctx->staging.filter_flags &= ~filter_nand;
+               ctx->staging.filter_flags |= filter_or;
+
+               /*
+                * Not committing directly because hardware can perform a scan,
+                * but we'll eventually commit the filter flags change anyway.
+                */
+       }
+
+       mutex_unlock(&priv->shrd->mutex);
+
+       /*
+        * Receiving all multicast frames is always enabled by the
+        * default flags setup in iwl_connection_init_rx_config()
+        * since we currently do not support programming multicast
+        * filters into the device.
+        */
+       *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS |
+                       FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
+}
+
+static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop)
+{
+       struct iwl_priv *priv = hw->priv;
+
+       mutex_lock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) {
+               IWL_DEBUG_TX(priv, "Aborting flush due to device shutdown\n");
+               goto done;
+       }
+       if (iwl_is_rfkill(priv->shrd)) {
+               IWL_DEBUG_TX(priv, "Aborting flush due to RF Kill\n");
+               goto done;
+       }
+
+       /*
+        * mac80211 will not push any more frames for transmit
+        * until the flush is completed
+        */
+       if (drop) {
+               IWL_DEBUG_MAC80211(priv, "send flush command\n");
+               if (iwlagn_txfifo_flush(priv, IWL_DROP_ALL)) {
+                       IWL_ERR(priv, "flush request fail\n");
+                       goto done;
+               }
+       }
+       IWL_DEBUG_MAC80211(priv, "wait transmit/flush all frames\n");
+       iwl_trans_wait_tx_queue_empty(trans(priv));
+done:
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw,
+                                    struct ieee80211_channel *channel,
+                                    enum nl80211_channel_type channel_type,
+                                    int duration)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
+       int err = 0;
+
+       if (!(priv->shrd->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
+               return -EOPNOTSUPP;
+
+       if (!(ctx->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)))
+               return -EOPNOTSUPP;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+       mutex_lock(&priv->shrd->mutex);
+
+       if (test_bit(STATUS_SCAN_HW, &priv->shrd->status)) {
+               err = -EBUSY;
+               goto out;
+       }
+
+       priv->hw_roc_channel = channel;
+       priv->hw_roc_chantype = channel_type;
+       /* convert from ms to TU */
+       priv->hw_roc_duration = DIV_ROUND_UP(1000 * duration, 1024);
+       priv->hw_roc_start_notified = false;
+       cancel_delayed_work(&priv->hw_roc_disable_work);
+
+       if (!ctx->is_active) {
+               static const struct iwl_qos_info default_qos_data = {
+                       .def_qos_parm = {
+                               .ac[0] = {
+                                       .cw_min = cpu_to_le16(3),
+                                       .cw_max = cpu_to_le16(7),
+                                       .aifsn = 2,
+                                       .edca_txop = cpu_to_le16(1504),
+                               },
+                               .ac[1] = {
+                                       .cw_min = cpu_to_le16(7),
+                                       .cw_max = cpu_to_le16(15),
+                                       .aifsn = 2,
+                                       .edca_txop = cpu_to_le16(3008),
+                               },
+                               .ac[2] = {
+                                       .cw_min = cpu_to_le16(15),
+                                       .cw_max = cpu_to_le16(1023),
+                                       .aifsn = 3,
+                               },
+                               .ac[3] = {
+                                       .cw_min = cpu_to_le16(15),
+                                       .cw_max = cpu_to_le16(1023),
+                                       .aifsn = 7,
+                               },
+                       },
+               };
+
+               ctx->is_active = true;
+               ctx->qos_data = default_qos_data;
+               ctx->staging.dev_type = RXON_DEV_TYPE_P2P;
+               memcpy(ctx->staging.node_addr,
+                      priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr,
+                      ETH_ALEN);
+               memcpy(ctx->staging.bssid_addr,
+                      priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr,
+                      ETH_ALEN);
+               err = iwlagn_commit_rxon(priv, ctx);
+               if (err)
+                       goto out;
+               ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK |
+                                            RXON_FILTER_PROMISC_MSK |
+                                            RXON_FILTER_CTL2HOST_MSK;
+
+               err = iwlagn_commit_rxon(priv, ctx);
+               if (err) {
+                       iwlagn_disable_roc(priv);
+                       goto out;
+               }
+               priv->hw_roc_setup = true;
+       }
+
+       err = iwl_scan_initiate(priv, ctx->vif, IWL_SCAN_ROC, channel->band);
+       if (err)
+               iwlagn_disable_roc(priv);
+
+ out:
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       return err;
+}
+
+static int iwlagn_mac_cancel_remain_on_channel(struct ieee80211_hw *hw)
+{
+       struct iwl_priv *priv = hw->priv;
+
+       if (!(priv->shrd->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
+               return -EOPNOTSUPP;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+       mutex_lock(&priv->shrd->mutex);
+       iwl_scan_cancel_timeout(priv, priv->hw_roc_duration);
+       iwlagn_disable_roc(priv);
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       return 0;
+}
+
+static int iwlagn_mac_tx_sync(struct ieee80211_hw *hw,
+                             struct ieee80211_vif *vif,
+                             const u8 *bssid,
+                             enum ieee80211_tx_sync_type type)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+       struct iwl_rxon_context *ctx = vif_priv->ctx;
+       int ret;
+       u8 sta_id;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+       mutex_lock(&priv->shrd->mutex);
+
+       if (iwl_is_associated_ctx(ctx)) {
+               ret = 0;
+               goto out;
+       }
+
+       if (ctx->preauth_bssid || test_bit(STATUS_SCAN_HW,
+           &priv->shrd->status)) {
+               ret = -EBUSY;
+               goto out;
+       }
+
+       ret = iwl_add_station_common(priv, ctx, bssid, true, NULL, &sta_id);
+       if (ret)
+               goto out;
+
+       if (WARN_ON(sta_id != ctx->ap_sta_id)) {
+               ret = -EIO;
+               goto out_remove_sta;
+       }
+
+       memcpy(ctx->bssid, bssid, ETH_ALEN);
+       ctx->preauth_bssid = true;
+
+       ret = iwlagn_commit_rxon(priv, ctx);
+
+       if (ret == 0)
+               goto out;
+
+ out_remove_sta:
+       iwl_remove_station(priv, sta_id, bssid);
+ out:
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       return ret;
+}
+
+static void iwlagn_mac_finish_tx_sync(struct ieee80211_hw *hw,
+                                  struct ieee80211_vif *vif,
+                                  const u8 *bssid,
+                                  enum ieee80211_tx_sync_type type)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+       struct iwl_rxon_context *ctx = vif_priv->ctx;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+       mutex_lock(&priv->shrd->mutex);
+
+       if (iwl_is_associated_ctx(ctx))
+               goto out;
+
+       iwl_remove_station(priv, ctx->ap_sta_id, bssid);
+       ctx->preauth_bssid = false;
+       /* no need to commit */
+ out:
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+static void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw,
+                          enum ieee80211_rssi_event rssi_event)
+{
+       struct iwl_priv *priv = hw->priv;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+       mutex_lock(&priv->shrd->mutex);
+
+       if (priv->cfg->bt_params &&
+                       priv->cfg->bt_params->advanced_bt_coexist) {
+               if (rssi_event == RSSI_EVENT_LOW)
+                       priv->bt_enable_pspoll = true;
+               else if (rssi_event == RSSI_EVENT_HIGH)
+                       priv->bt_enable_pspoll = false;
+
+               iwlagn_send_advance_bt_config(priv);
+       } else {
+               IWL_DEBUG_MAC80211(priv, "Advanced BT coex disabled,"
+                               "ignoring RSSI callback\n");
+       }
+
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+static int iwlagn_mac_set_tim(struct ieee80211_hw *hw,
+                          struct ieee80211_sta *sta, bool set)
+{
+       struct iwl_priv *priv = hw->priv;
+
+       queue_work(priv->shrd->workqueue, &priv->beacon_update);
+
+       return 0;
+}
+
+static int iwlagn_mac_conf_tx(struct ieee80211_hw *hw,
+                   struct ieee80211_vif *vif, u16 queue,
+                   const struct ieee80211_tx_queue_params *params)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+       struct iwl_rxon_context *ctx = vif_priv->ctx;
+       unsigned long flags;
+       int q;
+
+       if (WARN_ON(!ctx))
+               return -EINVAL;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       if (!iwl_is_ready_rf(priv->shrd)) {
+               IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
+               return -EIO;
+       }
+
+       if (queue >= AC_NUM) {
+               IWL_DEBUG_MAC80211(priv, "leave - queue >= AC_NUM %d\n", queue);
+               return 0;
+       }
+
+       q = AC_NUM - 1 - queue;
+
+       spin_lock_irqsave(&priv->shrd->lock, flags);
+
+       ctx->qos_data.def_qos_parm.ac[q].cw_min =
+               cpu_to_le16(params->cw_min);
+       ctx->qos_data.def_qos_parm.ac[q].cw_max =
+               cpu_to_le16(params->cw_max);
+       ctx->qos_data.def_qos_parm.ac[q].aifsn = params->aifs;
+       ctx->qos_data.def_qos_parm.ac[q].edca_txop =
+                       cpu_to_le16((params->txop * 32));
+
+       ctx->qos_data.def_qos_parm.ac[q].reserved1 = 0;
+
+       spin_unlock_irqrestore(&priv->shrd->lock, flags);
+
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+       return 0;
+}
+
+static int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw)
+{
+       struct iwl_priv *priv = hw->priv;
+
+       return priv->ibss_manager == IWL_IBSS_MANAGER;
+}
+
+static int iwl_set_mode(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
+{
+       iwl_connection_init_rx_config(priv, ctx);
+
+       iwlagn_set_rxon_chain(priv, ctx);
+
+       return iwlagn_commit_rxon(priv, ctx);
+}
+
+static int iwl_setup_interface(struct iwl_priv *priv,
+                              struct iwl_rxon_context *ctx)
+{
+       struct ieee80211_vif *vif = ctx->vif;
+       int err;
+
+       lockdep_assert_held(&priv->shrd->mutex);
+
+       /*
+        * This variable will be correct only when there's just
+        * a single context, but all code using it is for hardware
+        * that supports only one context.
+        */
+       priv->iw_mode = vif->type;
+
+       ctx->is_active = true;
+
+       err = iwl_set_mode(priv, ctx);
+       if (err) {
+               if (!ctx->always_active)
+                       ctx->is_active = false;
+               return err;
+       }
+
+       if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist &&
+           vif->type == NL80211_IFTYPE_ADHOC) {
+               /*
+                * pretend to have high BT traffic as long as we
+                * are operating in IBSS mode, as this will cause
+                * the rate scaling etc. to behave as intended.
+                */
+               priv->bt_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
+       }
+
+       return 0;
+}
+
+static int iwlagn_mac_add_interface(struct ieee80211_hw *hw,
+                            struct ieee80211_vif *vif)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+       struct iwl_rxon_context *tmp, *ctx = NULL;
+       int err;
+       enum nl80211_iftype viftype = ieee80211_vif_type_p2p(vif);
+
+       IWL_DEBUG_MAC80211(priv, "enter: type %d, addr %pM\n",
+                          viftype, vif->addr);
+
+       cancel_delayed_work_sync(&priv->hw_roc_disable_work);
+
+       mutex_lock(&priv->shrd->mutex);
+
+       iwlagn_disable_roc(priv);
+
+       if (!iwl_is_ready_rf(priv->shrd)) {
+               IWL_WARN(priv, "Try to add interface when device not ready\n");
+               err = -EINVAL;
+               goto out;
+       }
+
+       for_each_context(priv, tmp) {
+               u32 possible_modes =
+                       tmp->interface_modes | tmp->exclusive_interface_modes;
+
+               if (tmp->vif) {
+                       /* check if this busy context is exclusive */
+                       if (tmp->exclusive_interface_modes &
+                                               BIT(tmp->vif->type)) {
+                               err = -EINVAL;
+                               goto out;
+                       }
+                       continue;
+               }
+
+               if (!(possible_modes & BIT(viftype)))
+                       continue;
+
+               /* have maybe usable context w/o interface */
+               ctx = tmp;
+               break;
+       }
+
+       if (!ctx) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       vif_priv->ctx = ctx;
+       ctx->vif = vif;
+
+       err = iwl_setup_interface(priv, ctx);
+       if (!err)
+               goto out;
+
+       ctx->vif = NULL;
+       priv->iw_mode = NL80211_IFTYPE_STATION;
+ out:
+       mutex_unlock(&priv->shrd->mutex);
+
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+       return err;
+}
+
+static void iwl_teardown_interface(struct iwl_priv *priv,
+                                  struct ieee80211_vif *vif,
+                                  bool mode_change)
+{
+       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
+
+       lockdep_assert_held(&priv->shrd->mutex);
+
+       if (priv->scan_vif == vif) {
+               iwl_scan_cancel_timeout(priv, 200);
+               iwl_force_scan_end(priv);
+       }
+
+       if (!mode_change) {
+               iwl_set_mode(priv, ctx);
+               if (!ctx->always_active)
+                       ctx->is_active = false;
+       }
+
+       /*
+        * When removing the IBSS interface, overwrite the
+        * BT traffic load with the stored one from the last
+        * notification, if any. If this is a device that
+        * doesn't implement this, this has no effect since
+        * both values are the same and zero.
+        */
+       if (vif->type == NL80211_IFTYPE_ADHOC)
+               priv->bt_traffic_load = priv->last_bt_traffic_load;
+}
+
+static void iwlagn_mac_remove_interface(struct ieee80211_hw *hw,
+                             struct ieee80211_vif *vif)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       mutex_lock(&priv->shrd->mutex);
+
+       if (WARN_ON(ctx->vif != vif)) {
+               struct iwl_rxon_context *tmp;
+               IWL_ERR(priv, "ctx->vif = %p, vif = %p\n", ctx->vif, vif);
+               for_each_context(priv, tmp)
+                       IWL_ERR(priv, "\tID = %d:\tctx = %p\tctx->vif = %p\n",
+                               tmp->ctxid, tmp, tmp->vif);
+       }
+       ctx->vif = NULL;
+
+       iwl_teardown_interface(priv, vif, false);
+
+       mutex_unlock(&priv->shrd->mutex);
+
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+}
+
+static int iwlagn_mac_change_interface(struct ieee80211_hw *hw,
+                               struct ieee80211_vif *vif,
+                               enum nl80211_iftype newtype, bool newp2p)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
+       struct iwl_rxon_context *bss_ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+       struct iwl_rxon_context *tmp;
+       enum nl80211_iftype newviftype = newtype;
+       u32 interface_modes;
+       int err;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       newtype = ieee80211_iftype_p2p(newtype, newp2p);
+
+       mutex_lock(&priv->shrd->mutex);
+
+       if (!ctx->vif || !iwl_is_ready_rf(priv->shrd)) {
+               /*
+                * Huh? But wait ... this can maybe happen when
+                * we're in the middle of a firmware restart!
+                */
+               err = -EBUSY;
+               goto out;
+       }
+
+       interface_modes = ctx->interface_modes | ctx->exclusive_interface_modes;
+
+       if (!(interface_modes & BIT(newtype))) {
+               err = -EBUSY;
+               goto out;
+       }
+
+       /*
+        * Refuse a change that should be done by moving from the PAN
+        * context to the BSS context instead, if the BSS context is
+        * available and can support the new interface type.
+        */
+       if (ctx->ctxid == IWL_RXON_CTX_PAN && !bss_ctx->vif &&
+           (bss_ctx->interface_modes & BIT(newtype) ||
+            bss_ctx->exclusive_interface_modes & BIT(newtype))) {
+               BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
+               err = -EBUSY;
+               goto out;
+       }
+
+       if (ctx->exclusive_interface_modes & BIT(newtype)) {
+               for_each_context(priv, tmp) {
+                       if (ctx == tmp)
+                               continue;
+
+                       if (!tmp->vif)
+                               continue;
+
+                       /*
+                        * The current mode switch would be exclusive, but
+                        * another context is active ... refuse the switch.
+                        */
+                       err = -EBUSY;
+                       goto out;
+               }
+       }
+
+       /* success */
+       iwl_teardown_interface(priv, vif, true);
+       vif->type = newviftype;
+       vif->p2p = newp2p;
+       err = iwl_setup_interface(priv, ctx);
+       WARN_ON(err);
+       /*
+        * We've switched internally, but submitting to the
+        * device may have failed for some reason. Mask this
+        * error, because otherwise mac80211 will not switch
+        * (and set the interface type back) and we'll be
+        * out of sync with it.
+        */
+       err = 0;
+
+ out:
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       return err;
+}
+
+static int iwlagn_mac_hw_scan(struct ieee80211_hw *hw,
+                   struct ieee80211_vif *vif,
+                   struct cfg80211_scan_request *req)
+{
+       struct iwl_priv *priv = hw->priv;
+       int ret;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       if (req->n_channels == 0)
+               return -EINVAL;
+
+       mutex_lock(&priv->shrd->mutex);
+
+       /*
+        * If an internal scan is in progress, just set
+        * up the scan_request as per above.
+        */
+       if (priv->scan_type != IWL_SCAN_NORMAL) {
+               IWL_DEBUG_SCAN(priv,
+                              "SCAN request during internal scan - defer\n");
+               priv->scan_request = req;
+               priv->scan_vif = vif;
+               ret = 0;
+       } else {
+               priv->scan_request = req;
+               priv->scan_vif = vif;
+               /*
+                * mac80211 will only ask for one band at a time
+                * so using channels[0] here is ok
+                */
+               ret = iwl_scan_initiate(priv, vif, IWL_SCAN_NORMAL,
+                                       req->channels[0]->band);
+               if (ret) {
+                       priv->scan_request = NULL;
+                       priv->scan_vif = NULL;
+               }
+       }
+
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       mutex_unlock(&priv->shrd->mutex);
+
+       return ret;
+}
+
+static int iwlagn_mac_sta_remove(struct ieee80211_hw *hw,
+                      struct ieee80211_vif *vif,
+                      struct ieee80211_sta *sta)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+       int ret;
+
+       IWL_DEBUG_MAC80211(priv, "enter: received request to remove "
+                          "station %pM\n", sta->addr);
+       mutex_lock(&priv->shrd->mutex);
+       IWL_DEBUG_INFO(priv, "proceeding to remove station %pM\n",
+                       sta->addr);
+       ret = iwl_remove_station(priv, sta_priv->sta_id, sta->addr);
+       if (ret)
+               IWL_DEBUG_QUIET_RFKILL(priv, "Error removing station %pM\n",
+                       sta->addr);
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       return ret;
+}
+
+static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->shrd->sta_lock, flags);
+       priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK;
+       priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK;
+       priv->stations[sta_id].sta.sta.modify_mask = 0;
+       priv->stations[sta_id].sta.sleep_tx_count = 0;
+       priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+       iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+       spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
+
+}
+
+static void iwlagn_mac_sta_notify(struct ieee80211_hw *hw,
+                          struct ieee80211_vif *vif,
+                          enum sta_notify_cmd cmd,
+                          struct ieee80211_sta *sta)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+       int sta_id;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       switch (cmd) {
+       case STA_NOTIFY_SLEEP:
+               WARN_ON(!sta_priv->client);
+               sta_priv->asleep = true;
+               if (atomic_read(&sta_priv->pending_frames) > 0)
+                       ieee80211_sta_block_awake(hw, sta, true);
+               break;
+       case STA_NOTIFY_AWAKE:
+               WARN_ON(!sta_priv->client);
+               if (!sta_priv->asleep)
+                       break;
+               sta_priv->asleep = false;
+               sta_id = iwl_sta_id(sta);
+               if (sta_id != IWL_INVALID_STATION)
+                       iwl_sta_modify_ps_wake(priv, sta_id);
+               break;
+       default:
+               break;
+       }
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+struct ieee80211_ops iwlagn_hw_ops = {
+       .tx = iwlagn_mac_tx,
+       .start = iwlagn_mac_start,
+       .stop = iwlagn_mac_stop,
+#ifdef CONFIG_PM_SLEEP
+       .suspend = iwlagn_mac_suspend,
+       .resume = iwlagn_mac_resume,
+#endif
+       .add_interface = iwlagn_mac_add_interface,
+       .remove_interface = iwlagn_mac_remove_interface,
+       .change_interface = iwlagn_mac_change_interface,
+       .config = iwlagn_mac_config,
+       .configure_filter = iwlagn_configure_filter,
+       .set_key = iwlagn_mac_set_key,
+       .update_tkip_key = iwlagn_mac_update_tkip_key,
+       .set_rekey_data = iwlagn_mac_set_rekey_data,
+       .conf_tx = iwlagn_mac_conf_tx,
+       .bss_info_changed = iwlagn_bss_info_changed,
+       .ampdu_action = iwlagn_mac_ampdu_action,
+       .hw_scan = iwlagn_mac_hw_scan,
+       .sta_notify = iwlagn_mac_sta_notify,
+       .sta_add = iwlagn_mac_sta_add,
+       .sta_remove = iwlagn_mac_sta_remove,
+       .channel_switch = iwlagn_mac_channel_switch,
+       .flush = iwlagn_mac_flush,
+       .tx_last_beacon = iwlagn_mac_tx_last_beacon,
+       .remain_on_channel = iwlagn_mac_remain_on_channel,
+       .cancel_remain_on_channel = iwlagn_mac_cancel_remain_on_channel,
+       .rssi_callback = iwlagn_mac_rssi_callback,
+       CFG80211_TESTMODE_CMD(iwlagn_mac_testmode_cmd)
+       CFG80211_TESTMODE_DUMP(iwlagn_mac_testmode_dump)
+       .tx_sync = iwlagn_mac_tx_sync,
+       .finish_tx_sync = iwlagn_mac_finish_tx_sync,
+       .set_tim = iwlagn_mac_set_tim,
+};
+
+/* This function both allocates and initializes hw and priv. */
+struct ieee80211_hw *iwl_alloc_all(void)
+{
+       struct iwl_priv *priv;
+       /* mac80211 allocates memory for this device instance, including
+        *   space for this driver's private structure */
+       struct ieee80211_hw *hw;
+
+       hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), &iwlagn_hw_ops);
+       if (!hw)
+               goto out;
+
+       priv = hw->priv;
+       priv->hw = hw;
+
+out:
+       return hw;
+}
index 1800029..850ec8e 100644 (file)
@@ -256,6 +256,8 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
        {IWL_PCI_DEVICE(0x0082, 0xC020, iwl6005_2agn_sff_cfg)},
        {IWL_PCI_DEVICE(0x0085, 0xC220, iwl6005_2agn_sff_cfg)},
        {IWL_PCI_DEVICE(0x0082, 0x1341, iwl6005_2agn_d_cfg)},
+       {IWL_PCI_DEVICE(0x0082, 0x1304, iwl6005_2agn_cfg)},/* low 5GHz active */
+       {IWL_PCI_DEVICE(0x0082, 0x1305, iwl6005_2agn_cfg)},/* high 5GHz active */
 
 /* 6x30 Series */
        {IWL_PCI_DEVICE(0x008A, 0x5305, iwl1030_bgn_cfg)},
@@ -325,46 +327,28 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
        {IWL_PCI_DEVICE(0x0890, 0x4022, iwl2000_2bgn_cfg)},
        {IWL_PCI_DEVICE(0x0891, 0x4222, iwl2000_2bgn_cfg)},
        {IWL_PCI_DEVICE(0x0890, 0x4422, iwl2000_2bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0890, 0x4026, iwl2000_2bg_cfg)},
-       {IWL_PCI_DEVICE(0x0891, 0x4226, iwl2000_2bg_cfg)},
-       {IWL_PCI_DEVICE(0x0890, 0x4426, iwl2000_2bg_cfg)},
        {IWL_PCI_DEVICE(0x0890, 0x4822, iwl2000_2bgn_d_cfg)},
 
 /* 2x30 Series */
        {IWL_PCI_DEVICE(0x0887, 0x4062, iwl2030_2bgn_cfg)},
        {IWL_PCI_DEVICE(0x0888, 0x4262, iwl2030_2bgn_cfg)},
        {IWL_PCI_DEVICE(0x0887, 0x4462, iwl2030_2bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0887, 0x4066, iwl2030_2bg_cfg)},
-       {IWL_PCI_DEVICE(0x0888, 0x4266, iwl2030_2bg_cfg)},
-       {IWL_PCI_DEVICE(0x0887, 0x4466, iwl2030_2bg_cfg)},
 
 /* 6x35 Series */
        {IWL_PCI_DEVICE(0x088E, 0x4060, iwl6035_2agn_cfg)},
        {IWL_PCI_DEVICE(0x088F, 0x4260, iwl6035_2agn_cfg)},
        {IWL_PCI_DEVICE(0x088E, 0x4460, iwl6035_2agn_cfg)},
-       {IWL_PCI_DEVICE(0x088E, 0x4064, iwl6035_2abg_cfg)},
-       {IWL_PCI_DEVICE(0x088F, 0x4264, iwl6035_2abg_cfg)},
-       {IWL_PCI_DEVICE(0x088E, 0x4464, iwl6035_2abg_cfg)},
-       {IWL_PCI_DEVICE(0x088E, 0x4066, iwl6035_2bg_cfg)},
-       {IWL_PCI_DEVICE(0x088F, 0x4266, iwl6035_2bg_cfg)},
-       {IWL_PCI_DEVICE(0x088E, 0x4466, iwl6035_2bg_cfg)},
 
 /* 105 Series */
        {IWL_PCI_DEVICE(0x0894, 0x0022, iwl105_bgn_cfg)},
        {IWL_PCI_DEVICE(0x0895, 0x0222, iwl105_bgn_cfg)},
        {IWL_PCI_DEVICE(0x0894, 0x0422, iwl105_bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0894, 0x0026, iwl105_bg_cfg)},
-       {IWL_PCI_DEVICE(0x0895, 0x0226, iwl105_bg_cfg)},
-       {IWL_PCI_DEVICE(0x0894, 0x0426, iwl105_bg_cfg)},
        {IWL_PCI_DEVICE(0x0894, 0x0822, iwl105_bgn_d_cfg)},
 
 /* 135 Series */
        {IWL_PCI_DEVICE(0x0892, 0x0062, iwl135_bgn_cfg)},
        {IWL_PCI_DEVICE(0x0893, 0x0262, iwl135_bgn_cfg)},
        {IWL_PCI_DEVICE(0x0892, 0x0462, iwl135_bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0892, 0x0066, iwl135_bg_cfg)},
-       {IWL_PCI_DEVICE(0x0893, 0x0266, iwl135_bg_cfg)},
-       {IWL_PCI_DEVICE(0x0892, 0x0466, iwl135_bg_cfg)},
 
        {0}
 };
index e5d727f..359d218 100644 (file)
@@ -416,6 +416,8 @@ static u16 iwl_limit_dwell(struct iwl_priv *priv, u16 dwell_time)
 
                if (!iwl_is_associated_ctx(ctx))
                        continue;
+               if (ctx->staging.dev_type == RXON_DEV_TYPE_P2P)
+                       continue;
                value = ctx->beacon_int;
                if (!value)
                        value = IWL_PASSIVE_DWELL_BASE;
@@ -678,7 +680,8 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
                        priv->contexts[IWL_RXON_CTX_BSS].active.flags &
                                                RXON_FLG_CHANNEL_MODE_MSK)
                                       >> RXON_FLG_CHANNEL_MODE_POS;
-               if (chan_mod == CHANNEL_MODE_PURE_40) {
+               if ((priv->scan_request && priv->scan_request->no_cck) ||
+                   chan_mod == CHANNEL_MODE_PURE_40) {
                        rate = IWL_RATE_6M_PLCP;
                } else {
                        rate = IWL_RATE_1M_PLCP;
@@ -938,51 +941,6 @@ int __must_check iwl_scan_initiate(struct iwl_priv *priv,
        return 0;
 }
 
-int iwlagn_mac_hw_scan(struct ieee80211_hw *hw,
-                   struct ieee80211_vif *vif,
-                   struct cfg80211_scan_request *req)
-{
-       struct iwl_priv *priv = hw->priv;
-       int ret;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-
-       if (req->n_channels == 0)
-               return -EINVAL;
-
-       mutex_lock(&priv->shrd->mutex);
-
-       /*
-        * If an internal scan is in progress, just set
-        * up the scan_request as per above.
-        */
-       if (priv->scan_type != IWL_SCAN_NORMAL) {
-               IWL_DEBUG_SCAN(priv,
-                              "SCAN request during internal scan - defer\n");
-               priv->scan_request = req;
-               priv->scan_vif = vif;
-               ret = 0;
-       } else {
-               priv->scan_request = req;
-               priv->scan_vif = vif;
-               /*
-                * mac80211 will only ask for one band at a time
-                * so using channels[0] here is ok
-                */
-               ret = iwl_scan_initiate(priv, vif, IWL_SCAN_NORMAL,
-                                       req->channels[0]->band);
-               if (ret) {
-                       priv->scan_request = NULL;
-                       priv->scan_vif = NULL;
-               }
-       }
-
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       mutex_unlock(&priv->shrd->mutex);
-
-       return ret;
-}
 
 /*
  * internal short scan, this function should only been called while associated.
index 5e50d88..e3882d0 100644 (file)
@@ -396,8 +396,7 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
                break;
 
        case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW:
-               status = iwlagn_load_ucode_wait_alive(priv, &priv->ucode_init,
-                                                     IWL_UCODE_INIT);
+               status = iwlagn_load_ucode_wait_alive(priv, IWL_UCODE_INIT);
                if (status)
                        IWL_DEBUG_INFO(priv,
                                "Error loading init ucode: %d\n", status);
@@ -409,9 +408,7 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
                break;
 
        case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW:
-               status = iwlagn_load_ucode_wait_alive(priv,
-                                          &priv->ucode_rt,
-                                          IWL_UCODE_REGULAR);
+               status = iwlagn_load_ucode_wait_alive(priv, IWL_UCODE_REGULAR);
                if (status) {
                        IWL_DEBUG_INFO(priv,
                                "Error loading runtime ucode: %d\n", status);
index 2b6756e..afaaa2a 100644 (file)
@@ -355,7 +355,7 @@ static inline void iwl_set_swq_id(struct iwl_tx_queue *txq, u8 ac, u8 hwq)
 }
 
 static inline void iwl_wake_queue(struct iwl_trans *trans,
-                                 struct iwl_tx_queue *txq)
+                                 struct iwl_tx_queue *txq, const char *msg)
 {
        u8 queue = txq->swq_id;
        u8 ac = queue & 3;
@@ -363,13 +363,22 @@ static inline void iwl_wake_queue(struct iwl_trans *trans,
        struct iwl_trans_pcie *trans_pcie =
                IWL_TRANS_GET_PCIE_TRANS(trans);
 
-       if (test_and_clear_bit(hwq, trans_pcie->queue_stopped))
-               if (atomic_dec_return(&trans_pcie->queue_stop_count[ac]) <= 0)
+       if (test_and_clear_bit(hwq, trans_pcie->queue_stopped)) {
+               if (atomic_dec_return(&trans_pcie->queue_stop_count[ac]) <= 0) {
                        iwl_wake_sw_queue(priv(trans), ac);
+                       IWL_DEBUG_TX_QUEUES(trans, "Wake hwq %d ac %d. %s",
+                                           hwq, ac, msg);
+               } else {
+                       IWL_DEBUG_TX_QUEUES(trans, "Don't wake hwq %d ac %d"
+                                           " stop count %d. %s",
+                                           hwq, ac, atomic_read(&trans_pcie->
+                                           queue_stop_count[ac]), msg);
+               }
+       }
 }
 
 static inline void iwl_stop_queue(struct iwl_trans *trans,
-                                 struct iwl_tx_queue *txq)
+                                 struct iwl_tx_queue *txq, const char *msg)
 {
        u8 queue = txq->swq_id;
        u8 ac = queue & 3;
@@ -377,9 +386,23 @@ static inline void iwl_stop_queue(struct iwl_trans *trans,
        struct iwl_trans_pcie *trans_pcie =
                IWL_TRANS_GET_PCIE_TRANS(trans);
 
-       if (!test_and_set_bit(hwq, trans_pcie->queue_stopped))
-               if (atomic_inc_return(&trans_pcie->queue_stop_count[ac]) > 0)
+       if (!test_and_set_bit(hwq, trans_pcie->queue_stopped)) {
+               if (atomic_inc_return(&trans_pcie->queue_stop_count[ac]) > 0) {
                        iwl_stop_sw_queue(priv(trans), ac);
+                       IWL_DEBUG_TX_QUEUES(trans, "Stop hwq %d ac %d"
+                                           " stop count %d. %s",
+                                           hwq, ac, atomic_read(&trans_pcie->
+                                           queue_stop_count[ac]), msg);
+               } else {
+                       IWL_DEBUG_TX_QUEUES(trans, "Don't stop hwq %d ac %d"
+                                           " stop count %d. %s",
+                                           hwq, ac, atomic_read(&trans_pcie->
+                                           queue_stop_count[ac]), msg);
+               }
+       } else {
+               IWL_DEBUG_TX_QUEUES(trans, "stop hwq %d, but it is stopped/ %s",
+                                   hwq, msg);
+       }
 }
 
 #ifdef ieee80211_stop_queue
index 374c68c..ee126f8 100644 (file)
@@ -1108,7 +1108,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans)
                isr_stats->tx++;
                handled |= CSR_INT_BIT_FH_TX;
                /* Wake up uCode load routine, now that load is complete */
-               priv(trans)->ucode_write_complete = 1;
+               trans->ucode_write_complete = 1;
                wake_up(&trans->shrd->wait_command_queue);
        }
 
index 4a0c953..6dba151 100644 (file)
@@ -430,7 +430,7 @@ void iwl_trans_tx_queue_set_status(struct iwl_trans *trans,
 
        txq->sched_retry = scd_retry;
 
-       IWL_DEBUG_INFO(trans, "%s %s Queue %d on FIFO %d\n",
+       IWL_DEBUG_TX_QUEUES(trans, "%s %s Queue %d on FIFO %d\n",
                       active ? "Activate" : "Deactivate",
                       scd_retry ? "BA" : "AC/CMD", txq_id, tx_fifo_id);
 }
@@ -561,12 +561,13 @@ int iwl_trans_pcie_tx_agg_alloc(struct iwl_trans *trans,
 
        tid_data = &trans->shrd->tid_data[sta_id][tid];
        if (tid_data->tfds_in_queue == 0) {
-               IWL_DEBUG_HT(trans, "HW queue is empty\n");
+               IWL_DEBUG_TX_QUEUES(trans, "HW queue is empty\n");
                tid_data->agg.state = IWL_AGG_ON;
                iwl_start_tx_ba_trans_ready(priv(trans), ctx, sta_id, tid);
        } else {
-               IWL_DEBUG_HT(trans, "HW queue is NOT empty: %d packets in HW"
-                            "queue\n", tid_data->tfds_in_queue);
+               IWL_DEBUG_TX_QUEUES(trans,
+                                   "HW queue is NOT empty: %d packets in HW"
+                                   " queue\n", tid_data->tfds_in_queue);
                tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA;
        }
        spin_unlock_irqrestore(&trans->shrd->sta_lock, flags);
@@ -643,14 +644,15 @@ int iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans,
 
        /* The queue is not empty */
        if (write_ptr != read_ptr) {
-               IWL_DEBUG_HT(trans, "Stopping a non empty AGG HW QUEUE\n");
+               IWL_DEBUG_TX_QUEUES(trans,
+                                   "Stopping a non empty AGG HW QUEUE\n");
                trans->shrd->tid_data[sta_id][tid].agg.state =
                        IWL_EMPTYING_HW_QUEUE_DELBA;
                spin_unlock_irqrestore(&trans->shrd->sta_lock, flags);
                return 0;
        }
 
-       IWL_DEBUG_HT(trans, "HW queue is empty\n");
+       IWL_DEBUG_TX_QUEUES(trans, "HW queue is empty\n");
 turn_off:
        trans->shrd->tid_data[sta_id][tid].agg.state = IWL_AGG_OFF;
 
@@ -982,7 +984,8 @@ static int iwl_send_cmd_async(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
 
        ret = iwl_enqueue_hcmd(trans, cmd);
        if (ret < 0) {
-               IWL_ERR(trans, "Error sending %s: enqueue_hcmd failed: %d\n",
+               IWL_DEBUG_QUIET_RFKILL(trans,
+                       "Error sending %s: enqueue_hcmd failed: %d\n",
                          get_cmd_string(cmd->id), ret);
                return ret;
        }
@@ -1000,6 +1003,20 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
        IWL_DEBUG_INFO(trans, "Attempting to send sync command %s\n",
                        get_cmd_string(cmd->id));
 
+       if (test_bit(STATUS_EXIT_PENDING, &trans->shrd->status))
+               return -EBUSY;
+
+
+       if (test_bit(STATUS_RF_KILL_HW, &trans->shrd->status)) {
+               IWL_ERR(trans, "Command %s aborted: RF KILL Switch\n",
+                              get_cmd_string(cmd->id));
+               return -ECANCELED;
+       }
+       if (test_bit(STATUS_FW_ERROR, &trans->shrd->status)) {
+               IWL_ERR(trans, "Command %s failed: FW Error\n",
+                              get_cmd_string(cmd->id));
+               return -EIO;
+       }
        set_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status);
        IWL_DEBUG_INFO(trans, "Setting HCMD_ACTIVE for command %s\n",
                        get_cmd_string(cmd->id));
@@ -1008,7 +1025,8 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
        if (cmd_idx < 0) {
                ret = cmd_idx;
                clear_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status);
-               IWL_ERR(trans, "Error sending %s: enqueue_hcmd failed: %d\n",
+               IWL_DEBUG_QUIET_RFKILL(trans,
+                       "Error sending %s: enqueue_hcmd failed: %d\n",
                          get_cmd_string(cmd->id), ret);
                return ret;
        }
@@ -1022,12 +1040,12 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
                                &trans_pcie->txq[trans->shrd->cmd_queue];
                        struct iwl_queue *q = &txq->q;
 
-                       IWL_ERR(trans,
+                       IWL_DEBUG_QUIET_RFKILL(trans,
                                "Error sending %s: time out after %dms.\n",
                                get_cmd_string(cmd->id),
                                jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));
 
-                       IWL_ERR(trans,
+                       IWL_DEBUG_QUIET_RFKILL(trans,
                                "Current CMD queue read_ptr %d write_ptr %d\n",
                                q->read_ptr, q->write_ptr);
 
@@ -1039,18 +1057,6 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
                }
        }
 
-       if (test_bit(STATUS_RF_KILL_HW, &trans->shrd->status)) {
-               IWL_ERR(trans, "Command %s aborted: RF KILL Switch\n",
-                              get_cmd_string(cmd->id));
-               ret = -ECANCELED;
-               goto fail;
-       }
-       if (test_bit(STATUS_FW_ERROR, &trans->shrd->status)) {
-               IWL_ERR(trans, "Command %s failed: FW Error\n",
-                              get_cmd_string(cmd->id));
-               ret = -EIO;
-               goto fail;
-       }
        if ((cmd->flags & CMD_WANT_SKB) && !cmd->reply_page) {
                IWL_ERR(trans, "Error: Response NULL in '%s'\n",
                          get_cmd_string(cmd->id));
@@ -1071,7 +1077,7 @@ cancel:
                trans_pcie->txq[trans->shrd->cmd_queue].meta[cmd_idx].flags &=
                                                        ~CMD_WANT_SKB;
        }
-fail:
+
        if (cmd->reply_page) {
                iwl_free_pages(trans->shrd, cmd->reply_page);
                cmd->reply_page = 0;
index da34110..93c4f56 100644 (file)
@@ -990,29 +990,16 @@ static int iwl_trans_tx_stop(struct iwl_trans *trans)
        return 0;
 }
 
-static void iwl_trans_pcie_disable_sync_irq(struct iwl_trans *trans)
+static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
 {
        unsigned long flags;
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 
+       /* tell the device to stop sending interrupts */
        spin_lock_irqsave(&trans->shrd->lock, flags);
        iwl_disable_interrupts(trans);
        spin_unlock_irqrestore(&trans->shrd->lock, flags);
 
-       /* wait to make sure we flush pending tasklet*/
-       synchronize_irq(bus(trans)->irq);
-       tasklet_kill(&trans_pcie->irq_tasklet);
-}
-
-static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
-{
-       /* stop and reset the on-board processor */
-       iwl_write32(bus(trans), CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
-
-       /* tell the device to stop sending interrupts */
-       iwl_trans_pcie_disable_sync_irq(trans);
-
        /* device going down, Stop using ICT table */
        iwl_disable_ict(trans);
 
@@ -1039,6 +1026,20 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
 
        /* Stop the device, and put it in low power state */
        iwl_apm_stop(priv(trans));
+
+       /* Upon stop, the APM issues an interrupt if HW RF kill is set.
+        * Clean again the interrupt here
+        */
+       spin_lock_irqsave(&trans->shrd->lock, flags);
+       iwl_disable_interrupts(trans);
+       spin_unlock_irqrestore(&trans->shrd->lock, flags);
+
+       /* wait to make sure we flush pending tasklet*/
+       synchronize_irq(bus(trans)->irq);
+       tasklet_kill(&trans_pcie->irq_tasklet);
+
+       /* stop and reset the on-board processor */
+       iwl_write32(bus(trans), CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
 }
 
 static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
@@ -1231,7 +1232,7 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
                        txq->need_update = 1;
                        iwl_txq_update_write_ptr(trans, txq);
                } else {
-                       iwl_stop_queue(trans, txq);
+                       iwl_stop_queue(trans, txq, "Queue is full");
                }
        }
        return 0;
@@ -1283,20 +1284,21 @@ static int iwlagn_txq_check_empty(struct iwl_trans *trans,
                /* aggregated HW queue */
                if ((txq_id  == tid_data->agg.txq_id) &&
                    (q->read_ptr == q->write_ptr)) {
-                       IWL_DEBUG_HT(trans,
+                       IWL_DEBUG_TX_QUEUES(trans,
                                "HW queue empty: continue DELBA flow\n");
                        iwl_trans_pcie_txq_agg_disable(trans, txq_id);
                        tid_data->agg.state = IWL_AGG_OFF;
                        iwl_stop_tx_ba_trans_ready(priv(trans),
                                                   NUM_IWL_RXON_CTX,
                                                   sta_id, tid);
-                       iwl_wake_queue(trans, &trans_pcie->txq[txq_id]);
+                       iwl_wake_queue(trans, &trans_pcie->txq[txq_id],
+                                      "DELBA flow complete");
                }
                break;
        case IWL_EMPTYING_HW_QUEUE_ADDBA:
                /* We are reclaiming the last packet of the queue */
                if (tid_data->tfds_in_queue == 0) {
-                       IWL_DEBUG_HT(trans,
+                       IWL_DEBUG_TX_QUEUES(trans,
                                "HW queue empty: continue ADDBA flow\n");
                        tid_data->agg.state = IWL_AGG_ON;
                        iwl_start_tx_ba_trans_ready(priv(trans),
@@ -1354,7 +1356,7 @@ static void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid,
                                ssn , tfd_num, txq_id, txq->swq_id);
                freed = iwl_tx_queue_reclaim(trans, txq_id, tfd_num, skbs);
                if (iwl_queue_space(&txq->q) > txq->q.low_mark && cond)
-                       iwl_wake_queue(trans, txq);
+                       iwl_wake_queue(trans, txq, "Packets reclaimed");
        }
 
        iwl_free_tfds_in_queue(trans, sta_id, tid, freed);
@@ -1418,7 +1420,8 @@ static int iwl_trans_pcie_resume(struct iwl_trans *trans)
 #endif /* CONFIG_PM_SLEEP */
 
 static void iwl_trans_pcie_wake_any_queue(struct iwl_trans *trans,
-                                         enum iwl_rxon_context_id ctx)
+                                         enum iwl_rxon_context_id ctx,
+                                         const char *msg)
 {
        u8 ac, txq_id;
        struct iwl_trans_pcie *trans_pcie =
@@ -1426,11 +1429,11 @@ static void iwl_trans_pcie_wake_any_queue(struct iwl_trans *trans,
 
        for (ac = 0; ac < AC_NUM; ac++) {
                txq_id = trans_pcie->ac_to_queue[ctx][ac];
-               IWL_DEBUG_INFO(trans, "Queue Status: Q[%d] %s\n",
+               IWL_DEBUG_TX_QUEUES(trans, "Queue Status: Q[%d] %s\n",
                        ac,
                        (atomic_read(&trans_pcie->queue_stop_count[ac]) > 0)
                              ? "stopped" : "awake");
-               iwl_wake_queue(trans, &trans_pcie->txq[txq_id]);
+               iwl_wake_queue(trans, &trans_pcie->txq[txq_id], msg);
        }
 }
 
@@ -1453,11 +1456,12 @@ static struct iwl_trans *iwl_trans_pcie_alloc(struct iwl_shared *shrd)
        return iwl_trans;
 }
 
-static void iwl_trans_pcie_stop_queue(struct iwl_trans *trans, int txq_id)
+static void iwl_trans_pcie_stop_queue(struct iwl_trans *trans, int txq_id,
+                                     const char *msg)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 
-       iwl_stop_queue(trans, &trans_pcie->txq[txq_id]);
+       iwl_stop_queue(trans, &trans_pcie->txq[txq_id], msg);
 }
 
 #define IWL_FLUSH_WAIT_MS      2000
index c592312..50227eb 100644 (file)
@@ -171,7 +171,8 @@ struct iwl_trans_ops {
        void (*tx_start)(struct iwl_trans *trans);
 
        void (*wake_any_queue)(struct iwl_trans *trans,
-                              enum iwl_rxon_context_id ctx);
+                              enum iwl_rxon_context_id ctx,
+                              const char *msg);
 
        int (*send_cmd)(struct iwl_trans *trans, struct iwl_host_cmd *cmd);
 
@@ -196,7 +197,7 @@ struct iwl_trans_ops {
 
        void (*free)(struct iwl_trans *trans);
 
-       void (*stop_queue)(struct iwl_trans *trans, int q);
+       void (*stop_queue)(struct iwl_trans *trans, int q, const char *msg);
 
        int (*dbgfs_register)(struct iwl_trans *trans, struct dentry* dir);
        int (*check_stuck_queue)(struct iwl_trans *trans, int q);
@@ -207,17 +208,48 @@ struct iwl_trans_ops {
 #endif
 };
 
+/* one for each uCode image (inst/data, boot/init/runtime) */
+struct fw_desc {
+       dma_addr_t p_addr;      /* hardware address */
+       void *v_addr;           /* software address */
+       u32 len;                /* size in bytes */
+};
+
+struct fw_img {
+       struct fw_desc code;    /* firmware code image */
+       struct fw_desc data;    /* firmware data image */
+};
+
+enum iwl_ucode_type {
+       IWL_UCODE_NONE,
+       IWL_UCODE_REGULAR,
+       IWL_UCODE_INIT,
+       IWL_UCODE_WOWLAN,
+};
+
 /**
  * struct iwl_trans - transport common data
  * @ops - pointer to iwl_trans_ops
  * @shrd - pointer to iwl_shared which holds shared data from the upper layer
  * @hcmd_lock: protects HCMD
+ * @ucode_write_complete: indicates that the ucode has been copied.
+ * @ucode_rt: run time ucode image
+ * @ucode_init: init ucode image
+ * @ucode_wowlan: wake on wireless ucode image (optional)
  */
 struct iwl_trans {
        const struct iwl_trans_ops *ops;
        struct iwl_shared *shrd;
        spinlock_t hcmd_lock;
 
+       u8 ucode_write_complete;        /* the image write is complete */
+       struct fw_img ucode_rt;
+       struct fw_img ucode_init;
+       struct fw_img ucode_wowlan;
+
+       /* eeprom related variables */
+       int    nvm_device_type;
+
        /* pointer to trans specific struct */
        /*Ensure that this pointer will always be aligned to sizeof pointer */
        char trans_specific[0] __attribute__((__aligned__(sizeof(void *))));
@@ -249,9 +281,10 @@ static inline void iwl_trans_tx_start(struct iwl_trans *trans)
 }
 
 static inline void iwl_trans_wake_any_queue(struct iwl_trans *trans,
-                                           enum iwl_rxon_context_id ctx)
+                                           enum iwl_rxon_context_id ctx,
+                                           const char *msg)
 {
-       trans->ops->wake_any_queue(trans, ctx);
+       trans->ops->wake_any_queue(trans, ctx, msg);
 }
 
 
@@ -311,9 +344,10 @@ static inline void iwl_trans_free(struct iwl_trans *trans)
        trans->ops->free(trans);
 }
 
-static inline void iwl_trans_stop_queue(struct iwl_trans *trans, int q)
+static inline void iwl_trans_stop_queue(struct iwl_trans *trans, int q,
+                                       const char *msg)
 {
-       trans->ops->stop_queue(trans, q);
+       trans->ops->stop_queue(trans, q, msg);
 }
 
 static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans)
@@ -348,4 +382,8 @@ static inline int iwl_trans_resume(struct iwl_trans *trans)
 ******************************************************/
 extern const struct iwl_trans_ops trans_ops_pcie;
 
+int iwl_alloc_fw_desc(struct iwl_bus *bus, struct fw_desc *desc,
+                     const void *data, size_t len);
+void iwl_dealloc_ucode(struct iwl_trans *trans);
+
 #endif /* __iwl_trans_h__ */
index c42be81..48e8218 100644 (file)
@@ -165,11 +165,15 @@ static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
                                struct key_params *params)
 {
        struct iwm_priv *iwm = ndev_to_iwm(ndev);
-       struct iwm_key *key = &iwm->keys[key_index];
+       struct iwm_key *key;
        int ret;
 
        IWM_DBG_WEXT(iwm, DBG, "Adding key for %pM\n", mac_addr);
 
+       if (key_index >= IWM_NUM_KEYS)
+               return -ENOENT;
+
+       key = &iwm->keys[key_index];
        memset(key, 0, sizeof(struct iwm_key));
        ret = iwm_key_init(key, key_index, mac_addr, params);
        if (ret < 0) {
@@ -214,8 +218,12 @@ static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
                                u8 key_index, bool pairwise, const u8 *mac_addr)
 {
        struct iwm_priv *iwm = ndev_to_iwm(ndev);
-       struct iwm_key *key = &iwm->keys[key_index];
+       struct iwm_key *key;
 
+       if (key_index >= IWM_NUM_KEYS)
+               return -ENOENT;
+
+       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;
@@ -236,6 +244,9 @@ static int iwm_cfg80211_set_default_key(struct wiphy *wiphy,
 
        IWM_DBG_WEXT(iwm, DBG, "Default key index is: %d\n", key_index);
 
+       if (key_index >= IWM_NUM_KEYS)
+               return -ENOENT;
+
        if (!iwm->keys[key_index].key_len) {
                IWM_ERR(iwm, "Key %d not used\n", key_index);
                return -EINVAL;
index 4fcd653..d1d84e0 100644 (file)
@@ -485,6 +485,7 @@ static int lbs_cfg_set_channel(struct wiphy *wiphy,
 static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
        struct cmd_header *resp)
 {
+       struct cfg80211_bss *bss;
        struct cmd_ds_802_11_scan_rsp *scanresp = (void *)resp;
        int bsssize;
        const u8 *pos;
@@ -632,12 +633,14 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
                                     LBS_SCAN_RSSI_TO_MBM(rssi)/100);
 
                        if (channel &&
-                           !(channel->flags & IEEE80211_CHAN_DISABLED))
-                               cfg80211_inform_bss(wiphy, channel,
-                                       bssid, le64_to_cpu(*(__le64 *)tsfdesc),
+                           !(channel->flags & IEEE80211_CHAN_DISABLED)) {
+                               bss = cfg80211_inform_bss(wiphy, channel,
+                                       bssid, get_unaligned_le64(tsfdesc),
                                        capa, intvl, ie, ielen,
                                        LBS_SCAN_RSSI_TO_MBM(rssi),
                                        GFP_KERNEL);
+                               cfg80211_put_bss(bss);
+                       }
                } else
                        lbs_deb_scan("scan response: missing BSS channel IE\n");
 
@@ -1720,6 +1723,7 @@ static void lbs_join_post(struct lbs_private *priv,
                   2 + 2 +                      /* atim */
                   2 + 8];                      /* extended rates */
        u8 *fake = fake_ie;
+       struct cfg80211_bss *bss;
 
        lbs_deb_enter(LBS_DEB_CFG80211);
 
@@ -1763,14 +1767,15 @@ static void lbs_join_post(struct lbs_private *priv,
        *fake++ = 0x6c;
        lbs_deb_hex(LBS_DEB_CFG80211, "IE", fake_ie, fake - fake_ie);
 
-       cfg80211_inform_bss(priv->wdev->wiphy,
-                           params->channel,
-                           bssid,
-                           0,
-                           capability,
-                           params->beacon_interval,
-                           fake_ie, fake - fake_ie,
-                           0, GFP_KERNEL);
+       bss = cfg80211_inform_bss(priv->wdev->wiphy,
+                                 params->channel,
+                                 bssid,
+                                 0,
+                                 capability,
+                                 params->beacon_interval,
+                                 fake_ie, fake - fake_ie,
+                                 0, GFP_KERNEL);
+       cfg80211_put_bss(bss);
 
        memcpy(priv->wdev->ssid, params->ssid, params->ssid_len);
        priv->wdev->ssid_len = params->ssid_len;
index 11b69b3..728baa4 100644 (file)
@@ -995,6 +995,7 @@ static int if_spi_host_to_card(struct lbs_private *priv,
                spin_unlock_irqrestore(&card->buffer_lock, flags);
                break;
        default:
+               kfree(packet);
                netdev_err(priv->dev, "can't transfer buffer of type %d\n",
                           type);
                err = -EINVAL;
index 523ad55..6cf6d6d 100644 (file)
@@ -1748,6 +1748,8 @@ static int __init init_mac80211_hwsim(void)
                            IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
                            IEEE80211_HW_AMPDU_AGGREGATION;
 
+               hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
+
                /* ask mac80211 to reserve space for magic */
                hw->vif_data_size = sizeof(struct hwsim_vif_priv);
                hw->sta_data_size = sizeof(struct hwsim_sta_priv);
index 7aa9aa0..681d3f2 100644 (file)
@@ -33,7 +33,7 @@
  * Since the buffer is linear, the function uses rotation to simulate
  * circular buffer.
  */
-static int
+static void
 mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv,
                                         struct mwifiex_rx_reorder_tbl
                                         *rx_reor_tbl_ptr, int start_win)
@@ -71,8 +71,6 @@ mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv,
 
        rx_reor_tbl_ptr->start_win = start_win;
        spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
-
-       return 0;
 }
 
 /*
@@ -83,7 +81,7 @@ mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv,
  * Since the buffer is linear, the function uses rotation to simulate
  * circular buffer.
  */
-static int
+static void
 mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv,
                              struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr)
 {
@@ -119,7 +117,6 @@ mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv,
        rx_reor_tbl_ptr->start_win = (rx_reor_tbl_ptr->start_win + i)
                &(MAX_TID_VALUE - 1);
        spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
-       return 0;
 }
 
 /*
@@ -405,7 +402,7 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
                                u8 *ta, u8 pkt_type, void *payload)
 {
        struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
-       int start_win, end_win, win_size, ret;
+       int start_win, end_win, win_size;
        u16 pkt_index;
 
        rx_reor_tbl_ptr =
@@ -452,11 +449,8 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
                        start_win = (end_win - win_size) + 1;
                else
                        start_win = (MAX_TID_VALUE - (win_size - seq_num)) + 1;
-               ret = mwifiex_11n_dispatch_pkt_until_start_win(priv,
+               mwifiex_11n_dispatch_pkt_until_start_win(priv,
                                                rx_reor_tbl_ptr, start_win);
-
-               if (ret)
-                       return ret;
        }
 
        if (pkt_type != PKT_TYPE_BAR) {
@@ -475,9 +469,9 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
         * Dispatch all packets sequentially from start_win until a
         * hole is found and adjust the start_win appropriately
         */
-       ret = mwifiex_11n_scan_and_dispatch(priv, rx_reor_tbl_ptr);
+       mwifiex_11n_scan_and_dispatch(priv, rx_reor_tbl_ptr);
 
-       return ret;
+       return 0;
 }
 
 /*
index 462c710..e9ab9a3 100644 (file)
@@ -780,6 +780,7 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv)
 {
        struct ieee80211_channel *chan;
        struct mwifiex_bss_info bss_info;
+       struct cfg80211_bss *bss;
        int ie_len;
        u8 ie_buf[IEEE80211_MAX_SSID_LEN + sizeof(struct ieee_types_header)];
        enum ieee80211_band band;
@@ -800,9 +801,10 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv)
                        ieee80211_channel_to_frequency(bss_info.bss_chan,
                                                       band));
 
-       cfg80211_inform_bss(priv->wdev->wiphy, chan,
+       bss = cfg80211_inform_bss(priv->wdev->wiphy, chan,
                bss_info.bssid, 0, WLAN_CAPABILITY_IBSS,
                0, ie_buf, ie_len, 0, GFP_KERNEL);
+       cfg80211_put_bss(bss);
        memcpy(priv->cfg_bssid, bss_info.bssid, ETH_ALEN);
 
        return 0;
index 0cc5d73..35cb29c 100644 (file)
@@ -673,7 +673,7 @@ struct host_cmd_ds_802_11_ad_hoc_start {
        union ieee_types_phy_param_set phy_param_set;
        u16 reserved1;
        __le16 cap_info_bitmap;
-       u8 DataRate[HOSTCMD_SUPPORTED_RATES];
+       u8 data_rate[HOSTCMD_SUPPORTED_RATES];
 } __packed;
 
 struct host_cmd_ds_802_11_ad_hoc_result {
index d792b3f..2694045 100644 (file)
@@ -187,8 +187,6 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
        struct mwifiex_opt_sleep_confirm *sleep_cfm_buf = NULL;
 
        skb_put(adapter->sleep_cfm, sizeof(struct mwifiex_opt_sleep_confirm));
-       sleep_cfm_buf = (struct mwifiex_opt_sleep_confirm *)
-                                               (adapter->sleep_cfm->data);
 
        adapter->cmd_sent = false;
 
@@ -254,6 +252,8 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
        mwifiex_wmm_init(adapter);
 
        if (adapter->sleep_cfm) {
+               sleep_cfm_buf = (struct mwifiex_opt_sleep_confirm *)
+                                               adapter->sleep_cfm->data;
                memset(sleep_cfm_buf, 0, adapter->sleep_cfm->len);
                sleep_cfm_buf->command =
                                cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH);
index 62b4c29..1c49813 100644 (file)
@@ -724,8 +724,8 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
        u32 cmd_append_size = 0;
        u32 i;
        u16 tmp_cap;
-       uint16_t ht_cap_info;
        struct mwifiex_ie_types_chan_list_param_set *chan_tlv;
+       u8 radio_type;
 
        struct mwifiex_ie_types_htcap *ht_cap;
        struct mwifiex_ie_types_htinfo *ht_info;
@@ -837,8 +837,8 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
                bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL;
        }
 
-       memset(adhoc_start->DataRate, 0, sizeof(adhoc_start->DataRate));
-       mwifiex_get_active_data_rates(priv, adhoc_start->DataRate);
+       memset(adhoc_start->data_rate, 0, sizeof(adhoc_start->data_rate));
+       mwifiex_get_active_data_rates(priv, adhoc_start->data_rate);
        if ((adapter->adhoc_start_band & BAND_G) &&
            (priv->curr_pkt_filter & HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON)) {
                if (mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL,
@@ -850,20 +850,19 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
                }
        }
        /* Find the last non zero */
-       for (i = 0; i < sizeof(adhoc_start->DataRate) &&
-                       adhoc_start->DataRate[i];
-                       i++)
-                       ;
+       for (i = 0; i < sizeof(adhoc_start->data_rate); i++)
+               if (!adhoc_start->data_rate[i])
+                       break;
 
        priv->curr_bss_params.num_of_rates = i;
 
        /* Copy the ad-hoc creating rates into Current BSS rate structure */
        memcpy(&priv->curr_bss_params.data_rates,
-              &adhoc_start->DataRate, priv->curr_bss_params.num_of_rates);
+              &adhoc_start->data_rate, priv->curr_bss_params.num_of_rates);
 
        dev_dbg(adapter->dev, "info: ADHOC_S_CMD: rates=%02x %02x %02x %02x\n",
-              adhoc_start->DataRate[0], adhoc_start->DataRate[1],
-              adhoc_start->DataRate[2], adhoc_start->DataRate[3]);
+              adhoc_start->data_rate[0], adhoc_start->data_rate[1],
+              adhoc_start->data_rate[2], adhoc_start->data_rate[3]);
 
        dev_dbg(adapter->dev, "info: ADHOC_S_CMD: AD-HOC Start command is ready\n");
 
@@ -914,55 +913,40 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
        }
 
        if (adapter->adhoc_11n_enabled) {
-               {
-                       ht_cap = (struct mwifiex_ie_types_htcap *) pos;
-                       memset(ht_cap, 0,
-                              sizeof(struct mwifiex_ie_types_htcap));
-                       ht_cap->header.type =
-                               cpu_to_le16(WLAN_EID_HT_CAPABILITY);
-                       ht_cap->header.len =
-                              cpu_to_le16(sizeof(struct ieee80211_ht_cap));
-                       ht_cap_info = le16_to_cpu(ht_cap->ht_cap.cap_info);
-
-                       ht_cap_info |= IEEE80211_HT_CAP_SGI_20;
-                       if (adapter->chan_offset) {
-                               ht_cap_info |= IEEE80211_HT_CAP_SGI_40;
-                               ht_cap_info |= IEEE80211_HT_CAP_DSSSCCK40;
-                               ht_cap_info |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
-                               SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask);
-                       }
+               /* Fill HT CAPABILITY */
+               ht_cap = (struct mwifiex_ie_types_htcap *) pos;
+               memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap));
+               ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY);
+               ht_cap->header.len =
+                      cpu_to_le16(sizeof(struct ieee80211_ht_cap));
+               radio_type = mwifiex_band_to_radio_type(
+                                       priv->adapter->config_bands);
+               mwifiex_fill_cap_info(priv, radio_type, ht_cap);
+
+               pos += sizeof(struct mwifiex_ie_types_htcap);
+               cmd_append_size +=
+                       sizeof(struct mwifiex_ie_types_htcap);
 
-                       ht_cap->ht_cap.ampdu_params_info
-                                       = IEEE80211_HT_MAX_AMPDU_64K;
-                       ht_cap->ht_cap.mcs.rx_mask[0] = 0xff;
-                       pos += sizeof(struct mwifiex_ie_types_htcap);
-                       cmd_append_size +=
-                               sizeof(struct mwifiex_ie_types_htcap);
-               }
-               {
-                       ht_info = (struct mwifiex_ie_types_htinfo *) pos;
-                       memset(ht_info, 0,
-                              sizeof(struct mwifiex_ie_types_htinfo));
-                       ht_info->header.type =
-                               cpu_to_le16(WLAN_EID_HT_INFORMATION);
-                       ht_info->header.len =
-                               cpu_to_le16(sizeof(struct ieee80211_ht_info));
-                       ht_info->ht_info.control_chan =
-                               (u8) priv->curr_bss_params.bss_descriptor.
-                               channel;
-                       if (adapter->chan_offset) {
-                               ht_info->ht_info.ht_param =
-                                       adapter->chan_offset;
-                               ht_info->ht_info.ht_param |=
+               /* Fill HT INFORMATION */
+               ht_info = (struct mwifiex_ie_types_htinfo *) pos;
+               memset(ht_info, 0, sizeof(struct mwifiex_ie_types_htinfo));
+               ht_info->header.type = cpu_to_le16(WLAN_EID_HT_INFORMATION);
+               ht_info->header.len =
+                       cpu_to_le16(sizeof(struct ieee80211_ht_info));
+
+               ht_info->ht_info.control_chan =
+                       (u8) priv->curr_bss_params.bss_descriptor.channel;
+               if (adapter->chan_offset) {
+                       ht_info->ht_info.ht_param = adapter->chan_offset;
+                       ht_info->ht_info.ht_param |=
                                        IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;
-                       }
-                       ht_info->ht_info.operation_mode =
-                            cpu_to_le16(IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
-                       ht_info->ht_info.basic_set[0] = 0xff;
-                       pos += sizeof(struct mwifiex_ie_types_htinfo);
-                       cmd_append_size +=
-                               sizeof(struct mwifiex_ie_types_htinfo);
                }
+               ht_info->ht_info.operation_mode =
+                    cpu_to_le16(IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
+               ht_info->ht_info.basic_set[0] = 0xff;
+               pos += sizeof(struct mwifiex_ie_types_htinfo);
+               cmd_append_size +=
+                       sizeof(struct mwifiex_ie_types_htinfo);
        }
 
        cmd->size = cpu_to_le16((u16)
index d34acf0..a2f3200 100644 (file)
@@ -386,7 +386,6 @@ static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter)
        card->txbd_ring_vbase = kzalloc(card->txbd_ring_size, GFP_KERNEL);
        if (!card->txbd_ring_vbase) {
                dev_err(adapter->dev, "Unable to allocate buffer for txbd ring.\n");
-               kfree(card->txbd_ring_vbase);
                return -1;
        }
        card->txbd_ring_pbase = virt_to_phys(card->txbd_ring_vbase);
@@ -1229,9 +1228,12 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter,
        if (!skb)
                return 0;
 
-       if (rdptr >= MWIFIEX_MAX_EVT_BD)
+       if (rdptr >= MWIFIEX_MAX_EVT_BD) {
                dev_err(adapter->dev, "event_complete: Invalid rdptr 0x%x\n",
                                        rdptr);
+               ret = -EINVAL;
+               goto done;
+       }
 
        /* Read the event ring write pointer set by firmware */
        if (mwifiex_read_reg(adapter, REG_EVTBD_WRPTR, &wrptr)) {
@@ -1672,9 +1674,8 @@ static int mwifiex_pcie_host_to_card(struct mwifiex_adapter *adapter, u8 type,
                                     struct sk_buff *skb,
                                     struct mwifiex_tx_param *tx_param)
 {
-       if (!adapter || !skb) {
-               dev_err(adapter->dev, "Invalid parameter in %s <%p, %p>\n",
-                               __func__, adapter, skb);
+       if (!skb) {
+               dev_err(adapter->dev, "Passed NULL skb to %s\n", __func__);
                return -1;
        }
 
index dae8dbb..b8b9d37 100644 (file)
@@ -819,8 +819,10 @@ mwifiex_scan_setup_scan_config(struct mwifiex_private *priv,
                        wildcard_ssid_tlv->header.len = cpu_to_le16(
                                (u16) (ssid_len + sizeof(wildcard_ssid_tlv->
                                                         max_ssid_length)));
-                       wildcard_ssid_tlv->max_ssid_length =
-                               user_scan_in->ssid_list[ssid_idx].max_len;
+
+                       /* max_ssid_length = 0 tells firmware to perform
+                          specific scan for the SSID filled */
+                       wildcard_ssid_tlv->max_ssid_length = 0;
 
                        memcpy(wildcard_ssid_tlv->ssid,
                               user_scan_in->ssid_list[ssid_idx].ssid,
@@ -1469,7 +1471,7 @@ mwifiex_update_curr_bss_params(struct mwifiex_private *priv, u8 *bssid,
                               s32 rssi, const u8 *ie_buf, size_t ie_len,
                               u16 beacon_period, u16 cap_info_bitmap, u8 band)
 {
-       struct mwifiex_bssdescriptor *bss_desc = NULL;
+       struct mwifiex_bssdescriptor *bss_desc;
        int ret;
        unsigned long flags;
        u8 *beacon_ie;
@@ -1484,6 +1486,7 @@ mwifiex_update_curr_bss_params(struct mwifiex_private *priv, u8 *bssid,
 
        beacon_ie = kmemdup(ie_buf, ie_len, GFP_KERNEL);
        if (!beacon_ie) {
+               kfree(bss_desc);
                dev_err(priv->adapter->dev, " failed to alloc beacon_ie\n");
                return -ENOMEM;
        }
@@ -1534,11 +1537,6 @@ done:
        return 0;
 }
 
-static void mwifiex_free_bss_priv(struct cfg80211_bss *bss)
-{
-       kfree(bss->priv);
-}
-
 /*
  * This function handles the command response of scan.
  *
@@ -1764,7 +1762,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
                                              cap_info_bitmap, beacon_period,
                                              ie_buf, ie_len, rssi, GFP_KERNEL);
                                *(u8 *)bss->priv = band;
-                               bss->free_priv = mwifiex_free_bss_priv;
+                               cfg80211_put_bss(bss);
 
                                if (priv->media_connected && !memcmp(bssid,
                                        priv->curr_bss_params.bss_descriptor
index 283171b..ffaf3f3 100644 (file)
@@ -1630,14 +1630,14 @@ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter)
        card->mpa_tx.pkt_cnt = 0;
        card->mpa_tx.start_port = 0;
 
-       card->mpa_tx.enabled = 0;
+       card->mpa_tx.enabled = 1;
        card->mpa_tx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT;
 
        card->mpa_rx.buf_len = 0;
        card->mpa_rx.pkt_cnt = 0;
        card->mpa_rx.start_port = 0;
 
-       card->mpa_rx.enabled = 0;
+       card->mpa_rx.enabled = 1;
        card->mpa_rx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT;
 
        /* Allocate buffers for SDIO MP-A */
index 2743051..5e1ef7e 100644 (file)
@@ -126,6 +126,9 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter,
        u16 rx_pkt_type;
        struct mwifiex_private *priv = adapter->priv[rx_info->bss_index];
 
+       if (!priv)
+               return -1;
+
        local_rx_pd = (struct rxpd *) (skb->data);
        rx_pkt_type = local_rx_pd->rx_pkt_type;
 
@@ -189,12 +192,11 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter,
                                             (u8) local_rx_pd->rx_pkt_type,
                                             skb);
 
-       if (ret || (rx_pkt_type == PKT_TYPE_BAR)) {
-               if (priv && (ret == -1))
-                       priv->stats.rx_dropped++;
-
+       if (ret || (rx_pkt_type == PKT_TYPE_BAR))
                dev_kfree_skb_any(skb);
-       }
+
+       if (ret)
+               priv->stats.rx_dropped++;
 
        return ret;
 }
index e99ca1c..96e39ed 100644 (file)
@@ -76,6 +76,7 @@ static void orinoco_add_hostscan_result(struct orinoco_private *priv,
 {
        struct wiphy *wiphy = priv_to_wiphy(priv);
        struct ieee80211_channel *channel;
+       struct cfg80211_bss *cbss;
        u8 *ie;
        u8 ie_buf[46];
        u64 timestamp;
@@ -121,9 +122,10 @@ static void orinoco_add_hostscan_result(struct orinoco_private *priv,
        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);
+       cbss = cfg80211_inform_bss(wiphy, channel, bss->a.bssid, timestamp,
+                                  capability, beacon_interval, ie_buf, ie_len,
+                                  signal, GFP_KERNEL);
+       cfg80211_put_bss(cbss);
 }
 
 void orinoco_add_extscan_result(struct orinoco_private *priv,
@@ -132,6 +134,7 @@ void orinoco_add_extscan_result(struct orinoco_private *priv,
 {
        struct wiphy *wiphy = priv_to_wiphy(priv);
        struct ieee80211_channel *channel;
+       struct cfg80211_bss *cbss;
        const u8 *ie;
        u64 timestamp;
        s32 signal;
@@ -152,9 +155,10 @@ void orinoco_add_extscan_result(struct orinoco_private *priv,
        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);
+       cbss = cfg80211_inform_bss(wiphy, channel, bss->bssid, timestamp,
+                                  capability, beacon_interval, ie, ie_len,
+                                  signal, GFP_KERNEL);
+       cfg80211_put_bss(cbss);
 }
 
 void orinoco_add_hostscan_results(struct orinoco_private *priv,
index 0c13840..620e3c0 100644 (file)
@@ -414,6 +414,7 @@ struct ndis_80211_pmkid {
 #define RNDIS_WLAN_ALG_TKIP    (1<<1)
 #define RNDIS_WLAN_ALG_CCMP    (1<<2)
 
+#define RNDIS_WLAN_NUM_KEYS            4
 #define RNDIS_WLAN_KEY_MGMT_NONE       0
 #define RNDIS_WLAN_KEY_MGMT_802_1X     (1<<0)
 #define RNDIS_WLAN_KEY_MGMT_PSK                (1<<1)
@@ -516,7 +517,7 @@ struct rndis_wlan_private {
 
        /* encryption stuff */
        int  encr_tx_key_index;
-       struct rndis_wlan_encr_key encr_keys[4];
+       struct rndis_wlan_encr_key encr_keys[RNDIS_WLAN_NUM_KEYS];
        int  wpa_version;
 
        u8 command_buffer[COMMAND_BUFFER_SIZE];
@@ -1535,6 +1536,9 @@ static int remove_key(struct usbnet *usbdev, int index, const u8 *bssid)
        bool is_wpa;
        int ret;
 
+       if (index >= RNDIS_WLAN_NUM_KEYS)
+               return -ENOENT;
+
        if (priv->encr_keys[index].len == 0)
                return 0;
 
@@ -1972,11 +1976,12 @@ static int rndis_scan(struct wiphy *wiphy, struct net_device *dev,
        return ret;
 }
 
-static struct cfg80211_bss *rndis_bss_info_update(struct usbnet *usbdev,
-                                       struct ndis_80211_bssid_ex *bssid)
+static bool rndis_bss_info_update(struct usbnet *usbdev,
+                                 struct ndis_80211_bssid_ex *bssid)
 {
        struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
        struct ieee80211_channel *channel;
+       struct cfg80211_bss *bss;
        s32 signal;
        u64 timestamp;
        u16 capability;
@@ -2015,9 +2020,12 @@ static struct cfg80211_bss *rndis_bss_info_update(struct usbnet *usbdev,
        capability = le16_to_cpu(fixed->capabilities);
        beacon_interval = le16_to_cpu(fixed->beacon_interval);
 
-       return cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid->mac,
+       bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid->mac,
                timestamp, capability, beacon_interval, ie, ie_len, signal,
                GFP_KERNEL);
+       cfg80211_put_bss(bss);
+
+       return (bss != NULL);
 }
 
 static struct ndis_80211_bssid_ex *next_bssid_list_item(
@@ -2451,6 +2459,9 @@ static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
 
        netdev_dbg(usbdev->net, "%s(%i)\n", __func__, key_index);
 
+       if (key_index >= RNDIS_WLAN_NUM_KEYS)
+               return -ENOENT;
+
        priv->encr_tx_key_index = key_index;
 
        if (is_wpa_key(priv, key_index))
@@ -2641,6 +2652,7 @@ static void rndis_wlan_craft_connected_bss(struct usbnet *usbdev, u8 *bssid,
        struct ieee80211_channel *channel;
        struct ndis_80211_conf config;
        struct ndis_80211_ssid ssid;
+       struct cfg80211_bss *bss;
        s32 signal;
        u64 timestamp;
        u16 capability;
@@ -2714,9 +2726,10 @@ static void rndis_wlan_craft_connected_bss(struct usbnet *usbdev, u8 *bssid,
                bssid, (u32)timestamp, capability, beacon_interval, ie_len,
                ssid.essid, signal);
 
-       cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid,
+       bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid,
                timestamp, capability, beacon_interval, ie_buf, ie_len,
                signal, GFP_KERNEL);
+       cfg80211_put_bss(bss);
 }
 
 /*
index f156579..3778763 100644 (file)
@@ -919,6 +919,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x050d, 0x935b) },
        /* Buffalo */
        { USB_DEVICE(0x0411, 0x00e8) },
+       { USB_DEVICE(0x0411, 0x0158) },
        { USB_DEVICE(0x0411, 0x016f) },
        { USB_DEVICE(0x0411, 0x01a2) },
        /* Corega */
index 2ec5c00..99ff12d 100644 (file)
@@ -943,6 +943,7 @@ struct rt2x00_dev {
         * Powersaving work
         */
        struct delayed_work autowakeup_work;
+       struct work_struct sleep_work;
 
        /*
         * Data queue arrays for RX, TX, Beacon and ATIM.
index e1fb2a8..edd317f 100644 (file)
@@ -465,6 +465,23 @@ static u8 *rt2x00lib_find_ie(u8 *data, unsigned int len, u8 ie)
        return NULL;
 }
 
+static void rt2x00lib_sleep(struct work_struct *work)
+{
+       struct rt2x00_dev *rt2x00dev =
+           container_of(work, struct rt2x00_dev, sleep_work);
+
+       if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
+               return;
+
+       /*
+        * Check again is powersaving is enabled, to prevent races from delayed
+        * work execution.
+        */
+       if (!test_bit(CONFIG_POWERSAVING, &rt2x00dev->flags))
+               rt2x00lib_config(rt2x00dev, &rt2x00dev->hw->conf,
+                                IEEE80211_CONF_CHANGE_PS);
+}
+
 static void rt2x00lib_rxdone_check_ps(struct rt2x00_dev *rt2x00dev,
                                      struct sk_buff *skb,
                                      struct rxdone_entry_desc *rxdesc)
@@ -512,8 +529,7 @@ static void rt2x00lib_rxdone_check_ps(struct rt2x00_dev *rt2x00dev,
        cam |= (tim_ie->bitmap_ctrl & 0x01);
 
        if (!cam && !test_bit(CONFIG_POWERSAVING, &rt2x00dev->flags))
-               rt2x00lib_config(rt2x00dev, &rt2x00dev->hw->conf,
-                                IEEE80211_CONF_CHANGE_PS);
+               queue_work(rt2x00dev->workqueue, &rt2x00dev->sleep_work);
 }
 
 static int rt2x00lib_rxdone_read_signal(struct rt2x00_dev *rt2x00dev,
@@ -1141,6 +1157,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
 
        INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled);
        INIT_DELAYED_WORK(&rt2x00dev->autowakeup_work, rt2x00lib_autowakeup);
+       INIT_WORK(&rt2x00dev->sleep_work, rt2x00lib_sleep);
 
        /*
         * Let the driver probe the device to detect the capabilities.
@@ -1197,6 +1214,7 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
         */
        cancel_work_sync(&rt2x00dev->intf_work);
        cancel_delayed_work_sync(&rt2x00dev->autowakeup_work);
+       cancel_work_sync(&rt2x00dev->sleep_work);
        if (rt2x00_is_usb(rt2x00dev)) {
                del_timer_sync(&rt2x00dev->txstatus_timer);
                cancel_work_sync(&rt2x00dev->rxdone_work);
index c244f2f..94a3e17 100644 (file)
@@ -275,6 +275,8 @@ static struct usb_device_id rtl8192c_usb_ids[] = {
        {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8191, rtl92cu_hal_cfg)},
 
        /****** 8188CU ********/
+       /* RTL8188CTV */
+       {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x018a, rtl92cu_hal_cfg)},
        /* 8188CE-VAU USB minCard */
        {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8170, rtl92cu_hal_cfg)},
        /* 8188cu 1*1 dongle */
@@ -291,14 +293,14 @@ static struct usb_device_id rtl8192c_usb_ids[] = {
        {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817e, rtl92cu_hal_cfg)},
        /* 8188RU in Alfa AWUS036NHR */
        {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817f, rtl92cu_hal_cfg)},
+       /* RTL8188CUS-VL */
+       {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x818a, rtl92cu_hal_cfg)},
        /* 8188 Combo for BC4 */
        {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8754, rtl92cu_hal_cfg)},
 
        /****** 8192CU ********/
-       /* 8191cu 1*2 */
-       {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8177, rtl92cu_hal_cfg)},
        /* 8192cu 2*2 */
-       {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817b, rtl92cu_hal_cfg)},
+       {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8178, rtl92cu_hal_cfg)},
        /* 8192CE-VAU USB minCard */
        {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817c, rtl92cu_hal_cfg)},
 
@@ -309,13 +311,17 @@ static struct usb_device_id rtl8192c_usb_ids[] = {
        {RTL_USB_DEVICE(0x07b8, 0x8188, rtl92cu_hal_cfg)}, /*Abocom - Abocom*/
        {RTL_USB_DEVICE(0x07b8, 0x8189, rtl92cu_hal_cfg)}, /*Funai - Abocom*/
        {RTL_USB_DEVICE(0x0846, 0x9041, rtl92cu_hal_cfg)}, /*NetGear WNA1000M*/
-       {RTL_USB_DEVICE(0x0Df6, 0x0052, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/
+       {RTL_USB_DEVICE(0x0df6, 0x0052, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/
+       {RTL_USB_DEVICE(0x0df6, 0x005c, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/
        {RTL_USB_DEVICE(0x0eb0, 0x9071, rtl92cu_hal_cfg)}, /*NO Brand - Etop*/
        /* HP - Lite-On ,8188CUS Slim Combo */
        {RTL_USB_DEVICE(0x103c, 0x1629, rtl92cu_hal_cfg)},
        {RTL_USB_DEVICE(0x13d3, 0x3357, rtl92cu_hal_cfg)}, /* AzureWave */
        {RTL_USB_DEVICE(0x2001, 0x3308, rtl92cu_hal_cfg)}, /*D-Link - Alpha*/
+       {RTL_USB_DEVICE(0x2019, 0x4902, rtl92cu_hal_cfg)}, /*Planex - Etop*/
        {RTL_USB_DEVICE(0x2019, 0xab2a, rtl92cu_hal_cfg)}, /*Planex - Abocom*/
+       /*SW-WF02-AD15 -Abocom*/
+       {RTL_USB_DEVICE(0x2019, 0xab2e, rtl92cu_hal_cfg)},
        {RTL_USB_DEVICE(0x2019, 0xed17, rtl92cu_hal_cfg)}, /*PCI - Edimax*/
        {RTL_USB_DEVICE(0x20f4, 0x648b, rtl92cu_hal_cfg)}, /*TRENDnet - Cameo*/
        {RTL_USB_DEVICE(0x7392, 0x7811, rtl92cu_hal_cfg)}, /*Edimax - Edimax*/
@@ -326,14 +332,36 @@ static struct usb_device_id rtl8192c_usb_ids[] = {
        {RTL_USB_DEVICE(0x4855, 0x0091, rtl92cu_hal_cfg)}, /* NetweeN-Feixun */
        {RTL_USB_DEVICE(0x9846, 0x9041, rtl92cu_hal_cfg)}, /* Netgear Cameo */
 
+       /****** 8188 RU ********/
+       /* Netcore */
+       {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x317f, rtl92cu_hal_cfg)},
+
+       /****** 8188CUS Slim Solo********/
+       {RTL_USB_DEVICE(0x04f2, 0xaff7, rtl92cu_hal_cfg)}, /*Xavi*/
+       {RTL_USB_DEVICE(0x04f2, 0xaff9, rtl92cu_hal_cfg)}, /*Xavi*/
+       {RTL_USB_DEVICE(0x04f2, 0xaffa, rtl92cu_hal_cfg)}, /*Xavi*/
+
+       /****** 8188CUS Slim Combo ********/
+       {RTL_USB_DEVICE(0x04f2, 0xaff8, rtl92cu_hal_cfg)}, /*Xavi*/
+       {RTL_USB_DEVICE(0x04f2, 0xaffb, rtl92cu_hal_cfg)}, /*Xavi*/
+       {RTL_USB_DEVICE(0x04f2, 0xaffc, rtl92cu_hal_cfg)}, /*Xavi*/
+       {RTL_USB_DEVICE(0x2019, 0x1201, rtl92cu_hal_cfg)}, /*Planex-Vencer*/
+
        /****** 8192CU ********/
+       {RTL_USB_DEVICE(0x050d, 0x2102, rtl92cu_hal_cfg)}, /*Belcom-Sercomm*/
+       {RTL_USB_DEVICE(0x050d, 0x2103, rtl92cu_hal_cfg)}, /*Belcom-Edimax*/
        {RTL_USB_DEVICE(0x0586, 0x341f, rtl92cu_hal_cfg)}, /*Zyxel -Abocom*/
        {RTL_USB_DEVICE(0x07aa, 0x0056, rtl92cu_hal_cfg)}, /*ATKK-Gemtek*/
        {RTL_USB_DEVICE(0x07b8, 0x8178, rtl92cu_hal_cfg)}, /*Funai -Abocom*/
+       {RTL_USB_DEVICE(0x0846, 0x9021, rtl92cu_hal_cfg)}, /*Netgear-Sercomm*/
+       {RTL_USB_DEVICE(0x0b05, 0x17ab, rtl92cu_hal_cfg)}, /*ASUS-Edimax*/
+       {RTL_USB_DEVICE(0x0df6, 0x0061, rtl92cu_hal_cfg)}, /*Sitecom-Edimax*/
+       {RTL_USB_DEVICE(0x0e66, 0x0019, rtl92cu_hal_cfg)}, /*Hawking-Edimax*/
        {RTL_USB_DEVICE(0x2001, 0x3307, rtl92cu_hal_cfg)}, /*D-Link-Cameo*/
        {RTL_USB_DEVICE(0x2001, 0x3309, rtl92cu_hal_cfg)}, /*D-Link-Alpha*/
        {RTL_USB_DEVICE(0x2001, 0x330a, rtl92cu_hal_cfg)}, /*D-Link-Alpha*/
        {RTL_USB_DEVICE(0x2019, 0xab2b, rtl92cu_hal_cfg)}, /*Planex -Abocom*/
+       {RTL_USB_DEVICE(0x20f4, 0x624d, rtl92cu_hal_cfg)}, /*TRENDNet*/
        {RTL_USB_DEVICE(0x7392, 0x7822, rtl92cu_hal_cfg)}, /*Edimax -Edimax*/
        {}
 };
index 128ccb7..fc29c67 100644 (file)
@@ -559,7 +559,7 @@ wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl,
                                                break;
                                        }
                                /* Fail if SSID isn't present in the filters */
-                               if (j == req->n_ssids) {
+                               if (j == cmd->n_ssids) {
                                        ret = -EINVAL;
                                        goto out_free;
                                }
index 1825629..0b5c18f 100644 (file)
@@ -165,7 +165,8 @@ static int xenvif_change_mtu(struct net_device *dev, int mtu)
        return 0;
 }
 
-static u32 xenvif_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t xenvif_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        struct xenvif *vif = netdev_priv(dev);
 
index 226faab..4312db8 100644 (file)
@@ -201,7 +201,7 @@ static void xennet_sysfs_delif(struct net_device *netdev);
 #define xennet_sysfs_delif(dev) do { } while (0)
 #endif
 
-static int xennet_can_sg(struct net_device *dev)
+static bool xennet_can_sg(struct net_device *dev)
 {
        return dev->features & NETIF_F_SG;
 }
@@ -1190,7 +1190,8 @@ static void xennet_uninit(struct net_device *dev)
        gnttab_free_grant_references(np->gref_rx_head);
 }
 
-static u32 xennet_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t xennet_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        struct netfront_info *np = netdev_priv(dev);
        int val;
@@ -1216,7 +1217,8 @@ static u32 xennet_fix_features(struct net_device *dev, u32 features)
        return features;
 }
 
-static int xennet_set_features(struct net_device *dev, u32 features)
+static int xennet_set_features(struct net_device *dev,
+       netdev_features_t features)
 {
        if (!(features & NETIF_F_SG) && dev->mtu > ETH_DATA_LEN) {
                netdev_info(dev, "Reducing MTU because no SG offload");
index ef56644..e17e2f8 100644 (file)
@@ -2,23 +2,17 @@
 # PINCTRL infrastructure and drivers
 #
 
-menuconfig PINCTRL
-       bool "PINCTRL Support"
+config PINCTRL
+       bool
        depends on EXPERIMENTAL
-       help
-         This enables the PINCTRL subsystem for controlling pins
-         on chip packages, for example multiplexing pins on primarily
-         PGA and BGA packages for systems on chip.
-
-         If unsure, say N.
 
 if PINCTRL
 
+menu "Pin controllers"
+       depends on PINCTRL
+
 config PINMUX
        bool "Support pinmux controllers"
-       help
-         Say Y here if you want the pincontrol subsystem to handle pin
-         multiplexing drivers.
 
 config DEBUG_PINCTRL
        bool "Debug PINCTRL calls"
@@ -30,14 +24,12 @@ config PINMUX_SIRF
        bool "CSR SiRFprimaII pinmux driver"
        depends on ARCH_PRIMA2
        select PINMUX
-       help
-         Say Y here to enable the SiRFprimaII pinmux driver
 
 config PINMUX_U300
        bool "U300 pinmux driver"
        depends on ARCH_U300
        select PINMUX
-       help
-         Say Y here to enable the U300 pinmux driver
+
+endmenu
 
 endif
index f4e3d82..7f43cf8 100644 (file)
@@ -83,8 +83,10 @@ config DELL_LAPTOP
        depends on EXPERIMENTAL
        depends on BACKLIGHT_CLASS_DEVICE
        depends on RFKILL || RFKILL = n
-       depends on POWER_SUPPLY
        depends on SERIO_I8042
+       select POWER_SUPPLY
+       select LEDS_CLASS
+       select NEW_LEDS
        default n
        ---help---
        This driver adds support for rfkill and backlight control to Dell
index a43cfd9..d93e962 100644 (file)
@@ -589,14 +589,14 @@ static const struct backlight_ops dell_ops = {
        .update_status  = dell_send_intensity,
 };
 
-static void touchpad_led_on()
+static void touchpad_led_on(void)
 {
        int command = 0x97;
        char data = 1;
        i8042_command(&data, command | 1 << 12);
 }
 
-static void touchpad_led_off()
+static void touchpad_led_off(void)
 {
        int command = 0x97;
        char data = 2;
index d9fb729..fb73008 100644 (file)
@@ -952,7 +952,7 @@ static int ps3_vuart_bus_interrupt_get(void)
        }
 
        result = request_irq(vuart_bus_priv.virq, ps3_vuart_irq_handler,
-               IRQF_DISABLED, "vuart", &vuart_bus_priv);
+               0, "vuart", &vuart_bus_priv);
 
        if (result) {
                pr_debug("%s:%d: request_irq failed (%d)\n",
index cc328de..8c3f5ad 100644 (file)
@@ -167,7 +167,7 @@ int ps3stor_setup(struct ps3_storage_device *dev, irq_handler_t handler)
                goto fail_close_device;
        }
 
-       error = request_irq(dev->irq, handler, IRQF_DISABLED,
+       error = request_irq(dev->irq, handler, 0,
                            dev->sbd.core.driver->name, dev);
        if (error) {
                dev_err(&dev->sbd.core, "%s:%u: request_irq failed %d\n",
index d335448..bb21f44 100644 (file)
@@ -76,12 +76,15 @@ static inline unsigned char vrtc_is_updating(void)
 /*
  * rtc_time's year contains the increment over 1900, but vRTC's YEAR
  * register can't be programmed to value larger than 0x64, so vRTC
- * driver chose to use 1960 (1970 is UNIX time start point) as the base,
+ * driver chose to use 1972 (1970 is UNIX time start point) as the base,
  * and does the translation at read/write time.
  *
- * Why not just use 1970 as the offset? it's because using 1960 will
+ * Why not just use 1970 as the offset? it's because using 1972 will
  * make it consistent in leap year setting for both vrtc and low-level
- * physical rtc devices.
+ * physical rtc devices. Then why not use 1960 as the offset? If we use
+ * 1960, for a device's first use, its YEAR register is 0 and the system
+ * year will be parsed as 1960 which is not a valid UNIX time and will
+ * cause many applications to fail mysteriously.
  */
 static int mrst_read_time(struct device *dev, struct rtc_time *time)
 {
@@ -99,10 +102,10 @@ static int mrst_read_time(struct device *dev, struct rtc_time *time)
        time->tm_year = vrtc_cmos_read(RTC_YEAR);
        spin_unlock_irqrestore(&rtc_lock, flags);
 
-       /* Adjust for the 1960/1900 */
-       time->tm_year += 60;
+       /* Adjust for the 1972/1900 */
+       time->tm_year += 72;
        time->tm_mon--;
-       return RTC_24H;
+       return rtc_valid_tm(time);
 }
 
 static int mrst_set_time(struct device *dev, struct rtc_time *time)
@@ -119,9 +122,9 @@ static int mrst_set_time(struct device *dev, struct rtc_time *time)
        min = time->tm_min;
        sec = time->tm_sec;
 
-       if (yrs < 70 || yrs > 138)
+       if (yrs < 72 || yrs > 138)
                return -EINVAL;
-       yrs -= 60;
+       yrs -= 72;
 
        spin_lock_irqsave(&rtc_lock, flags);
 
index b3eba3c..e4b6880 100644 (file)
@@ -220,7 +220,7 @@ static void puv3_rtc_enable(struct platform_device *pdev, int en)
        }
 }
 
-static int puv3_rtc_remove(struct platform_device *dev)
+static int __devexit puv3_rtc_remove(struct platform_device *dev)
 {
        struct rtc_device *rtc = platform_get_drvdata(dev);
 
@@ -236,7 +236,7 @@ static int puv3_rtc_remove(struct platform_device *dev)
        return 0;
 }
 
-static int puv3_rtc_probe(struct platform_device *pdev)
+static int __devinit puv3_rtc_probe(struct platform_device *pdev)
 {
        struct rtc_device *rtc;
        struct resource *res;
index 43068fb..1b6d924 100644 (file)
@@ -641,6 +641,8 @@ static int __init zcore_init(void)
 
        if (ipl_info.type != IPL_TYPE_FCP_DUMP)
                return -ENODATA;
+       if (OLDMEM_BASE)
+               return -ENODATA;
 
        zcore_dbf = debug_register("zcore", 4, 1, 4 * sizeof(long));
        debug_register_view(zcore_dbf, &debug_sprintf_view);
index b77ae51..ec94f04 100644 (file)
@@ -1271,18 +1271,16 @@ ap_config_timeout(unsigned long ptr)
 }
 
 /**
- * ap_schedule_poll_timer(): Schedule poll timer.
+ * __ap_schedule_poll_timer(): Schedule poll timer.
  *
  * Set up the timer to run the poll tasklet
  */
-static inline void ap_schedule_poll_timer(void)
+static inline void __ap_schedule_poll_timer(void)
 {
        ktime_t hr_time;
 
        spin_lock_bh(&ap_poll_timer_lock);
-       if (ap_using_interrupts() || ap_suspend_flag)
-               goto out;
-       if (hrtimer_is_queued(&ap_poll_timer))
+       if (hrtimer_is_queued(&ap_poll_timer) || ap_suspend_flag)
                goto out;
        if (ktime_to_ns(hrtimer_expires_remaining(&ap_poll_timer)) <= 0) {
                hr_time = ktime_set(0, poll_timeout);
@@ -1294,6 +1292,18 @@ out:
 }
 
 /**
+ * ap_schedule_poll_timer(): Schedule poll timer.
+ *
+ * Set up the timer to run the poll tasklet
+ */
+static inline void ap_schedule_poll_timer(void)
+{
+       if (ap_using_interrupts())
+               return;
+       __ap_schedule_poll_timer();
+}
+
+/**
  * ap_poll_read(): Receive pending reply messages from an AP device.
  * @ap_dev: pointer to the AP device
  * @flags: pointer to control flags, bit 2^0 is set if another poll is
@@ -1374,8 +1384,9 @@ static int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags)
                        *flags |= 1;
                *flags |= 2;
                break;
-       case AP_RESPONSE_Q_FULL:
        case AP_RESPONSE_RESET_IN_PROGRESS:
+               __ap_schedule_poll_timer();
+       case AP_RESPONSE_Q_FULL:
                *flags |= 2;
                break;
        case AP_RESPONSE_MESSAGE_TOO_BIG:
index 94f49ff..8af868b 100644 (file)
@@ -263,6 +263,11 @@ error:
        return PTR_ERR(vqs[i]);
 }
 
+static const char *kvm_bus_name(struct virtio_device *vdev)
+{
+       return "";
+}
+
 /*
  * The config ops structure as defined by virtio config
  */
@@ -276,6 +281,7 @@ static struct virtio_config_ops kvm_vq_configspace_ops = {
        .reset = kvm_reset,
        .find_vqs = kvm_find_vqs,
        .del_vqs = kvm_del_vqs,
+       .bus_name = kvm_bus_name,
 };
 
 /*
index fa80ba1..9b66d2d 100644 (file)
@@ -4,7 +4,7 @@ menu "S/390 network device drivers"
 config LCS
        def_tristate m
        prompt "Lan Channel Station Interface"
-       depends on CCW && NETDEVICES && (NET_ETHERNET || TR || FDDI)
+       depends on CCW && NETDEVICES && (ETHERNET || TR || FDDI)
        help
           Select this option if you want to use LCS networking on IBM System z.
           This device driver supports Token Ring (IEEE 802.5),
index c28713d..863fc21 100644 (file)
@@ -50,7 +50,7 @@
 #include "lcs.h"
 
 
-#if !defined(CONFIG_NET_ETHERNET) && \
+#if !defined(CONFIG_ETHERNET) && \
     !defined(CONFIG_TR) && !defined(CONFIG_FDDI)
 #error Cannot compile lcs.c without some net devices switched on.
 #endif
@@ -1634,7 +1634,7 @@ lcs_startlan_auto(struct lcs_card *card)
        int rc;
 
        LCS_DBF_TEXT(2, trace, "strtauto");
-#ifdef CONFIG_NET_ETHERNET
+#ifdef CONFIG_ETHERNET
        card->lan_type = LCS_FRAME_TYPE_ENET;
        rc = lcs_send_startlan(card, LCS_INITIATOR_TCPIP);
        if (rc == 0)
@@ -2166,7 +2166,7 @@ lcs_new_device(struct ccwgroup_device *ccwgdev)
                goto netdev_out;
        }
        switch (card->lan_type) {
-#ifdef CONFIG_NET_ETHERNET
+#ifdef CONFIG_ETHERNET
        case LCS_FRAME_TYPE_ENET:
                card->lan_type_trans = eth_type_trans;
                dev = alloc_etherdev(0);
index 3251333..b6a6356 100644 (file)
@@ -1994,6 +1994,8 @@ static struct net_device *netiucv_init_netdevice(char *username)
                           netiucv_setup_netdevice);
        if (!dev)
                return NULL;
+       if (dev_alloc_name(dev, dev->name) < 0)
+               goto out_netdev;
 
        privptr = netdev_priv(dev);
        privptr->fsm = init_fsm("netiucvdev", dev_state_names,
index b77c65e..4abc79d 100644 (file)
@@ -236,8 +236,7 @@ static inline int qeth_is_ipa_enabled(struct qeth_ipa_info *ipa,
 #define QETH_IN_BUF_COUNT_MAX 128
 #define QETH_MAX_BUFFER_ELEMENTS(card) ((card)->qdio.in_buf_size >> 12)
 #define QETH_IN_BUF_REQUEUE_THRESHOLD(card) \
-               ((card)->ssqd.qdioac1 & AC1_SIGA_INPUT_NEEDED ? 1 : \
-                ((card)->qdio.in_buf_pool.buf_count / 2))
+                ((card)->qdio.in_buf_pool.buf_count / 2)
 
 /* buffers we have to be behind before we get a PCI */
 #define QETH_PCI_THRESHOLD_A(card) ((card)->qdio.in_buf_pool.buf_count+1)
index 8153443..fff57de 100644 (file)
@@ -881,7 +881,6 @@ EXPORT_SYMBOL_GPL(qeth_do_run_thread);
 void qeth_schedule_recovery(struct qeth_card *card)
 {
        QETH_CARD_TEXT(card, 2, "startrec");
-       WARN_ON(1);
        if (qeth_set_thread_start_bit(card, QETH_RECOVER_THREAD) == 0)
                schedule_work(&card->kernel_thread_starter);
 }
index e4c1176..6357892 100644 (file)
@@ -2756,11 +2756,13 @@ int inline qeth_l3_get_cast_type(struct qeth_card *card, struct sk_buff *skb)
        struct neighbour *n = NULL;
        struct dst_entry *dst;
 
+       rcu_read_lock();
        dst = skb_dst(skb);
        if (dst)
                n = dst_get_neighbour(dst);
        if (n) {
                cast_type = n->type;
+               rcu_read_unlock();
                if ((cast_type == RTN_BROADCAST) ||
                    (cast_type == RTN_MULTICAST) ||
                    (cast_type == RTN_ANYCAST))
@@ -2768,6 +2770,8 @@ int inline qeth_l3_get_cast_type(struct qeth_card *card, struct sk_buff *skb)
                else
                        return RTN_UNSPEC;
        }
+       rcu_read_unlock();
+
        /* try something else */
        if (skb->protocol == ETH_P_IPV6)
                return (skb_network_header(skb)[24] == 0xff) ?
@@ -2847,6 +2851,8 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
        }
 
        hdr->hdr.l3.length = skb->len - sizeof(struct qeth_hdr);
+
+       rcu_read_lock();
        dst = skb_dst(skb);
        if (dst)
                n = dst_get_neighbour(dst);
@@ -2893,6 +2899,7 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
                                QETH_CAST_UNICAST | QETH_HDR_PASSTHRU;
                }
        }
+       rcu_read_unlock();
 }
 
 static inline void qeth_l3_hdr_csum(struct qeth_card *card,
@@ -3202,7 +3209,8 @@ static int qeth_l3_stop(struct net_device *dev)
        return 0;
 }
 
-static u32 qeth_l3_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t qeth_l3_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        struct qeth_card *card = dev->ml_priv;
 
@@ -3216,7 +3224,8 @@ static u32 qeth_l3_fix_features(struct net_device *dev, u32 features)
        return features;
 }
 
-static int qeth_l3_set_features(struct net_device *dev, u32 features)
+static int qeth_l3_set_features(struct net_device *dev,
+       netdev_features_t features)
 {
        struct qeth_card *card = dev->ml_priv;
        u32 changed = dev->features ^ features;
index 0ea2fbf..d979bb2 100644 (file)
@@ -335,10 +335,10 @@ static ssize_t qeth_l3_dev_sniffer_store(struct device *dev,
                                        QETH_IN_BUF_COUNT_MAX)
                                qeth_realloc_buffer_pool(card,
                                        QETH_IN_BUF_COUNT_MAX);
-                       break;
                } else
                        rc = -EPERM;
-       default:   /* fall through */
+               break;
+       default:
                rc = -EINVAL;
        }
 out:
index 4aa76d6..705e13e 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/pci.h>
+#include <linux/pci-aspm.h>
 #include <linux/slab.h>
 #include <linux/mutex.h>
 #include <linux/spinlock.h>
@@ -1109,6 +1110,9 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
                unique_id++;
        }
 
+       pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |
+                              PCIE_LINK_STATE_CLKPM);
+
        error = pci_enable_device(pdev);
        if (error)
                goto out;
index e76107b..865d452 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/interrupt.h>
 #include <linux/types.h>
 #include <linux/pci.h>
+#include <linux/pci-aspm.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
@@ -3922,6 +3923,10 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h)
                dev_warn(&h->pdev->dev, "controller appears to be disabled\n");
                return -ENODEV;
        }
+
+       pci_disable_link_state(h->pdev, PCIE_LINK_STATE_L0S |
+                              PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_CLKPM);
+
        err = pci_enable_device(h->pdev);
        if (err) {
                dev_warn(&h->pdev->dev, "unable to enable PCI device\n");
index 8889b1b..4e041f6 100644 (file)
@@ -2802,6 +2802,11 @@ _scsih_error_recovery_delete_devices(struct MPT2SAS_ADAPTER *ioc)
 
        if (ioc->is_driver_loading)
                return;
+
+       fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
+       if (!fw_event)
+               return;
+
        fw_event->event = MPT2SAS_REMOVE_UNRESPONDING_DEVICES;
        fw_event->ioc = ioc;
        _scsih_fw_event_add(ioc, fw_event);
index 06bc265..f85cfa6 100644 (file)
@@ -1409,6 +1409,8 @@ static void scsi_kill_request(struct request *req, struct request_queue *q)
 
        blk_start_request(req);
 
+       scmd_printk(KERN_INFO, cmd, "killing request\n");
+
        sdev = cmd->device;
        starget = scsi_target(sdev);
        shost = sdev->host;
@@ -1490,7 +1492,6 @@ static void scsi_request_fn(struct request_queue *q)
        struct request *req;
 
        if (!sdev) {
-               printk("scsi: killing requests for dead queue\n");
                while ((req = blk_peek_request(q)) != NULL)
                        scsi_kill_request(req, q);
                return;
index 72273a0..b3c6d95 100644 (file)
@@ -319,11 +319,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
        return sdev;
 
 out_device_destroy:
-       scsi_device_set_state(sdev, SDEV_DEL);
-       transport_destroy_device(&sdev->sdev_gendev);
-       put_device(&sdev->sdev_dev);
-       scsi_free_queue(sdev->request_queue);
-       put_device(&sdev->sdev_gendev);
+       __scsi_remove_device(sdev);
 out:
        if (display_failure_msg)
                printk(ALLOC_FAILURE_MSG, __func__);
index 24e6cec..67e272a 100644 (file)
@@ -7,3 +7,11 @@ obj-$(CONFIG_HAVE_CLK)         += clk/
 obj-$(CONFIG_MAPLE)            += maple/
 obj-$(CONFIG_SUPERHYWAY)       += superhyway/
 obj-$(CONFIG_GENERIC_GPIO)     += pfc.o
+
+#
+# For the moment we only use this framework for ARM-based SH/R-Mobile
+# platforms and generic SH. SH-based SH-Mobile platforms are still using
+# an older framework that is pending up-porting, at which point this
+# special casing can go away.
+#
+obj-$(CONFIG_SUPERH)$(CONFIG_ARCH_SHMOBILE)    += pm_runtime.o
index dc8d022..db257a3 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/seq_file.h>
 #include <linux/err.h>
 #include <linux/io.h>
-#include <linux/debugfs.h>
 #include <linux/cpufreq.h>
 #include <linux/clk.h>
 #include <linux/sh_clk.h>
@@ -173,6 +172,26 @@ long clk_rate_div_range_round(struct clk *clk, unsigned int div_min,
        return clk_rate_round_helper(&div_range_round);
 }
 
+static long clk_rate_mult_range_iter(unsigned int pos,
+                                     struct clk_rate_round_data *rounder)
+{
+       return clk_get_rate(rounder->arg) * pos;
+}
+
+long clk_rate_mult_range_round(struct clk *clk, unsigned int mult_min,
+                              unsigned int mult_max, unsigned long rate)
+{
+       struct clk_rate_round_data mult_range_round = {
+               .min    = mult_min,
+               .max    = mult_max,
+               .func   = clk_rate_mult_range_iter,
+               .arg    = clk_get_parent(clk),
+               .rate   = rate,
+       };
+
+       return clk_rate_round_helper(&mult_range_round);
+}
+
 int clk_rate_table_find(struct clk *clk,
                        struct cpufreq_frequency_table *freq_table,
                        unsigned long rate)
@@ -205,9 +224,6 @@ int clk_reparent(struct clk *child, struct clk *parent)
                list_add(&child->sibling, &parent->children);
        child->parent = parent;
 
-       /* now do the debugfs renaming to reattach the child
-          to the proper parent */
-
        return 0;
 }
 
@@ -665,89 +681,6 @@ static int __init clk_syscore_init(void)
 subsys_initcall(clk_syscore_init);
 #endif
 
-/*
- *     debugfs support to trace clock tree hierarchy and attributes
- */
-static struct dentry *clk_debugfs_root;
-
-static int clk_debugfs_register_one(struct clk *c)
-{
-       int err;
-       struct dentry *d;
-       struct clk *pa = c->parent;
-       char s[255];
-       char *p = s;
-
-       p += sprintf(p, "%p", c);
-       d = debugfs_create_dir(s, pa ? pa->dentry : clk_debugfs_root);
-       if (!d)
-               return -ENOMEM;
-       c->dentry = d;
-
-       d = debugfs_create_u8("usecount", S_IRUGO, c->dentry, (u8 *)&c->usecount);
-       if (!d) {
-               err = -ENOMEM;
-               goto err_out;
-       }
-       d = debugfs_create_u32("rate", S_IRUGO, c->dentry, (u32 *)&c->rate);
-       if (!d) {
-               err = -ENOMEM;
-               goto err_out;
-       }
-       d = debugfs_create_x32("flags", S_IRUGO, c->dentry, (u32 *)&c->flags);
-       if (!d) {
-               err = -ENOMEM;
-               goto err_out;
-       }
-       return 0;
-
-err_out:
-       debugfs_remove_recursive(c->dentry);
-       return err;
-}
-
-static int clk_debugfs_register(struct clk *c)
-{
-       int err;
-       struct clk *pa = c->parent;
-
-       if (pa && !pa->dentry) {
-               err = clk_debugfs_register(pa);
-               if (err)
-                       return err;
-       }
-
-       if (!c->dentry) {
-               err = clk_debugfs_register_one(c);
-               if (err)
-                       return err;
-       }
-       return 0;
-}
-
-static int __init clk_debugfs_init(void)
-{
-       struct clk *c;
-       struct dentry *d;
-       int err;
-
-       d = debugfs_create_dir("clock", NULL);
-       if (!d)
-               return -ENOMEM;
-       clk_debugfs_root = d;
-
-       list_for_each_entry(c, &clock_list, node) {
-               err = clk_debugfs_register(c);
-               if (err)
-                       goto err_out;
-       }
-       return 0;
-err_out:
-       debugfs_remove_recursive(clk_debugfs_root);
-       return err;
-}
-late_initcall(clk_debugfs_init);
-
 static int __init clk_late_init(void)
 {
        unsigned long flags;
similarity index 94%
rename from arch/arm/mach-shmobile/pm_runtime.c
rename to drivers/sh/pm_runtime.c
index bd5c6a3..afe9282 100644 (file)
@@ -1,7 +1,5 @@
 /*
- * arch/arm/mach-shmobile/pm_runtime.c
- *
- * Runtime PM support code for SuperH Mobile ARM
+ * Runtime PM support code
  *
  *  Copyright (C) 2009-2010 Magnus Damm
  *
index 79665e2..16d6a83 100644 (file)
@@ -907,7 +907,7 @@ static void atmel_spi_cleanup(struct spi_device *spi)
 
 /*-------------------------------------------------------------------------*/
 
-static int __init atmel_spi_probe(struct platform_device *pdev)
+static int __devinit atmel_spi_probe(struct platform_device *pdev)
 {
        struct resource         *regs;
        int                     irq;
@@ -1003,7 +1003,7 @@ out_free:
        return ret;
 }
 
-static int __exit atmel_spi_remove(struct platform_device *pdev)
+static int __devexit atmel_spi_remove(struct platform_device *pdev)
 {
        struct spi_master       *master = platform_get_drvdata(pdev);
        struct atmel_spi        *as = spi_master_get_devdata(master);
@@ -1072,6 +1072,7 @@ static struct platform_driver atmel_spi_driver = {
        },
        .suspend        = atmel_spi_suspend,
        .resume         = atmel_spi_resume,
+       .probe          = atmel_spi_probe,
        .remove         = __exit_p(atmel_spi_remove),
 };
 module_platform_driver(atmel_spi_driver);
index f103e47..5559b22 100644 (file)
@@ -2184,6 +2184,12 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id)
                goto  err_clk_prep;
        }
 
+       status = clk_enable(pl022->clk);
+       if (status) {
+               dev_err(&adev->dev, "could not enable SSP/SPI bus clock\n");
+               goto err_no_clk_en;
+       }
+
        /* Disable SSP */
        writew((readw(SSP_CR1(pl022->virtbase)) & (~SSP_CR1_MASK_SSE)),
               SSP_CR1(pl022->virtbase));
@@ -2237,6 +2243,8 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id)
 
        free_irq(adev->irq[0], pl022);
  err_no_irq:
+       clk_disable(pl022->clk);
+ err_no_clk_en:
        clk_unprepare(pl022->clk);
  err_clk_prep:
        clk_put(pl022->clk);
index d335c7d..828526d 100644 (file)
@@ -32,8 +32,8 @@
 #include "as102_fw.h"
 #include "dvbdev.h"
 
-int debug;
-module_param_named(debug, debug, int, 0644);
+int as102_debug;
+module_param_named(debug, as102_debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off debugging (default: off)");
 
 int dual_tuner;
index bcda635..fd33f5a 100644 (file)
@@ -37,7 +37,8 @@ extern struct spi_driver as102_spi_driver;
 #define DRIVER_FULL_NAME "Abilis Systems as10x usb driver"
 #define DRIVER_NAME "as10x_usb"
 
-extern int debug;
+extern int as102_debug;
+#define debug  as102_debug
 
 #define dprintk(debug, args...) \
        do { if (debug) {       \
index b445cd6..2542c37 100644 (file)
@@ -275,7 +275,7 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev)
                CVM_OCT_SKB_CB(skb)[0] = hw_buffer.u64;
                for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
                        struct skb_frag_struct *fs = skb_shinfo(skb)->frags + i;
-                       hw_buffer.s.addr = XKPHYS_TO_PHYS((u64)(page_address(fs->page) + fs->page_offset));
+                       hw_buffer.s.addr = XKPHYS_TO_PHYS((u64)(page_address(fs->page.p) + fs->page_offset));
                        hw_buffer.s.size = fs->size;
                        CVM_OCT_SKB_CB(skb)[i + 1] = hw_buffer.u64;
                }
index 4cb0d0a..fc7bbba 100644 (file)
 static int debug;
 module_param(debug, int, 0600);
 
-#define T1     (HZ/10)
-#define T2     (HZ/3)
-#define N2     3
+/* Defaults: these are from the specification */
+
+#define T1     10              /* 100mS */
+#define T2     34              /* 333mS */
+#define N2     3               /* Retry 3 times */
 
 /* Use long timers for testing at low speed with debug on */
 #ifdef DEBUG_TIMING
-#define T1     HZ
-#define T2     (2 * HZ)
+#define T1     100
+#define T2     200
 #endif
 
 /*
index 1945c70..aff9d61 100644 (file)
@@ -207,6 +207,25 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
        },
 
        /*
+        * Common SH-2(A) SCIF definitions for ports with FIFO data
+        * count registers.
+        */
+       [SCIx_SH2_SCIF_FIFODATA_REGTYPE] = {
+               [SCSMR]         = { 0x00, 16 },
+               [SCBRR]         = { 0x04,  8 },
+               [SCSCR]         = { 0x08, 16 },
+               [SCxTDR]        = { 0x0c,  8 },
+               [SCxSR]         = { 0x10, 16 },
+               [SCxRDR]        = { 0x14,  8 },
+               [SCFCR]         = { 0x18, 16 },
+               [SCFDR]         = { 0x1c, 16 },
+               [SCTFDR]        = sci_reg_invalid,
+               [SCRFDR]        = sci_reg_invalid,
+               [SCSPTR]        = { 0x20, 16 },
+               [SCLSR]         = { 0x24, 16 },
+       },
+
+       /*
         * Common SH-3 SCIF definitions.
         */
        [SCIx_SH3_SCIF_REGTYPE] = {
index 3490770..7cdcb63 100644 (file)
@@ -298,11 +298,10 @@ static void pn_net_setup(struct net_device *dev)
 static int
 pn_rx_submit(struct f_phonet *fp, struct usb_request *req, gfp_t gfp_flags)
 {
-       struct net_device *dev = fp->dev;
        struct page *page;
        int err;
 
-       page = __netdev_alloc_page(dev, gfp_flags);
+       page = alloc_page(gfp_flags);
        if (!page)
                return -ENOMEM;
 
@@ -312,7 +311,7 @@ pn_rx_submit(struct f_phonet *fp, struct usb_request *req, gfp_t gfp_flags)
 
        err = usb_ep_queue(fp->out_ep, req, gfp_flags);
        if (unlikely(err))
-               netdev_free_page(dev, page);
+               put_page(page);
        return err;
 }
 
@@ -346,7 +345,7 @@ static void pn_rx_complete(struct usb_ep *ep, struct usb_request *req)
                }
 
                skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page,
-                               skb->len == 0, req->actual);
+                               skb->len <= 1, req->actual);
                page = NULL;
 
                if (req->actual < req->length) { /* Last fragment */
@@ -374,9 +373,9 @@ static void pn_rx_complete(struct usb_ep *ep, struct usb_request *req)
        }
 
        if (page)
-               netdev_free_page(dev, page);
+               put_page(page);
        if (req)
-               pn_rx_submit(fp, req, GFP_ATOMIC);
+               pn_rx_submit(fp, req, GFP_ATOMIC | __GFP_COLD);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -436,7 +435,7 @@ static int pn_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 
                        netif_carrier_on(dev);
                        for (i = 0; i < phonet_rxq_size; i++)
-                               pn_rx_submit(fp, fp->out_reqv[i], GFP_ATOMIC);
+                               pn_rx_submit(fp, fp->out_reqv[i], GFP_ATOMIC | __GFP_COLD);
                }
                spin_unlock(&port->lock);
                return 0;
index b2c44e1..d786ba3 100644 (file)
@@ -1717,7 +1717,7 @@ static void dtd_complete_irq(struct fsl_udc *udc)
 
 static inline enum usb_device_speed portscx_device_speed(u32 reg)
 {
-       switch (speed & PORTSCX_PORT_SPEED_MASK) {
+       switch (reg & PORTSCX_PORT_SPEED_MASK) {
        case PORTSCX_PORT_SPEED_HIGH:
                return USB_SPEED_HIGH;
        case PORTSCX_PORT_SPEED_FULL:
index acc5e43..2f57380 100644 (file)
@@ -361,7 +361,12 @@ static int vm_find_vqs(struct virtio_device *vdev, unsigned nvqs,
        return 0;
 }
 
+static const char *vm_bus_name(struct virtio_device *vdev)
+{
+       struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
 
+       return vm_dev->pdev->name;
+}
 
 static struct virtio_config_ops virtio_mmio_config_ops = {
        .get            = vm_get,
@@ -373,6 +378,7 @@ static struct virtio_config_ops virtio_mmio_config_ops = {
        .del_vqs        = vm_del_vqs,
        .get_features   = vm_get_features,
        .finalize_features = vm_finalize_features,
+       .bus_name       = vm_bus_name,
 };
 
 
index 79a31e5..91683e6 100644 (file)
@@ -580,6 +580,13 @@ static int vp_find_vqs(struct virtio_device *vdev, unsigned nvqs,
                                  false, false);
 }
 
+static const char *vp_bus_name(struct virtio_device *vdev)
+{
+       struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+
+       return pci_name(vp_dev->pci_dev);
+}
+
 static struct virtio_config_ops virtio_pci_config_ops = {
        .get            = vp_get,
        .set            = vp_set,
@@ -590,15 +597,16 @@ static struct virtio_config_ops virtio_pci_config_ops = {
        .del_vqs        = vp_del_vqs,
        .get_features   = vp_get_features,
        .finalize_features = vp_finalize_features,
+       .bus_name       = vp_bus_name,
 };
 
 static void virtio_pci_release_dev(struct device *_d)
 {
-       struct virtio_device *dev = container_of(_d, struct virtio_device,
-                                                dev);
-       struct virtio_pci_device *vp_dev = to_vp_device(dev);
-
-       kfree(vp_dev);
+       /*
+        * No need for a release method as we allocate/free
+        * all devices together with the pci devices.
+        * Provide an empty one to avoid getting a warning from core.
+        */
 }
 
 /* the PCI probing function */
@@ -686,6 +694,7 @@ static void __devexit virtio_pci_remove(struct pci_dev *pci_dev)
        pci_iounmap(pci_dev, vp_dev->ioaddr);
        pci_release_regions(pci_dev);
        pci_disable_device(pci_dev);
+       kfree(vp_dev);
 }
 
 #ifdef CONFIG_PM
index a767884..31ab82f 100644 (file)
@@ -501,7 +501,7 @@ EXPORT_SYMBOL_GPL(balloon_set_new_target);
  * alloc_xenballooned_pages - get pages that have been ballooned out
  * @nr_pages: Number of pages to get
  * @pages: pages returned
- * @highmem: highmem or lowmem pages
+ * @highmem: allow highmem pages
  * @return 0 on success, error otherwise
  */
 int alloc_xenballooned_pages(int nr_pages, struct page **pages, bool highmem)
@@ -511,7 +511,7 @@ int alloc_xenballooned_pages(int nr_pages, struct page **pages, bool highmem)
        mutex_lock(&balloon_mutex);
        while (pgno < nr_pages) {
                page = balloon_retrieve(highmem);
-               if (page && PageHighMem(page) == highmem) {
+               if (page && (highmem || !PageHighMem(page))) {
                        pages[pgno++] = page;
                } else {
                        enum bp_state st;
index f6832f4..e1c4c6e 100644 (file)
@@ -135,7 +135,7 @@ static int add_grefs(struct ioctl_gntalloc_alloc_gref *op,
                /* Grant foreign access to the page. */
                gref->gref_id = gnttab_grant_foreign_access(op->domid,
                        pfn_to_mfn(page_to_pfn(gref->page)), readonly);
-               if (gref->gref_id < 0) {
+               if ((int)gref->gref_id < 0) {
                        rc = gref->gref_id;
                        goto undo;
                }
@@ -280,7 +280,7 @@ static long gntalloc_ioctl_alloc(struct gntalloc_file_private_data *priv,
                goto out;
        }
 
-       gref_ids = kzalloc(sizeof(gref_ids[0]) * op.count, GFP_TEMPORARY);
+       gref_ids = kcalloc(op.count, sizeof(gref_ids[0]), GFP_TEMPORARY);
        if (!gref_ids) {
                rc = -ENOMEM;
                goto out;
index 3987132..afca14d 100644 (file)
@@ -114,11 +114,11 @@ static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count)
        if (NULL == add)
                return NULL;
 
-       add->grants    = kzalloc(sizeof(add->grants[0])    * count, GFP_KERNEL);
-       add->map_ops   = kzalloc(sizeof(add->map_ops[0])   * count, GFP_KERNEL);
-       add->unmap_ops = kzalloc(sizeof(add->unmap_ops[0]) * count, GFP_KERNEL);
-       add->kmap_ops  = kzalloc(sizeof(add->kmap_ops[0])  * count, GFP_KERNEL);
-       add->pages     = kzalloc(sizeof(add->pages[0])     * count, GFP_KERNEL);
+       add->grants    = kcalloc(count, sizeof(add->grants[0]), GFP_KERNEL);
+       add->map_ops   = kcalloc(count, sizeof(add->map_ops[0]), GFP_KERNEL);
+       add->unmap_ops = kcalloc(count, sizeof(add->unmap_ops[0]), GFP_KERNEL);
+       add->kmap_ops  = kcalloc(count, sizeof(add->kmap_ops[0]), GFP_KERNEL);
+       add->pages     = kcalloc(count, sizeof(add->pages[0]), GFP_KERNEL);
        if (NULL == add->grants    ||
            NULL == add->map_ops   ||
            NULL == add->unmap_ops ||
index 81c3ce6..1906125 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/vmalloc.h>
 #include <linux/export.h>
 #include <asm/xen/hypervisor.h>
+#include <asm/xen/page.h>
 #include <xen/interface/xen.h>
 #include <xen/interface/event_channel.h>
 #include <xen/events.h>
@@ -436,19 +437,20 @@ EXPORT_SYMBOL_GPL(xenbus_free_evtchn);
 int xenbus_map_ring_valloc(struct xenbus_device *dev, int gnt_ref, void **vaddr)
 {
        struct gnttab_map_grant_ref op = {
-               .flags = GNTMAP_host_map,
+               .flags = GNTMAP_host_map | GNTMAP_contains_pte,
                .ref   = gnt_ref,
                .dom   = dev->otherend_id,
        };
        struct vm_struct *area;
+       pte_t *pte;
 
        *vaddr = NULL;
 
-       area = alloc_vm_area(PAGE_SIZE);
+       area = alloc_vm_area(PAGE_SIZE, &pte);
        if (!area)
                return -ENOMEM;
 
-       op.host_addr = (unsigned long)area->addr;
+       op.host_addr = arbitrary_virt_to_machine(pte).maddr;
 
        if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
                BUG();
@@ -527,6 +529,7 @@ int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr)
        struct gnttab_unmap_grant_ref op = {
                .host_addr = (unsigned long)vaddr,
        };
+       unsigned int level;
 
        /* It'd be nice if linux/vmalloc.h provided a find_vm_area(void *addr)
         * method so that we don't have to muck with vmalloc internals here.
@@ -548,6 +551,8 @@ int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr)
        }
 
        op.handle = (grant_handle_t)area->phys_addr;
+       op.host_addr = arbitrary_virt_to_machine(
+               lookup_address((unsigned long)vaddr, &level)).maddr;
 
        if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
                BUG();
index 41c93c7..b1fe82c 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -337,7 +337,7 @@ static void bio_fs_destructor(struct bio *bio)
  *     RETURNS:
  *     Pointer to new bio on success, NULL on failure.
  */
-struct bio *bio_alloc(gfp_t gfp_mask, int nr_iovecs)
+struct bio *bio_alloc(gfp_t gfp_mask, unsigned int nr_iovecs)
 {
        struct bio *bio = bio_alloc_bioset(gfp_mask, nr_iovecs, fs_bio_set);
 
@@ -365,7 +365,7 @@ static void bio_kmalloc_destructor(struct bio *bio)
  *   %__GFP_WAIT, the allocation is guaranteed to succeed.
  *
  **/
-struct bio *bio_kmalloc(gfp_t gfp_mask, int nr_iovecs)
+struct bio *bio_kmalloc(gfp_t gfp_mask, unsigned int nr_iovecs)
 {
        struct bio *bio;
 
@@ -696,7 +696,8 @@ static void bio_free_map_data(struct bio_map_data *bmd)
        kfree(bmd);
 }
 
-static struct bio_map_data *bio_alloc_map_data(int nr_segs, int iov_count,
+static struct bio_map_data *bio_alloc_map_data(int nr_segs,
+                                              unsigned int iov_count,
                                               gfp_t gfp_mask)
 {
        struct bio_map_data *bmd;
index 5a5d325..634608d 100644 (file)
@@ -147,14 +147,12 @@ struct btrfs_inode {
         * the btrfs file release call will add this inode to the
         * ordered operations list so that we make sure to flush out any
         * new data the application may have written before commit.
-        *
-        * yes, its silly to have a single bitflag, but we might grow more
-        * of these.
         */
        unsigned ordered_data_close:1;
        unsigned orphan_meta_reserved:1;
        unsigned dummy_inode:1;
        unsigned in_defrag:1;
+       unsigned delalloc_meta_reserved:1;
 
        /*
         * always compress this one file
index 3a1b939..5b16357 100644 (file)
@@ -617,12 +617,14 @@ static void btrfs_delayed_item_release_metadata(struct btrfs_root *root,
 static int btrfs_delayed_inode_reserve_metadata(
                                        struct btrfs_trans_handle *trans,
                                        struct btrfs_root *root,
+                                       struct inode *inode,
                                        struct btrfs_delayed_node *node)
 {
        struct btrfs_block_rsv *src_rsv;
        struct btrfs_block_rsv *dst_rsv;
        u64 num_bytes;
        int ret;
+       int release = false;
 
        src_rsv = trans->block_rsv;
        dst_rsv = &root->fs_info->delayed_block_rsv;
@@ -652,12 +654,65 @@ static int btrfs_delayed_inode_reserve_metadata(
                if (!ret)
                        node->bytes_reserved = num_bytes;
                return ret;
+       } else if (src_rsv == &root->fs_info->delalloc_block_rsv) {
+               spin_lock(&BTRFS_I(inode)->lock);
+               if (BTRFS_I(inode)->delalloc_meta_reserved) {
+                       BTRFS_I(inode)->delalloc_meta_reserved = 0;
+                       spin_unlock(&BTRFS_I(inode)->lock);
+                       release = true;
+                       goto migrate;
+               }
+               spin_unlock(&BTRFS_I(inode)->lock);
+
+               /* Ok we didn't have space pre-reserved.  This shouldn't happen
+                * too often but it can happen if we do delalloc to an existing
+                * inode which gets dirtied because of the time update, and then
+                * isn't touched again until after the transaction commits and
+                * then we try to write out the data.  First try to be nice and
+                * reserve something strictly for us.  If not be a pain and try
+                * to steal from the delalloc block rsv.
+                */
+               ret = btrfs_block_rsv_add_noflush(root, dst_rsv, num_bytes);
+               if (!ret)
+                       goto out;
+
+               ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes);
+               if (!ret)
+                       goto out;
+
+               /*
+                * Ok this is a problem, let's just steal from the global rsv
+                * since this really shouldn't happen that often.
+                */
+               WARN_ON(1);
+               ret = btrfs_block_rsv_migrate(&root->fs_info->global_block_rsv,
+                                             dst_rsv, num_bytes);
+               goto out;
        }
 
+migrate:
        ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes);
+
+out:
+       /*
+        * Migrate only takes a reservation, it doesn't touch the size of the
+        * block_rsv.  This is to simplify people who don't normally have things
+        * migrated from their block rsv.  If they go to release their
+        * reservation, that will decrease the size as well, so if migrate
+        * reduced size we'd end up with a negative size.  But for the
+        * delalloc_meta_reserved stuff we will only know to drop 1 reservation,
+        * but we could in fact do this reserve/migrate dance several times
+        * between the time we did the original reservation and we'd clean it
+        * up.  So to take care of this, release the space for the meta
+        * reservation here.  I think it may be time for a documentation page on
+        * how block rsvs. work.
+        */
        if (!ret)
                node->bytes_reserved = num_bytes;
 
+       if (release)
+               btrfs_block_rsv_release(root, src_rsv, num_bytes);
+
        return ret;
 }
 
@@ -1708,7 +1763,8 @@ int btrfs_delayed_update_inode(struct btrfs_trans_handle *trans,
                goto release_node;
        }
 
-       ret = btrfs_delayed_inode_reserve_metadata(trans, root, delayed_node);
+       ret = btrfs_delayed_inode_reserve_metadata(trans, root, inode,
+                                                  delayed_node);
        if (ret)
                goto release_node;
 
index 102c176..62afe5c 100644 (file)
@@ -1890,31 +1890,32 @@ struct btrfs_root *open_ctree(struct super_block *sb,
        u64 features;
        struct btrfs_key location;
        struct buffer_head *bh;
-       struct btrfs_root *extent_root = kzalloc(sizeof(struct btrfs_root),
-                                                GFP_NOFS);
-       struct btrfs_root *csum_root = kzalloc(sizeof(struct btrfs_root),
-                                                GFP_NOFS);
+       struct btrfs_super_block *disk_super;
        struct btrfs_root *tree_root = btrfs_sb(sb);
-       struct btrfs_fs_info *fs_info = NULL;
-       struct btrfs_root *chunk_root = kzalloc(sizeof(struct btrfs_root),
-                                               GFP_NOFS);
-       struct btrfs_root *dev_root = kzalloc(sizeof(struct btrfs_root),
-                                             GFP_NOFS);
+       struct btrfs_fs_info *fs_info = tree_root->fs_info;
+       struct btrfs_root *extent_root;
+       struct btrfs_root *csum_root;
+       struct btrfs_root *chunk_root;
+       struct btrfs_root *dev_root;
        struct btrfs_root *log_tree_root;
-
        int ret;
        int err = -EINVAL;
        int num_backups_tried = 0;
        int backup_index = 0;
 
-       struct btrfs_super_block *disk_super;
+       extent_root = fs_info->extent_root =
+               kzalloc(sizeof(struct btrfs_root), GFP_NOFS);
+       csum_root = fs_info->csum_root =
+               kzalloc(sizeof(struct btrfs_root), GFP_NOFS);
+       chunk_root = fs_info->chunk_root =
+               kzalloc(sizeof(struct btrfs_root), GFP_NOFS);
+       dev_root = fs_info->dev_root =
+               kzalloc(sizeof(struct btrfs_root), GFP_NOFS);
 
-       if (!extent_root || !tree_root || !tree_root->fs_info ||
-           !chunk_root || !dev_root || !csum_root) {
+       if (!extent_root || !csum_root || !chunk_root || !dev_root) {
                err = -ENOMEM;
                goto fail;
        }
-       fs_info = tree_root->fs_info;
 
        ret = init_srcu_struct(&fs_info->subvol_srcu);
        if (ret) {
@@ -1954,12 +1955,6 @@ struct btrfs_root *open_ctree(struct super_block *sb,
        mutex_init(&fs_info->reloc_mutex);
 
        init_completion(&fs_info->kobj_unregister);
-       fs_info->tree_root = tree_root;
-       fs_info->extent_root = extent_root;
-       fs_info->csum_root = csum_root;
-       fs_info->chunk_root = chunk_root;
-       fs_info->dev_root = dev_root;
-       fs_info->fs_devices = fs_devices;
        INIT_LIST_HEAD(&fs_info->dirty_cowonly_roots);
        INIT_LIST_HEAD(&fs_info->space_info);
        btrfs_mapping_init(&fs_info->mapping_tree);
@@ -2465,21 +2460,20 @@ fail_sb_buffer:
        btrfs_stop_workers(&fs_info->caching_workers);
 fail_alloc:
 fail_iput:
+       btrfs_mapping_tree_free(&fs_info->mapping_tree);
+
        invalidate_inode_pages2(fs_info->btree_inode->i_mapping);
        iput(fs_info->btree_inode);
-
-       btrfs_close_devices(fs_info->fs_devices);
-       btrfs_mapping_tree_free(&fs_info->mapping_tree);
 fail_bdi:
        bdi_destroy(&fs_info->bdi);
 fail_srcu:
        cleanup_srcu_struct(&fs_info->subvol_srcu);
 fail:
+       btrfs_close_devices(fs_info->fs_devices);
        free_fs_info(fs_info);
        return ERR_PTR(err);
 
 recovery_tree_root:
-
        if (!btrfs_test_opt(tree_root, RECOVERY))
                goto fail_tree_roots;
 
index 9879bd4..b232150 100644 (file)
@@ -3797,16 +3797,16 @@ void btrfs_free_block_rsv(struct btrfs_root *root,
        kfree(rsv);
 }
 
-int btrfs_block_rsv_add(struct btrfs_root *root,
-                       struct btrfs_block_rsv *block_rsv,
-                       u64 num_bytes)
+static inline int __block_rsv_add(struct btrfs_root *root,
+                                 struct btrfs_block_rsv *block_rsv,
+                                 u64 num_bytes, int flush)
 {
        int ret;
 
        if (num_bytes == 0)
                return 0;
 
-       ret = reserve_metadata_bytes(root, block_rsv, num_bytes, 1);
+       ret = reserve_metadata_bytes(root, block_rsv, num_bytes, flush);
        if (!ret) {
                block_rsv_add_bytes(block_rsv, num_bytes, 1);
                return 0;
@@ -3815,22 +3815,18 @@ int btrfs_block_rsv_add(struct btrfs_root *root,
        return ret;
 }
 
+int btrfs_block_rsv_add(struct btrfs_root *root,
+                       struct btrfs_block_rsv *block_rsv,
+                       u64 num_bytes)
+{
+       return __block_rsv_add(root, block_rsv, num_bytes, 1);
+}
+
 int btrfs_block_rsv_add_noflush(struct btrfs_root *root,
                                struct btrfs_block_rsv *block_rsv,
                                u64 num_bytes)
 {
-       int ret;
-
-       if (num_bytes == 0)
-               return 0;
-
-       ret = reserve_metadata_bytes(root, block_rsv, num_bytes, 0);
-       if (!ret) {
-               block_rsv_add_bytes(block_rsv, num_bytes, 1);
-               return 0;
-       }
-
-       return ret;
+       return __block_rsv_add(root, block_rsv, num_bytes, 0);
 }
 
 int btrfs_block_rsv_check(struct btrfs_root *root,
@@ -4064,23 +4060,30 @@ int btrfs_snap_reserve_metadata(struct btrfs_trans_handle *trans,
  */
 static unsigned drop_outstanding_extent(struct inode *inode)
 {
+       unsigned drop_inode_space = 0;
        unsigned dropped_extents = 0;
 
        BUG_ON(!BTRFS_I(inode)->outstanding_extents);
        BTRFS_I(inode)->outstanding_extents--;
 
+       if (BTRFS_I(inode)->outstanding_extents == 0 &&
+           BTRFS_I(inode)->delalloc_meta_reserved) {
+               drop_inode_space = 1;
+               BTRFS_I(inode)->delalloc_meta_reserved = 0;
+       }
+
        /*
         * If we have more or the same amount of outsanding extents than we have
         * reserved then we need to leave the reserved extents count alone.
         */
        if (BTRFS_I(inode)->outstanding_extents >=
            BTRFS_I(inode)->reserved_extents)
-               return 0;
+               return drop_inode_space;
 
        dropped_extents = BTRFS_I(inode)->reserved_extents -
                BTRFS_I(inode)->outstanding_extents;
        BTRFS_I(inode)->reserved_extents -= dropped_extents;
-       return dropped_extents;
+       return dropped_extents + drop_inode_space;
 }
 
 /**
@@ -4166,9 +4169,18 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
                nr_extents = BTRFS_I(inode)->outstanding_extents -
                        BTRFS_I(inode)->reserved_extents;
                BTRFS_I(inode)->reserved_extents += nr_extents;
+       }
 
-               to_reserve = btrfs_calc_trans_metadata_size(root, nr_extents);
+       /*
+        * Add an item to reserve for updating the inode when we complete the
+        * delalloc io.
+        */
+       if (!BTRFS_I(inode)->delalloc_meta_reserved) {
+               nr_extents++;
+               BTRFS_I(inode)->delalloc_meta_reserved = 1;
        }
+
+       to_reserve = btrfs_calc_trans_metadata_size(root, nr_extents);
        to_reserve += calc_csum_metadata_size(inode, num_bytes, 1);
        spin_unlock(&BTRFS_I(inode)->lock);
 
index 7a15fcf..181760f 100644 (file)
@@ -537,6 +537,13 @@ static int io_ctl_read_entry(struct io_ctl *io_ctl,
                            struct btrfs_free_space *entry, u8 *type)
 {
        struct btrfs_free_space_entry *e;
+       int ret;
+
+       if (!io_ctl->cur) {
+               ret = io_ctl_check_crc(io_ctl, io_ctl->index);
+               if (ret)
+                       return ret;
+       }
 
        e = io_ctl->cur;
        entry->offset = le64_to_cpu(e->offset);
@@ -550,10 +557,7 @@ static int io_ctl_read_entry(struct io_ctl *io_ctl,
 
        io_ctl_unmap_page(io_ctl);
 
-       if (io_ctl->index >= io_ctl->num_pages)
-               return 0;
-
-       return io_ctl_check_crc(io_ctl, io_ctl->index);
+       return 0;
 }
 
 static int io_ctl_read_bitmap(struct io_ctl *io_ctl,
@@ -561,9 +565,6 @@ static int io_ctl_read_bitmap(struct io_ctl *io_ctl,
 {
        int ret;
 
-       if (io_ctl->cur && io_ctl->cur != io_ctl->orig)
-               io_ctl_unmap_page(io_ctl);
-
        ret = io_ctl_check_crc(io_ctl, io_ctl->index);
        if (ret)
                return ret;
@@ -699,6 +700,8 @@ int __load_free_space_cache(struct btrfs_root *root, struct inode *inode,
                num_entries--;
        }
 
+       io_ctl_unmap_page(&io_ctl);
+
        /*
         * We add the bitmaps at the end of the entries in order that
         * the bitmap entries are added to the cache.
index 53dcbdf..f8962a9 100644 (file)
@@ -398,6 +398,8 @@ int btrfs_save_ino_cache(struct btrfs_root *root,
        struct btrfs_free_space_ctl *ctl = root->free_ino_ctl;
        struct btrfs_path *path;
        struct inode *inode;
+       struct btrfs_block_rsv *rsv;
+       u64 num_bytes;
        u64 alloc_hint = 0;
        int ret;
        int prealloc;
@@ -421,11 +423,26 @@ int btrfs_save_ino_cache(struct btrfs_root *root,
        if (!path)
                return -ENOMEM;
 
+       rsv = trans->block_rsv;
+       trans->block_rsv = &root->fs_info->trans_block_rsv;
+
+       num_bytes = trans->bytes_reserved;
+       /*
+        * 1 item for inode item insertion if need
+        * 3 items for inode item update (in the worst case)
+        * 1 item for free space object
+        * 3 items for pre-allocation
+        */
+       trans->bytes_reserved = btrfs_calc_trans_metadata_size(root, 8);
+       ret = btrfs_block_rsv_add_noflush(root, trans->block_rsv,
+                                         trans->bytes_reserved);
+       if (ret)
+               goto out;
 again:
        inode = lookup_free_ino_inode(root, path);
        if (IS_ERR(inode) && PTR_ERR(inode) != -ENOENT) {
                ret = PTR_ERR(inode);
-               goto out;
+               goto out_release;
        }
 
        if (IS_ERR(inode)) {
@@ -434,7 +451,7 @@ again:
 
                ret = create_free_ino_inode(root, trans, path);
                if (ret)
-                       goto out;
+                       goto out_release;
                goto again;
        }
 
@@ -477,11 +494,14 @@ again:
        }
        btrfs_free_reserved_data_space(inode, prealloc);
 
+       ret = btrfs_write_out_ino_cache(root, trans, path);
 out_put:
        iput(inode);
+out_release:
+       btrfs_block_rsv_release(root, trans->block_rsv, trans->bytes_reserved);
 out:
-       if (ret == 0)
-               ret = btrfs_write_out_ino_cache(root, trans, path);
+       trans->block_rsv = rsv;
+       trans->bytes_reserved = num_bytes;
 
        btrfs_free_path(path);
        return ret;
index 966ddcc..116ab67 100644 (file)
@@ -93,6 +93,8 @@ static noinline int cow_file_range(struct inode *inode,
                                   struct page *locked_page,
                                   u64 start, u64 end, int *page_started,
                                   unsigned long *nr_written, int unlock);
+static noinline int btrfs_update_inode_fallback(struct btrfs_trans_handle *trans,
+                               struct btrfs_root *root, struct inode *inode);
 
 static int btrfs_init_inode_security(struct btrfs_trans_handle *trans,
                                     struct inode *inode,  struct inode *dir,
@@ -1741,7 +1743,7 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
                                trans = btrfs_join_transaction(root);
                        BUG_ON(IS_ERR(trans));
                        trans->block_rsv = &root->fs_info->delalloc_block_rsv;
-                       ret = btrfs_update_inode(trans, root, inode);
+                       ret = btrfs_update_inode_fallback(trans, root, inode);
                        BUG_ON(ret);
                }
                goto out;
@@ -1791,7 +1793,7 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
 
        ret = btrfs_ordered_update_i_size(inode, 0, ordered_extent);
        if (!ret || !test_bit(BTRFS_ORDERED_PREALLOC, &ordered_extent->flags)) {
-               ret = btrfs_update_inode(trans, root, inode);
+               ret = btrfs_update_inode_fallback(trans, root, inode);
                BUG_ON(ret);
        }
        ret = 0;
@@ -2199,6 +2201,9 @@ int btrfs_orphan_cleanup(struct btrfs_root *root)
                if (ret)
                        goto out;
        }
+       /* release the path since we're done with it */
+       btrfs_release_path(path);
+
        root->orphan_cleanup_state = ORPHAN_CLEANUP_DONE;
 
        if (root->orphan_block_rsv)
@@ -2426,7 +2431,7 @@ static void fill_inode_item(struct btrfs_trans_handle *trans,
 /*
  * copy everything in the in-memory inode into the btree.
  */
-noinline int btrfs_update_inode(struct btrfs_trans_handle *trans,
+static noinline int btrfs_update_inode_item(struct btrfs_trans_handle *trans,
                                struct btrfs_root *root, struct inode *inode)
 {
        struct btrfs_inode_item *inode_item;
@@ -2434,21 +2439,6 @@ noinline int btrfs_update_inode(struct btrfs_trans_handle *trans,
        struct extent_buffer *leaf;
        int ret;
 
-       /*
-        * If the inode is a free space inode, we can deadlock during commit
-        * if we put it into the delayed code.
-        *
-        * The data relocation inode should also be directly updated
-        * without delay
-        */
-       if (!btrfs_is_free_space_inode(root, inode)
-           && root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID) {
-               ret = btrfs_delayed_update_inode(trans, root, inode);
-               if (!ret)
-                       btrfs_set_inode_last_trans(trans, inode);
-               return ret;
-       }
-
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
@@ -2477,6 +2467,43 @@ failed:
 }
 
 /*
+ * copy everything in the in-memory inode into the btree.
+ */
+noinline int btrfs_update_inode(struct btrfs_trans_handle *trans,
+                               struct btrfs_root *root, struct inode *inode)
+{
+       int ret;
+
+       /*
+        * If the inode is a free space inode, we can deadlock during commit
+        * if we put it into the delayed code.
+        *
+        * The data relocation inode should also be directly updated
+        * without delay
+        */
+       if (!btrfs_is_free_space_inode(root, inode)
+           && root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID) {
+               ret = btrfs_delayed_update_inode(trans, root, inode);
+               if (!ret)
+                       btrfs_set_inode_last_trans(trans, inode);
+               return ret;
+       }
+
+       return btrfs_update_inode_item(trans, root, inode);
+}
+
+static noinline int btrfs_update_inode_fallback(struct btrfs_trans_handle *trans,
+                               struct btrfs_root *root, struct inode *inode)
+{
+       int ret;
+
+       ret = btrfs_update_inode(trans, root, inode);
+       if (ret == -ENOSPC)
+               return btrfs_update_inode_item(trans, root, inode);
+       return ret;
+}
+
+/*
  * unlink helper that gets used here in inode.c and in the tree logging
  * recovery code.  It remove a link in a directory with a given name, and
  * also drops the back refs in the inode to the directory
@@ -5632,7 +5659,7 @@ again:
        if (test_bit(BTRFS_ORDERED_NOCOW, &ordered->flags)) {
                ret = btrfs_ordered_update_i_size(inode, 0, ordered);
                if (!ret)
-                       err = btrfs_update_inode(trans, root, inode);
+                       err = btrfs_update_inode_fallback(trans, root, inode);
                goto out;
        }
 
@@ -5670,7 +5697,7 @@ again:
        add_pending_csums(trans, inode, ordered->file_offset, &ordered->list);
        ret = btrfs_ordered_update_i_size(inode, 0, ordered);
        if (!ret || !test_bit(BTRFS_ORDERED_PREALLOC, &ordered->flags))
-               btrfs_update_inode(trans, root, inode);
+               btrfs_update_inode_fallback(trans, root, inode);
        ret = 0;
 out_unlock:
        unlock_extent_cached(&BTRFS_I(inode)->io_tree, ordered->file_offset,
@@ -6529,14 +6556,16 @@ end_trans:
                ret = btrfs_orphan_del(NULL, inode);
        }
 
-       trans->block_rsv = &root->fs_info->trans_block_rsv;
-       ret = btrfs_update_inode(trans, root, inode);
-       if (ret && !err)
-               err = ret;
+       if (trans) {
+               trans->block_rsv = &root->fs_info->trans_block_rsv;
+               ret = btrfs_update_inode(trans, root, inode);
+               if (ret && !err)
+                       err = ret;
 
-       nr = trans->blocks_used;
-       ret = btrfs_end_transaction_throttle(trans, root);
-       btrfs_btree_balance_dirty(root, nr);
+               nr = trans->blocks_used;
+               ret = btrfs_end_transaction_throttle(trans, root);
+               btrfs_btree_balance_dirty(root, nr);
+       }
 
 out:
        btrfs_free_block_rsv(root, rsv);
@@ -6605,6 +6634,7 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
        ei->orphan_meta_reserved = 0;
        ei->dummy_inode = 0;
        ei->in_defrag = 0;
+       ei->delalloc_meta_reserved = 0;
        ei->force_compress = BTRFS_COMPRESS_NONE;
 
        ei->delayed_node = NULL;
index 24d654c..dff29d5 100644 (file)
@@ -1174,6 +1174,8 @@ static int clone_backref_node(struct btrfs_trans_handle *trans,
                        list_add_tail(&new_edge->list[UPPER],
                                      &new_node->lower);
                }
+       } else {
+               list_add_tail(&new_node->lower, &cache->leaves);
        }
 
        rb_node = tree_insert(&cache->rb_root, new_node->bytenr,
index ed11d38..f4190f2 100644 (file)
@@ -944,50 +944,18 @@ static int scrub_checksum_super(struct scrub_bio *sbio, void *buffer)
 static int scrub_submit(struct scrub_dev *sdev)
 {
        struct scrub_bio *sbio;
-       struct bio *bio;
-       int i;
 
        if (sdev->curr == -1)
                return 0;
 
        sbio = sdev->bios[sdev->curr];
-
-       bio = bio_alloc(GFP_NOFS, sbio->count);
-       if (!bio)
-               goto nomem;
-
-       bio->bi_private = sbio;
-       bio->bi_end_io = scrub_bio_end_io;
-       bio->bi_bdev = sdev->dev->bdev;
-       bio->bi_sector = sbio->physical >> 9;
-
-       for (i = 0; i < sbio->count; ++i) {
-               struct page *page;
-               int ret;
-
-               page = alloc_page(GFP_NOFS);
-               if (!page)
-                       goto nomem;
-
-               ret = bio_add_page(bio, page, PAGE_SIZE, 0);
-               if (!ret) {
-                       __free_page(page);
-                       goto nomem;
-               }
-       }
-
        sbio->err = 0;
        sdev->curr = -1;
        atomic_inc(&sdev->in_flight);
 
-       submit_bio(READ, bio);
+       submit_bio(READ, sbio->bio);
 
        return 0;
-
-nomem:
-       scrub_free_bio(bio);
-
-       return -ENOMEM;
 }
 
 static int scrub_page(struct scrub_dev *sdev, u64 logical, u64 len,
@@ -995,6 +963,8 @@ static int scrub_page(struct scrub_dev *sdev, u64 logical, u64 len,
                      u8 *csum, int force)
 {
        struct scrub_bio *sbio;
+       struct page *page;
+       int ret;
 
 again:
        /*
@@ -1015,12 +985,22 @@ again:
        }
        sbio = sdev->bios[sdev->curr];
        if (sbio->count == 0) {
+               struct bio *bio;
+
                sbio->physical = physical;
                sbio->logical = logical;
+               bio = bio_alloc(GFP_NOFS, SCRUB_PAGES_PER_BIO);
+               if (!bio)
+                       return -ENOMEM;
+
+               bio->bi_private = sbio;
+               bio->bi_end_io = scrub_bio_end_io;
+               bio->bi_bdev = sdev->dev->bdev;
+               bio->bi_sector = sbio->physical >> 9;
+               sbio->err = 0;
+               sbio->bio = bio;
        } else if (sbio->physical + sbio->count * PAGE_SIZE != physical ||
                   sbio->logical + sbio->count * PAGE_SIZE != logical) {
-               int ret;
-
                ret = scrub_submit(sdev);
                if (ret)
                        return ret;
@@ -1030,6 +1010,20 @@ again:
        sbio->spag[sbio->count].generation = gen;
        sbio->spag[sbio->count].have_csum = 0;
        sbio->spag[sbio->count].mirror_num = mirror_num;
+
+       page = alloc_page(GFP_NOFS);
+       if (!page)
+               return -ENOMEM;
+
+       ret = bio_add_page(sbio->bio, page, PAGE_SIZE, 0);
+       if (!ret) {
+               __free_page(page);
+               ret = scrub_submit(sdev);
+               if (ret)
+                       return ret;
+               goto again;
+       }
+
        if (csum) {
                sbio->spag[sbio->count].have_csum = 1;
                memcpy(sbio->spag[sbio->count].csum, csum, sdev->csum_size);
index 57080df..17ee7fc 100644 (file)
@@ -197,7 +197,7 @@ static match_table_t tokens = {
        {Opt_subvolrootid, "subvolrootid=%d"},
        {Opt_defrag, "autodefrag"},
        {Opt_inode_cache, "inode_cache"},
-       {Opt_no_space_cache, "no_space_cache"},
+       {Opt_no_space_cache, "nospace_cache"},
        {Opt_recovery, "recovery"},
        {Opt_err, NULL},
 };
@@ -448,6 +448,7 @@ static int btrfs_parse_early_options(const char *options, fmode_t flags,
                token = match_token(p, tokens, args);
                switch (token) {
                case Opt_subvol:
+                       kfree(*subvol_name);
                        *subvol_name = match_strdup(&args[0]);
                        break;
                case Opt_subvolid:
@@ -710,7 +711,7 @@ static int btrfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
        if (btrfs_test_opt(root, SPACE_CACHE))
                seq_puts(seq, ",space_cache");
        else
-               seq_puts(seq, ",no_space_cache");
+               seq_puts(seq, ",nospace_cache");
        if (btrfs_test_opt(root, CLEAR_CACHE))
                seq_puts(seq, ",clear_cache");
        if (btrfs_test_opt(root, USER_SUBVOL_RM_ALLOWED))
@@ -824,13 +825,9 @@ static char *setup_root_args(char *args)
 static struct dentry *mount_subvol(const char *subvol_name, int flags,
                                   const char *device_name, char *data)
 {
-       struct super_block *s;
        struct dentry *root;
        struct vfsmount *mnt;
-       struct mnt_namespace *ns_private;
        char *newargs;
-       struct path path;
-       int error;
 
        newargs = setup_root_args(data);
        if (!newargs)
@@ -841,39 +838,17 @@ static struct dentry *mount_subvol(const char *subvol_name, int flags,
        if (IS_ERR(mnt))
                return ERR_CAST(mnt);
 
-       ns_private = create_mnt_ns(mnt);
-       if (IS_ERR(ns_private)) {
-               mntput(mnt);
-               return ERR_CAST(ns_private);
-       }
-
-       /*
-        * This will trigger the automount of the subvol so we can just
-        * drop the mnt we have here and return the dentry that we
-        * found.
-        */
-       error = vfs_path_lookup(mnt->mnt_root, mnt, subvol_name,
-                               LOOKUP_FOLLOW, &path);
-       put_mnt_ns(ns_private);
-       if (error)
-               return ERR_PTR(error);
+       root = mount_subtree(mnt, subvol_name);
 
-       if (!is_subvolume_inode(path.dentry->d_inode)) {
-               path_put(&path);
-               mntput(mnt);
-               error = -EINVAL;
+       if (!IS_ERR(root) && !is_subvolume_inode(root->d_inode)) {
+               struct super_block *s = root->d_sb;
+               dput(root);
+               root = ERR_PTR(-EINVAL);
+               deactivate_locked_super(s);
                printk(KERN_ERR "btrfs: '%s' is not a valid subvolume\n",
                                subvol_name);
-               return ERR_PTR(-EINVAL);
        }
 
-       /* Get a ref to the sb and the dentry we found and return it */
-       s = path.mnt->mnt_sb;
-       atomic_inc(&s->s_active);
-       root = dget(path.dentry);
-       path_put(&path);
-       down_write(&s->s_umount);
-
        return root;
 }
 
@@ -890,7 +865,6 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
        struct super_block *s;
        struct dentry *root;
        struct btrfs_fs_devices *fs_devices = NULL;
-       struct btrfs_root *tree_root = NULL;
        struct btrfs_fs_info *fs_info = NULL;
        fmode_t mode = FMODE_READ;
        char *subvol_name = NULL;
@@ -904,8 +878,10 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
        error = btrfs_parse_early_options(data, mode, fs_type,
                                          &subvol_name, &subvol_objectid,
                                          &subvol_rootid, &fs_devices);
-       if (error)
+       if (error) {
+               kfree(subvol_name);
                return ERR_PTR(error);
+       }
 
        if (subvol_name) {
                root = mount_subvol(subvol_name, flags, device_name, data);
@@ -917,15 +893,6 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
        if (error)
                return ERR_PTR(error);
 
-       error = btrfs_open_devices(fs_devices, mode, fs_type);
-       if (error)
-               return ERR_PTR(error);
-
-       if (!(flags & MS_RDONLY) && fs_devices->rw_devices == 0) {
-               error = -EACCES;
-               goto error_close_devices;
-       }
-
        /*
         * Setup a dummy root and fs_info for test/set super.  This is because
         * we don't actually fill this stuff out until open_ctree, but we need
@@ -933,24 +900,36 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
         * then open_ctree will properly initialize everything later.
         */
        fs_info = kzalloc(sizeof(struct btrfs_fs_info), GFP_NOFS);
-       tree_root = kzalloc(sizeof(struct btrfs_root), GFP_NOFS);
-       if (!fs_info || !tree_root) {
+       if (!fs_info)
+               return ERR_PTR(-ENOMEM);
+
+       fs_info->tree_root = kzalloc(sizeof(struct btrfs_root), GFP_NOFS);
+       if (!fs_info->tree_root) {
                error = -ENOMEM;
-               goto error_close_devices;
+               goto error_fs_info;
        }
-       fs_info->tree_root = tree_root;
+       fs_info->tree_root->fs_info = fs_info;
        fs_info->fs_devices = fs_devices;
-       tree_root->fs_info = fs_info;
 
        fs_info->super_copy = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_NOFS);
        fs_info->super_for_commit = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_NOFS);
        if (!fs_info->super_copy || !fs_info->super_for_commit) {
                error = -ENOMEM;
+               goto error_fs_info;
+       }
+
+       error = btrfs_open_devices(fs_devices, mode, fs_type);
+       if (error)
+               goto error_fs_info;
+
+       if (!(flags & MS_RDONLY) && fs_devices->rw_devices == 0) {
+               error = -EACCES;
                goto error_close_devices;
        }
 
        bdev = fs_devices->latest_bdev;
-       s = sget(fs_type, btrfs_test_super, btrfs_set_super, tree_root);
+       s = sget(fs_type, btrfs_test_super, btrfs_set_super,
+                fs_info->tree_root);
        if (IS_ERR(s)) {
                error = PTR_ERR(s);
                goto error_close_devices;
@@ -959,12 +938,12 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
        if (s->s_root) {
                if ((flags ^ s->s_flags) & MS_RDONLY) {
                        deactivate_locked_super(s);
-                       return ERR_PTR(-EBUSY);
+                       error = -EBUSY;
+                       goto error_close_devices;
                }
 
                btrfs_close_devices(fs_devices);
                free_fs_info(fs_info);
-               kfree(tree_root);
        } else {
                char b[BDEVNAME_SIZE];
 
@@ -991,8 +970,8 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
 
 error_close_devices:
        btrfs_close_devices(fs_devices);
+error_fs_info:
        free_fs_info(fs_info);
-       kfree(tree_root);
        return ERR_PTR(error);
 }
 
index 960835e..6a0574e 100644 (file)
@@ -882,8 +882,8 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
        btrfs_reloc_pre_snapshot(trans, pending, &to_reserve);
 
        if (to_reserve > 0) {
-               ret = btrfs_block_rsv_add(root, &pending->block_rsv,
-                                         to_reserve);
+               ret = btrfs_block_rsv_add_noflush(root, &pending->block_rsv,
+                                                 to_reserve);
                if (ret) {
                        pending->error = ret;
                        goto fail;
index f8e2943..c37433d 100644 (file)
@@ -999,7 +999,7 @@ static int btrfs_free_dev_extent(struct btrfs_trans_handle *trans,
        key.objectid = device->devid;
        key.offset = start;
        key.type = BTRFS_DEV_EXTENT_KEY;
-
+again:
        ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
        if (ret > 0) {
                ret = btrfs_previous_item(root, path, key.objectid,
@@ -1012,6 +1012,9 @@ static int btrfs_free_dev_extent(struct btrfs_trans_handle *trans,
                                        struct btrfs_dev_extent);
                BUG_ON(found_key.offset > start || found_key.offset +
                       btrfs_dev_extent_length(leaf, extent) < start);
+               key = found_key;
+               btrfs_release_path(path);
+               goto again;
        } else if (ret == 0) {
                leaf = path->nodes[0];
                extent = btrfs_item_ptr(leaf, path->slots[0],
index 990626e..0b3109e 100644 (file)
@@ -281,7 +281,7 @@ static int nodeid_to_addr(int nodeid, struct sockaddr *retaddr)
        } else {
                struct sockaddr_in6 *in6  = (struct sockaddr_in6 *) &addr;
                struct sockaddr_in6 *ret6 = (struct sockaddr_in6 *) retaddr;
-               ipv6_addr_copy(&ret6->sin6_addr, &in6->sin6_addr);
+               ret6->sin6_addr = in6->sin6_addr;
        }
 
        return 0;
index e673a88..b1ce4c7 100644 (file)
@@ -40,6 +40,8 @@ int hfs_mac2asc(struct super_block *sb, char *out, const struct hfs_name *in)
 
        src = in->name;
        srclen = in->len;
+       if (srclen > HFS_NAMELEN)
+               srclen = HFS_NAMELEN;
        dst = out;
        dstlen = HFS_MAX_NAMELEN;
        if (nls_io) {
index e5e1c7d..50ee303 100644 (file)
@@ -2483,11 +2483,41 @@ struct mnt_namespace *create_mnt_ns(struct vfsmount *mnt)
                __mnt_make_longterm(mnt);
                new_ns->root = mnt;
                list_add(&new_ns->list, &new_ns->root->mnt_list);
+       } else {
+               mntput(mnt);
        }
        return new_ns;
 }
 EXPORT_SYMBOL(create_mnt_ns);
 
+struct dentry *mount_subtree(struct vfsmount *mnt, const char *name)
+{
+       struct mnt_namespace *ns;
+       struct path path;
+       int err;
+
+       ns = create_mnt_ns(mnt);
+       if (IS_ERR(ns))
+               return ERR_CAST(ns);
+
+       err = vfs_path_lookup(mnt->mnt_root, mnt,
+                       name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &path);
+
+       put_mnt_ns(ns);
+
+       if (err)
+               return ERR_PTR(err);
+
+       /* trade a vfsmount reference for active sb one */
+       atomic_inc(&path.mnt->mnt_sb->s_active);
+       mntput(path.mnt);
+       /* lock the sucker */
+       down_write(&path.mnt->mnt_sb->s_umount);
+       /* ... and return the root of (sub)tree on it */
+       return path.dentry;
+}
+EXPORT_SYMBOL(mount_subtree);
+
 SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,
                char __user *, type, unsigned long, flags, void __user *, data)
 {
index 480b3b6..1347774 100644 (file)
@@ -2787,43 +2787,18 @@ static void nfs_referral_loop_unprotect(void)
 static struct dentry *nfs_follow_remote_path(struct vfsmount *root_mnt,
                const char *export_path)
 {
-       struct mnt_namespace *ns_private;
-       struct super_block *s;
        struct dentry *dentry;
-       struct path path;
-       int ret;
-
-       ns_private = create_mnt_ns(root_mnt);
-       ret = PTR_ERR(ns_private);
-       if (IS_ERR(ns_private))
-               goto out_mntput;
-
-       ret = nfs_referral_loop_protect();
-       if (ret != 0)
-               goto out_put_mnt_ns;
+       int ret = nfs_referral_loop_protect();
 
-       ret = vfs_path_lookup(root_mnt->mnt_root, root_mnt,
-                       export_path, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &path);
+       if (ret) {
+               mntput(root_mnt);
+               return ERR_PTR(ret);
+       }
 
+       dentry = mount_subtree(root_mnt, export_path);
        nfs_referral_loop_unprotect();
-       put_mnt_ns(ns_private);
-
-       if (ret != 0)
-               goto out_err;
-
-       s = path.mnt->mnt_sb;
-       atomic_inc(&s->s_active);
-       dentry = dget(path.dentry);
 
-       path_put(&path);
-       down_write(&s->s_umount);
        return dentry;
-out_put_mnt_ns:
-       put_mnt_ns(ns_private);
-out_mntput:
-       mntput(root_mnt);
-out_err:
-       return ERR_PTR(ret);
 }
 
 static struct dentry *nfs4_try_mount(int flags, const char *dev_name,
index 2db1bd3..851ba3d 100644 (file)
@@ -1652,46 +1652,12 @@ out:
        return error;
 }
 
-static int proc_pid_fd_link_getattr(struct vfsmount *mnt, struct dentry *dentry,
-               struct kstat *stat)
-{
-       struct inode *inode = dentry->d_inode;
-       struct task_struct *task = get_proc_task(inode);
-       int rc;
-
-       if (task == NULL)
-               return -ESRCH;
-
-       rc = -EACCES;
-       if (lock_trace(task))
-               goto out_task;
-
-       generic_fillattr(inode, stat);
-       unlock_trace(task);
-       rc = 0;
-out_task:
-       put_task_struct(task);
-       return rc;
-}
-
 static const struct inode_operations proc_pid_link_inode_operations = {
        .readlink       = proc_pid_readlink,
        .follow_link    = proc_pid_follow_link,
        .setattr        = proc_setattr,
 };
 
-static const struct inode_operations proc_fdinfo_link_inode_operations = {
-       .setattr        = proc_setattr,
-       .getattr        = proc_pid_fd_link_getattr,
-};
-
-static const struct inode_operations proc_fd_link_inode_operations = {
-       .readlink       = proc_pid_readlink,
-       .follow_link    = proc_pid_follow_link,
-       .setattr        = proc_setattr,
-       .getattr        = proc_pid_fd_link_getattr,
-};
-
 
 /* building an inode */
 
@@ -1923,61 +1889,49 @@ out:
 
 static int proc_fd_info(struct inode *inode, struct path *path, char *info)
 {
-       struct task_struct *task;
-       struct files_struct *files;
+       struct task_struct *task = get_proc_task(inode);
+       struct files_struct *files = NULL;
        struct file *file;
        int fd = proc_fd(inode);
-       int rc;
-
-       task = get_proc_task(inode);
-       if (!task)
-               return -ENOENT;
-
-       rc = -EACCES;
-       if (lock_trace(task))
-               goto out_task;
-
-       rc = -ENOENT;
-       files = get_files_struct(task);
-       if (files == NULL)
-               goto out_unlock;
 
-       /*
-        * We are not taking a ref to the file structure, so we must
-        * hold ->file_lock.
-        */
-       spin_lock(&files->file_lock);
-       file = fcheck_files(files, fd);
-       if (file) {
-               unsigned int f_flags;
-               struct fdtable *fdt;
-
-               fdt = files_fdtable(files);
-               f_flags = file->f_flags & ~O_CLOEXEC;
-               if (FD_ISSET(fd, fdt->close_on_exec))
-                       f_flags |= O_CLOEXEC;
-
-               if (path) {
-                       *path = file->f_path;
-                       path_get(&file->f_path);
+       if (task) {
+               files = get_files_struct(task);
+               put_task_struct(task);
+       }
+       if (files) {
+               /*
+                * We are not taking a ref to the file structure, so we must
+                * hold ->file_lock.
+                */
+               spin_lock(&files->file_lock);
+               file = fcheck_files(files, fd);
+               if (file) {
+                       unsigned int f_flags;
+                       struct fdtable *fdt;
+
+                       fdt = files_fdtable(files);
+                       f_flags = file->f_flags & ~O_CLOEXEC;
+                       if (FD_ISSET(fd, fdt->close_on_exec))
+                               f_flags |= O_CLOEXEC;
+
+                       if (path) {
+                               *path = file->f_path;
+                               path_get(&file->f_path);
+                       }
+                       if (info)
+                               snprintf(info, PROC_FDINFO_MAX,
+                                        "pos:\t%lli\n"
+                                        "flags:\t0%o\n",
+                                        (long long) file->f_pos,
+                                        f_flags);
+                       spin_unlock(&files->file_lock);
+                       put_files_struct(files);
+                       return 0;
                }
-               if (info)
-                       snprintf(info, PROC_FDINFO_MAX,
-                                "pos:\t%lli\n"
-                                "flags:\t0%o\n",
-                                (long long) file->f_pos,
-                                f_flags);
-               rc = 0;
-       } else
-               rc = -ENOENT;
-       spin_unlock(&files->file_lock);
-       put_files_struct(files);
-
-out_unlock:
-       unlock_trace(task);
-out_task:
-       put_task_struct(task);
-       return rc;
+               spin_unlock(&files->file_lock);
+               put_files_struct(files);
+       }
+       return -ENOENT;
 }
 
 static int proc_fd_link(struct inode *inode, struct path *path)
@@ -2072,7 +2026,7 @@ static struct dentry *proc_fd_instantiate(struct inode *dir,
        spin_unlock(&files->file_lock);
        put_files_struct(files);
 
-       inode->i_op = &proc_fd_link_inode_operations;
+       inode->i_op = &proc_pid_link_inode_operations;
        inode->i_size = 64;
        ei->op.proc_get_link = proc_fd_link;
        d_set_d_op(dentry, &tid_fd_dentry_operations);
@@ -2104,12 +2058,7 @@ static struct dentry *proc_lookupfd_common(struct inode *dir,
        if (fd == ~0U)
                goto out;
 
-       result = ERR_PTR(-EACCES);
-       if (lock_trace(task))
-               goto out;
-
        result = instantiate(dir, dentry, task, &fd);
-       unlock_trace(task);
 out:
        put_task_struct(task);
 out_no_task:
@@ -2129,28 +2078,23 @@ static int proc_readfd_common(struct file * filp, void * dirent,
        retval = -ENOENT;
        if (!p)
                goto out_no_task;
-
-       retval = -EACCES;
-       if (lock_trace(p))
-               goto out;
-
        retval = 0;
 
        fd = filp->f_pos;
        switch (fd) {
                case 0:
                        if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0)
-                               goto out_unlock;
+                               goto out;
                        filp->f_pos++;
                case 1:
                        ino = parent_ino(dentry);
                        if (filldir(dirent, "..", 2, 1, ino, DT_DIR) < 0)
-                               goto out_unlock;
+                               goto out;
                        filp->f_pos++;
                default:
                        files = get_files_struct(p);
                        if (!files)
-                               goto out_unlock;
+                               goto out;
                        rcu_read_lock();
                        for (fd = filp->f_pos-2;
                             fd < files_fdtable(files)->max_fds;
@@ -2174,9 +2118,6 @@ static int proc_readfd_common(struct file * filp, void * dirent,
                        rcu_read_unlock();
                        put_files_struct(files);
        }
-
-out_unlock:
-       unlock_trace(p);
 out:
        put_task_struct(p);
 out_no_task:
@@ -2254,7 +2195,6 @@ static struct dentry *proc_fdinfo_instantiate(struct inode *dir,
        ei->fd = fd;
        inode->i_mode = S_IFREG | S_IRUSR;
        inode->i_fop = &proc_fdinfo_file_operations;
-       inode->i_op = &proc_fdinfo_link_inode_operations;
        d_set_d_op(dentry, &tid_fd_dentry_operations);
        d_add(dentry, inode);
        /* Close the race of the process dying before we return the dentry */
index 33b1331..574d4ee 100644 (file)
@@ -189,7 +189,7 @@ xfs_end_io(
        int             error = 0;
 
        if (XFS_FORCED_SHUTDOWN(ip->i_mount)) {
-               error = -EIO;
+               ioend->io_error = -EIO;
                goto done;
        }
        if (ioend->io_error)
index 1a35138..eac97ef 100644 (file)
@@ -656,7 +656,7 @@ xfs_buf_item_committing(
 /*
  * This is the ops vector shared by all buf log items.
  */
-static struct xfs_item_ops xfs_buf_item_ops = {
+static const struct xfs_item_ops xfs_buf_item_ops = {
        .iop_size       = xfs_buf_item_size,
        .iop_format     = xfs_buf_item_format,
        .iop_pin        = xfs_buf_item_pin,
index bb3f71d..0dee0b7 100644 (file)
@@ -295,7 +295,7 @@ xfs_qm_dquot_logitem_committing(
 /*
  * This is the ops vector for dquots
  */
-static struct xfs_item_ops xfs_dquot_item_ops = {
+static const struct xfs_item_ops xfs_dquot_item_ops = {
        .iop_size       = xfs_qm_dquot_logitem_size,
        .iop_format     = xfs_qm_dquot_logitem_format,
        .iop_pin        = xfs_qm_dquot_logitem_pin,
@@ -483,7 +483,7 @@ xfs_qm_qoff_logitem_committing(
 {
 }
 
-static struct xfs_item_ops xfs_qm_qoffend_logitem_ops = {
+static const struct xfs_item_ops xfs_qm_qoffend_logitem_ops = {
        .iop_size       = xfs_qm_qoff_logitem_size,
        .iop_format     = xfs_qm_qoff_logitem_format,
        .iop_pin        = xfs_qm_qoff_logitem_pin,
@@ -498,7 +498,7 @@ static struct xfs_item_ops xfs_qm_qoffend_logitem_ops = {
 /*
  * This is the ops vector shared by all quotaoff-start log items.
  */
-static struct xfs_item_ops xfs_qm_qoff_logitem_ops = {
+static const struct xfs_item_ops xfs_qm_qoff_logitem_ops = {
        .iop_size       = xfs_qm_qoff_logitem_size,
        .iop_format     = xfs_qm_qoff_logitem_format,
        .iop_pin        = xfs_qm_qoff_logitem_pin,
index d22e626..35c2aff 100644 (file)
@@ -217,7 +217,7 @@ xfs_efi_item_committing(
 /*
  * This is the ops vector shared by all efi log items.
  */
-static struct xfs_item_ops xfs_efi_item_ops = {
+static const struct xfs_item_ops xfs_efi_item_ops = {
        .iop_size       = xfs_efi_item_size,
        .iop_format     = xfs_efi_item_format,
        .iop_pin        = xfs_efi_item_pin,
@@ -477,7 +477,7 @@ xfs_efd_item_committing(
 /*
  * This is the ops vector shared by all efd log items.
  */
-static struct xfs_item_ops xfs_efd_item_ops = {
+static const struct xfs_item_ops xfs_efd_item_ops = {
        .iop_size       = xfs_efd_item_size,
        .iop_format     = xfs_efd_item_format,
        .iop_pin        = xfs_efd_item_pin,
index b7cf21b..abaafdb 100644 (file)
@@ -795,7 +795,7 @@ xfs_inode_item_committing(
 /*
  * This is the ops vector shared by all buf log items.
  */
-static struct xfs_item_ops xfs_inode_item_ops = {
+static const struct xfs_item_ops xfs_inode_item_ops = {
        .iop_size       = xfs_inode_item_size,
        .iop_format     = xfs_inode_item_format,
        .iop_pin        = xfs_inode_item_pin,
index 2758a62..a14cd89 100644 (file)
@@ -626,7 +626,7 @@ xfs_log_item_init(
        struct xfs_mount        *mp,
        struct xfs_log_item     *item,
        int                     type,
-       struct xfs_item_ops     *ops)
+       const struct xfs_item_ops *ops)
 {
        item->li_mountp = mp;
        item->li_ailp = mp->m_ail;
index 78c9039..3f7bf45 100644 (file)
@@ -137,7 +137,7 @@ struct xfs_trans;
 void   xfs_log_item_init(struct xfs_mount      *mp,
                        struct xfs_log_item     *item,
                        int                     type,
-                       struct xfs_item_ops     *ops);
+                       const struct xfs_item_ops *ops);
 
 xfs_lsn_t xfs_log_done(struct xfs_mount *mp,
                       struct xlog_ticket *ticket,
index 5cff443..0bbb1a4 100644 (file)
@@ -674,7 +674,8 @@ xfs_qm_dqattach_one(
         * disk and we didn't ask it to allocate;
         * ESRCH if quotas got turned off suddenly.
         */
-       error = xfs_qm_dqget(ip->i_mount, ip, id, type, XFS_QMOPT_DOWARN, &dqp);
+       error = xfs_qm_dqget(ip->i_mount, ip, id, type,
+                            doalloc | XFS_QMOPT_DOWARN, &dqp);
        if (error)
                return error;
 
index 603f3eb..3ae713c 100644 (file)
@@ -326,7 +326,7 @@ typedef struct xfs_log_item {
                                                 struct xfs_log_item *);
                                                        /* buffer item iodone */
                                                        /* callback func */
-       struct xfs_item_ops             *li_ops;        /* function list */
+       const struct xfs_item_ops       *li_ops;        /* function list */
 
        /* delayed logging */
        struct list_head                li_cil;         /* CIL pointers */
@@ -341,7 +341,7 @@ typedef struct xfs_log_item {
        { XFS_LI_IN_AIL,        "IN_AIL" }, \
        { XFS_LI_ABORTED,       "ABORTED" }
 
-typedef struct xfs_item_ops {
+struct xfs_item_ops {
        uint (*iop_size)(xfs_log_item_t *);
        void (*iop_format)(xfs_log_item_t *, struct xfs_log_iovec *);
        void (*iop_pin)(xfs_log_item_t *);
@@ -352,7 +352,7 @@ typedef struct xfs_item_ops {
        void (*iop_push)(xfs_log_item_t *);
        bool (*iop_pushbuf)(xfs_log_item_t *);
        void (*iop_committing)(xfs_log_item_t *, xfs_lsn_t);
-} xfs_item_ops_t;
+};
 
 #define IOP_SIZE(ip)           (*(ip)->li_ops->iop_size)(ip)
 #define IOP_FORMAT(ip,vp)      (*(ip)->li_ops->iop_format)(ip, vp)
index 4ecf2a5..ce9268a 100644 (file)
@@ -112,7 +112,7 @@ xfs_readlink(
        char            *link)
 {
        xfs_mount_t     *mp = ip->i_mount;
-       int             pathlen;
+       xfs_fsize_t     pathlen;
        int             error = 0;
 
        trace_xfs_readlink(ip);
@@ -122,13 +122,19 @@ xfs_readlink(
 
        xfs_ilock(ip, XFS_ILOCK_SHARED);
 
-       ASSERT(S_ISLNK(ip->i_d.di_mode));
-       ASSERT(ip->i_d.di_size <= MAXPATHLEN);
-
        pathlen = ip->i_d.di_size;
        if (!pathlen)
                goto out;
 
+       if (pathlen < 0 || pathlen > MAXPATHLEN) {
+               xfs_alert(mp, "%s: inode (%llu) bad symlink length (%lld)",
+                        __func__, (unsigned long long) ip->i_ino,
+                        (long long) pathlen);
+               ASSERT(0);
+               return XFS_ERROR(EFSCORRUPTED);
+       }
+
+
        if (ip->i_df.if_flags & XFS_IFINLINE) {
                memcpy(link, ip->i_df.if_u1.if_data, pathlen);
                link[pathlen] = '\0';
index 9a6115e..49c1704 100644 (file)
@@ -64,4 +64,7 @@
 #define SO_DOMAIN              39
 
 #define SO_RXQ_OVFL             40
+
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS        SO_WIFI_STATUS
 #endif /* __ASM_GENERIC_SOCKET_H */
index cf39949..1f9e951 100644 (file)
@@ -990,7 +990,9 @@ struct drm_minor {
        struct proc_dir_entry *proc_root;  /**< proc directory entry */
        struct drm_info_node proc_nodes;
        struct dentry *debugfs_root;
-       struct drm_info_node debugfs_nodes;
+
+       struct list_head debugfs_list;
+       struct mutex debugfs_lock; /* Protects debugfs_list. */
 
        struct drm_master *master; /* currently active master for this node */
        struct list_head master_list;
index 3d53efd..f81676f 100644 (file)
@@ -4,6 +4,7 @@
 */
 #define radeon_PCI_IDS \
        {0x1002, 0x3150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
+       {0x1002, 0x3151, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x3152, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x3154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x3155, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
@@ -55,6 +56,7 @@
        {0x1002, 0x4C64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \
        {0x1002, 0x4C66, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \
        {0x1002, 0x4C67, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \
+       {0x1002, 0x4C6E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|RADEON_IS_MOBILITY}, \
        {0x1002, 0x4E44, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
        {0x1002, 0x4E45, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
        {0x1002, 0x4E46, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
index 874c4d2..1d161cb 100644 (file)
  *     - this size value would be page-aligned internally.
  * @flags: user request for setting memory type or cache attributes.
  * @handle: returned handle for the object.
+ * @pad: just padding to be 64-bit aligned.
  */
 struct drm_exynos_gem_create {
        unsigned int size;
        unsigned int flags;
        unsigned int handle;
+       unsigned int pad;
 };
 
 /**
index 619b565..0b091b3 100644 (file)
@@ -185,6 +185,7 @@ header-y += if_pppol2tp.h
 header-y += if_pppox.h
 header-y += if_slip.h
 header-y += if_strip.h
+header-y += if_team.h
 header-y += if_tr.h
 header-y += if_tun.h
 header-y += if_tunnel.h
index 49a83ca..43ea1b2 100644 (file)
@@ -452,7 +452,7 @@ void atm_dev_release_vccs(struct atm_dev *dev);
 
 static inline int atm_guess_pdu2truesize(int size)
 {
-       return SKB_DATA_ALIGN(size) + sizeof(struct skb_shared_info);
+       return SKB_TRUESIZE(size);
 }
 
 
index a3c071c..847994a 100644 (file)
@@ -211,8 +211,8 @@ extern void bio_pair_release(struct bio_pair *dbio);
 extern struct bio_set *bioset_create(unsigned int, unsigned int);
 extern void bioset_free(struct bio_set *);
 
-extern struct bio *bio_alloc(gfp_t, int);
-extern struct bio *bio_kmalloc(gfp_t, int);
+extern struct bio *bio_alloc(gfp_t, unsigned int);
+extern struct bio *bio_kmalloc(gfp_t, unsigned int);
 extern struct bio *bio_alloc_bioset(gfp_t, int, struct bio_set *);
 extern void bio_put(struct bio *);
 extern void bio_free(struct bio *, struct bio_set *);
@@ -519,7 +519,11 @@ extern void bio_integrity_init(void);
 #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, d)        (0)
+static inline int bio_integrity_clone(struct bio *bio, struct bio *bio_src,
+                                     gfp_t gfp_mask, struct bio_set *bs)
+{
+       return 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)
index ac663c1..0bd390c 100644 (file)
@@ -59,8 +59,16 @@ SUBSYS(net_cls)
 SUBSYS(blkio)
 #endif
 
+/* */
+
 #ifdef CONFIG_CGROUP_PERF
 SUBSYS(perf)
 #endif
 
 /* */
+
+#ifdef CONFIG_NETPRIO_CGROUP
+SUBSYS(net_prio)
+#endif
+
+/* */
index afb9458..98ce812 100644 (file)
@@ -41,7 +41,7 @@ struct devfreq_dev_status {
        unsigned long total_time;
        unsigned long busy_time;
        unsigned long current_frequency;
-       void *private_date;
+       void *private_data;
 };
 
 /**
index ffbcf95..52b3a41 100644 (file)
@@ -682,6 +682,11 @@ static inline bool device_async_suspend_enabled(struct device *dev)
        return !!dev->power.async_suspend;
 }
 
+static inline void pm_suspend_ignore_children(struct device *dev, bool enable)
+{
+       dev->power.ignore_children = enable;
+}
+
 static inline void device_lock(struct device *dev)
 {
        mutex_lock(&dev->mutex);
index 034072c..c9f522b 100644 (file)
@@ -17,7 +17,8 @@ struct sock_extended_err {
 #define SO_EE_ORIGIN_LOCAL     1
 #define SO_EE_ORIGIN_ICMP      2
 #define SO_EE_ORIGIN_ICMP6     3
-#define SO_EE_ORIGIN_TIMESTAMPING 4
+#define SO_EE_ORIGIN_TXSTATUS  4
+#define SO_EE_ORIGIN_TIMESTAMPING SO_EE_ORIGIN_TXSTATUS
 
 #define SO_EE_OFFENDER(ee)     ((struct sockaddr*)((ee)+1))
 
index de33de1..20db5b2 100644 (file)
@@ -724,9 +724,6 @@ enum ethtool_sfeatures_retval_bits {
 
 #include <linux/rculist.h>
 
-/* needed by dev_disable_lro() */
-extern int __ethtool_set_flags(struct net_device *dev, u32 flags);
-
 extern int __ethtool_get_settings(struct net_device *dev,
                                  struct ethtool_cmd *cmd);
 
@@ -750,19 +747,6 @@ struct net_device;
 
 /* Some generic methods drivers may use in their ethtool_ops */
 u32 ethtool_op_get_link(struct net_device *dev);
-u32 ethtool_op_get_tx_csum(struct net_device *dev);
-int ethtool_op_set_tx_csum(struct net_device *dev, u32 data);
-int ethtool_op_set_tx_hw_csum(struct net_device *dev, u32 data);
-int ethtool_op_set_tx_ipv6_csum(struct net_device *dev, u32 data);
-u32 ethtool_op_get_sg(struct net_device *dev);
-int ethtool_op_set_sg(struct net_device *dev, u32 data);
-u32 ethtool_op_get_tso(struct net_device *dev);
-int ethtool_op_set_tso(struct net_device *dev, u32 data);
-u32 ethtool_op_get_ufo(struct net_device *dev);
-int ethtool_op_set_ufo(struct net_device *dev, u32 data);
-u32 ethtool_op_get_flags(struct net_device *dev);
-int ethtool_op_set_flags(struct net_device *dev, u32 data, u32 supported);
-bool ethtool_invalid_flags(struct net_device *dev, u32 data, u32 supported);
 
 /**
  * struct ethtool_ops - optional netdev operations
@@ -807,22 +791,6 @@ bool ethtool_invalid_flags(struct net_device *dev, u32 data, u32 supported);
  * @get_pauseparam: Report pause parameters
  * @set_pauseparam: Set pause parameters.  Returns a negative error code
  *     or zero.
- * @get_rx_csum: Deprecated in favour of the netdev feature %NETIF_F_RXCSUM.
- *     Report whether receive checksums are turned on or off.
- * @set_rx_csum: Deprecated in favour of generic netdev features.  Turn
- *     receive checksum on or off.  Returns a negative error code or zero.
- * @get_tx_csum: Deprecated as redundant. Report whether transmit checksums
- *     are turned on or off.
- * @set_tx_csum: Deprecated in favour of generic netdev features.  Turn
- *     transmit checksums on or off.  Returns a negative error code or zero.
- * @get_sg: Deprecated as redundant.  Report whether scatter-gather is
- *     enabled.  
- * @set_sg: Deprecated in favour of generic netdev features.  Turn
- *     scatter-gather on or off. Returns a negative error code or zero.
- * @get_tso: Deprecated as redundant.  Report whether TCP segmentation
- *     offload is enabled.
- * @set_tso: Deprecated in favour of generic netdev features.  Turn TCP
- *     segmentation offload on or off.  Returns a negative error code or zero.
  * @self_test: Run specified self-tests
  * @get_strings: Return a set of strings that describe the requested objects
  * @set_phys_id: Identify the physical devices, e.g. by flashing an LED
@@ -844,15 +812,6 @@ bool ethtool_invalid_flags(struct net_device *dev, u32 data, u32 supported);
  *     negative error code or zero.
  * @complete: Function to be called after any other operation except
  *     @begin.  Will be called even if the other operation failed.
- * @get_ufo: Deprecated as redundant.  Report whether UDP fragmentation
- *     offload is enabled.
- * @set_ufo: Deprecated in favour of generic netdev features.  Turn UDP
- *     fragmentation offload on or off.  Returns a negative error code or zero.
- * @get_flags: Deprecated as redundant.  Report features included in
- *     &enum ethtool_flags that are enabled.  
- * @set_flags: Deprecated in favour of generic netdev features.  Turn
- *     features included in &enum ethtool_flags on or off.  Returns a
- *     negative error code or zero.
  * @get_priv_flags: Report driver-specific feature flags.
  * @set_priv_flags: Set driver-specific feature flags.  Returns a negative
  *     error code or zero.
@@ -917,14 +876,6 @@ struct ethtool_ops {
                                  struct ethtool_pauseparam*);
        int     (*set_pauseparam)(struct net_device *,
                                  struct ethtool_pauseparam*);
-       u32     (*get_rx_csum)(struct net_device *);
-       int     (*set_rx_csum)(struct net_device *, u32);
-       u32     (*get_tx_csum)(struct net_device *);
-       int     (*set_tx_csum)(struct net_device *, u32);
-       u32     (*get_sg)(struct net_device *);
-       int     (*set_sg)(struct net_device *, u32);
-       u32     (*get_tso)(struct net_device *);
-       int     (*set_tso)(struct net_device *, u32);
        void    (*self_test)(struct net_device *, struct ethtool_test *, u64 *);
        void    (*get_strings)(struct net_device *, u32 stringset, u8 *);
        int     (*set_phys_id)(struct net_device *, enum ethtool_phys_id_state);
@@ -932,10 +883,6 @@ struct ethtool_ops {
                                     struct ethtool_stats *, u64 *);
        int     (*begin)(struct net_device *);
        void    (*complete)(struct net_device *);
-       u32     (*get_ufo)(struct net_device *);
-       int     (*set_ufo)(struct net_device *, u32);
-       u32     (*get_flags)(struct net_device *);
-       int     (*set_flags)(struct net_device *, u32);
        u32     (*get_priv_flags)(struct net_device *);
        int     (*set_priv_flags)(struct net_device *, u32);
        int     (*get_sset_count)(struct net_device *, int);
index 0c4df26..e313022 100644 (file)
@@ -1886,6 +1886,7 @@ extern struct dentry *mount_single(struct file_system_type *fs_type,
 extern struct dentry *mount_nodev(struct file_system_type *fs_type,
        int flags, void *data,
        int (*fill_super)(struct super_block *, void *, int));
+extern struct dentry *mount_subtree(struct vfsmount *mnt, const char *path);
 void generic_shutdown_super(struct super_block *sb);
 void kill_block_super(struct super_block *sb);
 void kill_anon_super(struct super_block *sb);
index 9de31bc..6d18f35 100644 (file)
@@ -21,8 +21,6 @@
 #define dev_to_part(device)    container_of((device), struct hd_struct, __dev)
 #define disk_to_dev(disk)      (&(disk)->part0.__dev)
 #define part_to_dev(part)      (&((part)->__dev))
-#define alias_name(disk)       ((disk)->alias ? (disk)->alias : \
-                                                (disk)->disk_name)
 
 extern struct device_type part_type;
 extern struct kobject *block_depr;
@@ -60,7 +58,6 @@ enum {
 
 #define DISK_MAX_PARTS                 256
 #define DISK_NAME_LEN                  32
-#define ALIAS_LEN                      256
 
 #include <linux/major.h>
 #include <linux/device.h>
@@ -166,7 +163,6 @@ struct gendisk {
                                          * disks that can't be partitioned. */
 
        char disk_name[DISK_NAME_LEN];  /* name of major driver */
-       char *alias;                    /* alias name of disk */
        char *(*devnode)(struct gendisk *gd, mode_t *mode);
 
        unsigned int events;            /* supported events */
index 19644e0..d9d6c86 100644 (file)
@@ -110,11 +110,6 @@ static inline void copy_huge_page(struct page *dst, struct page *src)
 
 #define hugetlb_change_protection(vma, address, end, newprot)
 
-#ifndef HPAGE_MASK
-#define HPAGE_MASK     PAGE_MASK               /* Keep the compiler happy */
-#define HPAGE_SIZE     PAGE_SIZE
-#endif
-
 #endif /* !CONFIG_HUGETLB_PAGE */
 
 #define HUGETLB_ANON_FILE "anon_hugepage"
index 08a2fee..aad6bd4 100644 (file)
@@ -118,7 +118,6 @@ int __hwspin_trylock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
 static inline
 void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
 {
-       return 0;
 }
 
 static inline int hwspin_lock_get_id(struct hwspinlock *hwlock)
index 48363c3..66cedf6 100644 (file)
 #define IEEE80211_QOS_CTL_ACK_POLICY_NOACK     0x0020
 #define IEEE80211_QOS_CTL_ACK_POLICY_NO_EXPL   0x0040
 #define IEEE80211_QOS_CTL_ACK_POLICY_BLOCKACK  0x0060
+#define IEEE80211_QOS_CTL_ACK_POLICY_MASK      0x0060
 /* A-MSDU 802.11n */
 #define IEEE80211_QOS_CTL_A_MSDU_PRESENT       0x0080
 /* Mesh Control 802.11s */
@@ -770,6 +771,9 @@ struct ieee80211_mgmt {
        } u;
 } __attribute__ ((packed));
 
+/* Supported Rates value encodings in 802.11n-2009 7.3.2.2 */
+#define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
+
 /* mgmt header + 1 byte category code */
 #define IEEE80211_MIN_ACTION_SIZE offsetof(struct ieee80211_mgmt, u.action.u)
 
@@ -1552,6 +1556,8 @@ enum ieee80211_sa_query_action {
 #define WLAN_CIPHER_SUITE_WEP104       0x000FAC05
 #define WLAN_CIPHER_SUITE_AES_CMAC     0x000FAC06
 
+#define WLAN_CIPHER_SUITE_SMS4         0x00147201
+
 /* AKM suite selectors */
 #define WLAN_AKM_SUITE_8021X           0x000FAC01
 #define WLAN_AKM_SUITE_PSK             0x000FAC02
index db20bd4..06b6ef6 100644 (file)
@@ -79,6 +79,7 @@
 #define IFF_TX_SKB_SHARING     0x10000 /* The interface supports sharing
                                         * skbs on transmit */
 #define IFF_UNICAST_FLT        0x20000         /* Supports unicast filtering   */
+#define IFF_TEAM_PORT  0x40000         /* device used as team port */
 
 #define IF_GET_IFACE   0x0001          /* for querying only */
 #define IF_GET_PROTO   0x0002
diff --git a/include/linux/if_team.h b/include/linux/if_team.h
new file mode 100644 (file)
index 0000000..828181f
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * include/linux/if_team.h - Network team device driver header
+ * Copyright (c) 2011 Jiri Pirko <jpirko@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.
+ */
+
+#ifndef _LINUX_IF_TEAM_H_
+#define _LINUX_IF_TEAM_H_
+
+#ifdef __KERNEL__
+
+struct team_pcpu_stats {
+       u64                     rx_packets;
+       u64                     rx_bytes;
+       u64                     rx_multicast;
+       u64                     tx_packets;
+       u64                     tx_bytes;
+       struct u64_stats_sync   syncp;
+       u32                     rx_dropped;
+       u32                     tx_dropped;
+};
+
+struct team;
+
+struct team_port {
+       struct net_device *dev;
+       struct hlist_node hlist; /* node in hash list */
+       struct list_head list; /* node in ordinary list */
+       struct team *team;
+       int index;
+
+       /*
+        * A place for storing original values of the device before it
+        * become a port.
+        */
+       struct {
+               unsigned char dev_addr[MAX_ADDR_LEN];
+               unsigned int mtu;
+       } orig;
+
+       bool linkup;
+       u32 speed;
+       u8 duplex;
+
+       struct rcu_head rcu;
+};
+
+struct team_mode_ops {
+       int (*init)(struct team *team);
+       void (*exit)(struct team *team);
+       rx_handler_result_t (*receive)(struct team *team,
+                                      struct team_port *port,
+                                      struct sk_buff *skb);
+       bool (*transmit)(struct team *team, struct sk_buff *skb);
+       int (*port_enter)(struct team *team, struct team_port *port);
+       void (*port_leave)(struct team *team, struct team_port *port);
+       void (*port_change_mac)(struct team *team, struct team_port *port);
+};
+
+enum team_option_type {
+       TEAM_OPTION_TYPE_U32,
+       TEAM_OPTION_TYPE_STRING,
+};
+
+struct team_option {
+       struct list_head list;
+       const char *name;
+       enum team_option_type type;
+       int (*getter)(struct team *team, void *arg);
+       int (*setter)(struct team *team, void *arg);
+};
+
+struct team_mode {
+       struct list_head list;
+       const char *kind;
+       struct module *owner;
+       size_t priv_size;
+       const struct team_mode_ops *ops;
+};
+
+#define TEAM_PORT_HASHBITS 4
+#define TEAM_PORT_HASHENTRIES (1 << TEAM_PORT_HASHBITS)
+
+#define TEAM_MODE_PRIV_LONGS 4
+#define TEAM_MODE_PRIV_SIZE (sizeof(long) * TEAM_MODE_PRIV_LONGS)
+
+struct team {
+       struct net_device *dev; /* associated netdevice */
+       struct team_pcpu_stats __percpu *pcpu_stats;
+
+       struct mutex lock; /* used for overall locking, e.g. port lists write */
+
+       /*
+        * port lists with port count
+        */
+       int port_count;
+       struct hlist_head port_hlist[TEAM_PORT_HASHENTRIES];
+       struct list_head port_list;
+
+       struct list_head option_list;
+
+       const struct team_mode *mode;
+       struct team_mode_ops ops;
+       long mode_priv[TEAM_MODE_PRIV_LONGS];
+};
+
+static inline struct hlist_head *team_port_index_hash(struct team *team,
+                                                     int port_index)
+{
+       return &team->port_hlist[port_index & (TEAM_PORT_HASHENTRIES - 1)];
+}
+
+static inline struct team_port *team_get_port_by_index(struct team *team,
+                                                      int port_index)
+{
+       struct hlist_node *p;
+       struct team_port *port;
+       struct hlist_head *head = team_port_index_hash(team, port_index);
+
+       hlist_for_each_entry(port, p, head, hlist)
+               if (port->index == port_index)
+                       return port;
+       return NULL;
+}
+static inline struct team_port *team_get_port_by_index_rcu(struct team *team,
+                                                          int port_index)
+{
+       struct hlist_node *p;
+       struct team_port *port;
+       struct hlist_head *head = team_port_index_hash(team, port_index);
+
+       hlist_for_each_entry_rcu(port, p, head, hlist)
+               if (port->index == port_index)
+                       return port;
+       return NULL;
+}
+
+extern int team_port_set_team_mac(struct team_port *port);
+extern int team_options_register(struct team *team,
+                                const struct team_option *option,
+                                size_t option_count);
+extern void team_options_unregister(struct team *team,
+                                   const struct team_option *option,
+                                   size_t option_count);
+extern int team_mode_register(struct team_mode *mode);
+extern int team_mode_unregister(struct team_mode *mode);
+
+#endif /* __KERNEL__ */
+
+#define TEAM_STRING_MAX_LEN 32
+
+/**********************************
+ * NETLINK_GENERIC netlink family.
+ **********************************/
+
+enum {
+       TEAM_CMD_NOOP,
+       TEAM_CMD_OPTIONS_SET,
+       TEAM_CMD_OPTIONS_GET,
+       TEAM_CMD_PORT_LIST_GET,
+
+       __TEAM_CMD_MAX,
+       TEAM_CMD_MAX = (__TEAM_CMD_MAX - 1),
+};
+
+enum {
+       TEAM_ATTR_UNSPEC,
+       TEAM_ATTR_TEAM_IFINDEX,         /* u32 */
+       TEAM_ATTR_LIST_OPTION,          /* nest */
+       TEAM_ATTR_LIST_PORT,            /* nest */
+
+       __TEAM_ATTR_MAX,
+       TEAM_ATTR_MAX = __TEAM_ATTR_MAX - 1,
+};
+
+/* Nested layout of get/set msg:
+ *
+ *     [TEAM_ATTR_LIST_OPTION]
+ *             [TEAM_ATTR_ITEM_OPTION]
+ *                     [TEAM_ATTR_OPTION_*], ...
+ *             [TEAM_ATTR_ITEM_OPTION]
+ *                     [TEAM_ATTR_OPTION_*], ...
+ *             ...
+ *     [TEAM_ATTR_LIST_PORT]
+ *             [TEAM_ATTR_ITEM_PORT]
+ *                     [TEAM_ATTR_PORT_*], ...
+ *             [TEAM_ATTR_ITEM_PORT]
+ *                     [TEAM_ATTR_PORT_*], ...
+ *             ...
+ */
+
+enum {
+       TEAM_ATTR_ITEM_OPTION_UNSPEC,
+       TEAM_ATTR_ITEM_OPTION,          /* nest */
+
+       __TEAM_ATTR_ITEM_OPTION_MAX,
+       TEAM_ATTR_ITEM_OPTION_MAX = __TEAM_ATTR_ITEM_OPTION_MAX - 1,
+};
+
+enum {
+       TEAM_ATTR_OPTION_UNSPEC,
+       TEAM_ATTR_OPTION_NAME,          /* string */
+       TEAM_ATTR_OPTION_CHANGED,       /* flag */
+       TEAM_ATTR_OPTION_TYPE,          /* u8 */
+       TEAM_ATTR_OPTION_DATA,          /* dynamic */
+
+       __TEAM_ATTR_OPTION_MAX,
+       TEAM_ATTR_OPTION_MAX = __TEAM_ATTR_OPTION_MAX - 1,
+};
+
+enum {
+       TEAM_ATTR_ITEM_PORT_UNSPEC,
+       TEAM_ATTR_ITEM_PORT,            /* nest */
+
+       __TEAM_ATTR_ITEM_PORT_MAX,
+       TEAM_ATTR_ITEM_PORT_MAX = __TEAM_ATTR_ITEM_PORT_MAX - 1,
+};
+
+enum {
+       TEAM_ATTR_PORT_UNSPEC,
+       TEAM_ATTR_PORT_IFINDEX,         /* u32 */
+       TEAM_ATTR_PORT_CHANGED,         /* flag */
+       TEAM_ATTR_PORT_LINKUP,          /* flag */
+       TEAM_ATTR_PORT_SPEED,           /* u32 */
+       TEAM_ATTR_PORT_DUPLEX,          /* u8 */
+
+       __TEAM_ATTR_PORT_MAX,
+       TEAM_ATTR_PORT_MAX = __TEAM_ATTR_PORT_MAX - 1,
+};
+
+/*
+ * NETLINK_GENERIC related info
+ */
+#define TEAM_GENL_NAME "team"
+#define TEAM_GENL_VERSION 0x1
+#define TEAM_GENL_CHANGE_EVENT_MC_GRP_NAME "change_event"
+
+#endif /* _LINUX_IF_TEAM_H_ */
index 80b480c..abf5028 100644 (file)
@@ -98,9 +98,10 @@ enum {
        INET_DIAG_VEGASINFO,
        INET_DIAG_CONG,
        INET_DIAG_TOS,
+       INET_DIAG_TCLASS,
 };
 
-#define INET_DIAG_MAX INET_DIAG_TOS
+#define INET_DIAG_MAX INET_DIAG_TCLASS
 
 
 /* INET_DIAG_MEM */
index f47fcd3..c3892fc 100644 (file)
@@ -555,7 +555,6 @@ struct kvm_ppc_pvinfo {
 #define KVM_CAP_PPC_SMT 64
 #define KVM_CAP_PPC_RMA        65
 #define KVM_CAP_MAX_VCPUS 66       /* returns max vcpus per vm */
-#define KVM_CAP_PPC_HIOR 67
 #define KVM_CAP_PPC_PAPR 68
 #define KVM_CAP_S390_GMAP 71
 
index 0fe00cd..76f52bb 100644 (file)
@@ -32,6 +32,8 @@ struct mdiobb_ops {
 
 struct mdiobb_ctrl {
        const struct mdiobb_ops *ops;
+       /* reset callback */
+       int (*reset)(struct mii_bus *bus);
 };
 
 /* The returned bus is not yet registered with the phy layer. */
index e9d3fdf..7c9fe3c 100644 (file)
@@ -20,6 +20,8 @@ struct mdio_gpio_platform_data {
 
        unsigned int phy_mask;
        int irqs[PHY_MAX_ADDR];
+       /* reset callback */
+       int (*reset)(struct mii_bus *bus);
 };
 
 #endif /* __LINUX_MDIO_GPIO_H */
index fae2950..83a9cae 100644 (file)
 #define WM8958_MICB2_DISCH_WIDTH                     1  /* MICB2_DISCH */
 
 /*
+ * R210 (0xD2) - Mic Detect 3
+ */
+#define WM8958_MICD_LVL_MASK                    0x07FC  /* MICD_LVL - [10:2] */
+#define WM8958_MICD_LVL_SHIFT                        2  /* MICD_LVL - [10:2] */
+#define WM8958_MICD_LVL_WIDTH                        9  /* MICD_LVL - [10:2] */
+#define WM8958_MICD_VALID                       0x0002  /* MICD_VALID */
+#define WM8958_MICD_VALID_MASK                  0x0002  /* MICD_VALID */
+#define WM8958_MICD_VALID_SHIFT                      1  /* MICD_VALID */
+#define WM8958_MICD_VALID_WIDTH                      1  /* MICD_VALID */
+#define WM8958_MICD_STS                         0x0001  /* MICD_STS */
+#define WM8958_MICD_STS_MASK                    0x0001  /* MICD_STS */
+#define WM8958_MICD_STS_SHIFT                        0  /* MICD_STS */
+#define WM8958_MICD_STS_WIDTH                        1  /* MICD_STS */
+
+/*
  * R76 (0x4C) - Charge Pump (1)
  */
 #define WM8994_CP_ENA                           0x8000  /* CP_ENA */
index 2774823..2783eca 100644 (file)
@@ -9,6 +9,7 @@
 #define __LINUX_MII_H__
 
 #include <linux/types.h>
+#include <linux/ethtool.h>
 
 /* Generic MII registers. */
 #define MII_BMCR               0x00    /* Basic mode control register */
@@ -240,6 +241,205 @@ static inline unsigned int mii_duplex (unsigned int duplex_lock,
 }
 
 /**
+ * ethtool_adv_to_mii_adv_t
+ * @ethadv: the ethtool advertisement settings
+ *
+ * A small helper function that translates ethtool advertisement
+ * settings to phy autonegotiation advertisements for the
+ * MII_ADVERTISE register.
+ */
+static inline u32 ethtool_adv_to_mii_adv_t(u32 ethadv)
+{
+       u32 result = 0;
+
+       if (ethadv & ADVERTISED_10baseT_Half)
+               result |= ADVERTISE_10HALF;
+       if (ethadv & ADVERTISED_10baseT_Full)
+               result |= ADVERTISE_10FULL;
+       if (ethadv & ADVERTISED_100baseT_Half)
+               result |= ADVERTISE_100HALF;
+       if (ethadv & ADVERTISED_100baseT_Full)
+               result |= ADVERTISE_100FULL;
+       if (ethadv & ADVERTISED_Pause)
+               result |= ADVERTISE_PAUSE_CAP;
+       if (ethadv & ADVERTISED_Asym_Pause)
+               result |= ADVERTISE_PAUSE_ASYM;
+
+       return result;
+}
+
+/**
+ * mii_adv_to_ethtool_adv_t
+ * @adv: value of the MII_ADVERTISE register
+ *
+ * A small helper function that translates MII_ADVERTISE bits
+ * to ethtool advertisement settings.
+ */
+static inline u32 mii_adv_to_ethtool_adv_t(u32 adv)
+{
+       u32 result = 0;
+
+       if (adv & ADVERTISE_10HALF)
+               result |= ADVERTISED_10baseT_Half;
+       if (adv & ADVERTISE_10FULL)
+               result |= ADVERTISED_10baseT_Full;
+       if (adv & ADVERTISE_100HALF)
+               result |= ADVERTISED_100baseT_Half;
+       if (adv & ADVERTISE_100FULL)
+               result |= ADVERTISED_100baseT_Full;
+       if (adv & ADVERTISE_PAUSE_CAP)
+               result |= ADVERTISED_Pause;
+       if (adv & ADVERTISE_PAUSE_ASYM)
+               result |= ADVERTISED_Asym_Pause;
+
+       return result;
+}
+
+/**
+ * ethtool_adv_to_mii_ctrl1000_t
+ * @ethadv: the ethtool advertisement settings
+ *
+ * A small helper function that translates ethtool advertisement
+ * settings to phy autonegotiation advertisements for the
+ * MII_CTRL1000 register when in 1000T mode.
+ */
+static inline u32 ethtool_adv_to_mii_ctrl1000_t(u32 ethadv)
+{
+       u32 result = 0;
+
+       if (ethadv & ADVERTISED_1000baseT_Half)
+               result |= ADVERTISE_1000HALF;
+       if (ethadv & ADVERTISED_1000baseT_Full)
+               result |= ADVERTISE_1000FULL;
+
+       return result;
+}
+
+/**
+ * mii_ctrl1000_to_ethtool_adv_t
+ * @adv: value of the MII_CTRL1000 register
+ *
+ * A small helper function that translates MII_CTRL1000
+ * bits, when in 1000Base-T mode, to ethtool
+ * advertisement settings.
+ */
+static inline u32 mii_ctrl1000_to_ethtool_adv_t(u32 adv)
+{
+       u32 result = 0;
+
+       if (adv & ADVERTISE_1000HALF)
+               result |= ADVERTISED_1000baseT_Half;
+       if (adv & ADVERTISE_1000FULL)
+               result |= ADVERTISED_1000baseT_Full;
+
+       return result;
+}
+
+/**
+ * mii_lpa_to_ethtool_lpa_t
+ * @adv: value of the MII_LPA register
+ *
+ * A small helper function that translates MII_LPA
+ * bits, when in 1000Base-T mode, to ethtool
+ * LP advertisement settings.
+ */
+static inline u32 mii_lpa_to_ethtool_lpa_t(u32 lpa)
+{
+       u32 result = 0;
+
+       if (lpa & LPA_LPACK)
+               result |= ADVERTISED_Autoneg;
+
+       return result | mii_adv_to_ethtool_adv_t(lpa);
+}
+
+/**
+ * mii_stat1000_to_ethtool_lpa_t
+ * @adv: value of the MII_STAT1000 register
+ *
+ * A small helper function that translates MII_STAT1000
+ * bits, when in 1000Base-T mode, to ethtool
+ * advertisement settings.
+ */
+static inline u32 mii_stat1000_to_ethtool_lpa_t(u32 lpa)
+{
+       u32 result = 0;
+
+       if (lpa & LPA_1000HALF)
+               result |= ADVERTISED_1000baseT_Half;
+       if (lpa & LPA_1000FULL)
+               result |= ADVERTISED_1000baseT_Full;
+
+       return result;
+}
+
+/**
+ * ethtool_adv_to_mii_adv_x
+ * @ethadv: the ethtool advertisement settings
+ *
+ * A small helper function that translates ethtool advertisement
+ * settings to phy autonegotiation advertisements for the
+ * MII_CTRL1000 register when in 1000Base-X mode.
+ */
+static inline u32 ethtool_adv_to_mii_adv_x(u32 ethadv)
+{
+       u32 result = 0;
+
+       if (ethadv & ADVERTISED_1000baseT_Half)
+               result |= ADVERTISE_1000XHALF;
+       if (ethadv & ADVERTISED_1000baseT_Full)
+               result |= ADVERTISE_1000XFULL;
+       if (ethadv & ADVERTISED_Pause)
+               result |= ADVERTISE_1000XPAUSE;
+       if (ethadv & ADVERTISED_Asym_Pause)
+               result |= ADVERTISE_1000XPSE_ASYM;
+
+       return result;
+}
+
+/**
+ * mii_adv_to_ethtool_adv_x
+ * @adv: value of the MII_CTRL1000 register
+ *
+ * A small helper function that translates MII_CTRL1000
+ * bits, when in 1000Base-X mode, to ethtool
+ * advertisement settings.
+ */
+static inline u32 mii_adv_to_ethtool_adv_x(u32 adv)
+{
+       u32 result = 0;
+
+       if (adv & ADVERTISE_1000XHALF)
+               result |= ADVERTISED_1000baseT_Half;
+       if (adv & ADVERTISE_1000XFULL)
+               result |= ADVERTISED_1000baseT_Full;
+       if (adv & ADVERTISE_1000XPAUSE)
+               result |= ADVERTISED_Pause;
+       if (adv & ADVERTISE_1000XPSE_ASYM)
+               result |= ADVERTISED_Asym_Pause;
+
+       return result;
+}
+
+/**
+ * mii_lpa_to_ethtool_lpa_x
+ * @adv: value of the MII_LPA register
+ *
+ * A small helper function that translates MII_LPA
+ * bits, when in 1000Base-X mode, to ethtool
+ * LP advertisement settings.
+ */
+static inline u32 mii_lpa_to_ethtool_lpa_x(u32 lpa)
+{
+       u32 result = 0;
+
+       if (lpa & LPA_LPACK)
+               result |= ADVERTISED_Autoneg;
+
+       return result | mii_adv_to_ethtool_adv_x(lpa);
+}
+
+/**
  * mii_advertise_flowctrl - get flow control advertisement flags
  * @cap: Flow control capabilities (FLOW_CTRL_RX, FLOW_CTRL_TX or both)
  */
index a7003b7..b188f68 100644 (file)
@@ -116,6 +116,7 @@ enum {
        NDTPA_PROXY_DELAY,              /* u64, msecs */
        NDTPA_PROXY_QLEN,               /* u32 */
        NDTPA_LOCKTIME,                 /* u64, msecs */
+       NDTPA_QUEUE_LENBYTES,           /* u32 */
        __NDTPA_MAX
 };
 #define NDTPA_MAX (__NDTPA_MAX - 1)
diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h
new file mode 100644 (file)
index 0000000..77f5202
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Network device features.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _LINUX_NETDEV_FEATURES_H
+#define _LINUX_NETDEV_FEATURES_H
+
+#include <linux/types.h>
+
+typedef u64 netdev_features_t;
+
+enum {
+       NETIF_F_SG_BIT,                 /* Scatter/gather IO. */
+       NETIF_F_IP_CSUM_BIT,            /* Can checksum TCP/UDP over IPv4. */
+       __UNUSED_NETIF_F_1,
+       NETIF_F_HW_CSUM_BIT,            /* Can checksum all the packets. */
+       NETIF_F_IPV6_CSUM_BIT,          /* Can checksum TCP/UDP over IPV6 */
+       NETIF_F_HIGHDMA_BIT,            /* Can DMA to high memory. */
+       NETIF_F_FRAGLIST_BIT,           /* Scatter/gather IO. */
+       NETIF_F_HW_VLAN_TX_BIT,         /* Transmit VLAN hw acceleration */
+       NETIF_F_HW_VLAN_RX_BIT,         /* Receive VLAN hw acceleration */
+       NETIF_F_HW_VLAN_FILTER_BIT,     /* Receive filtering on VLAN */
+       NETIF_F_VLAN_CHALLENGED_BIT,    /* Device cannot handle VLAN packets */
+       NETIF_F_GSO_BIT,                /* Enable software GSO. */
+       NETIF_F_LLTX_BIT,               /* LockLess TX - deprecated. Please */
+                                       /* do not use LLTX in new drivers */
+       NETIF_F_NETNS_LOCAL_BIT,        /* Does not change network namespaces */
+       NETIF_F_GRO_BIT,                /* Generic receive offload */
+       NETIF_F_LRO_BIT,                /* large receive offload */
+
+       /**/NETIF_F_GSO_SHIFT,          /* keep the order of SKB_GSO_* bits */
+       NETIF_F_TSO_BIT                 /* ... TCPv4 segmentation */
+               = NETIF_F_GSO_SHIFT,
+       NETIF_F_UFO_BIT,                /* ... UDPv4 fragmentation */
+       NETIF_F_GSO_ROBUST_BIT,         /* ... ->SKB_GSO_DODGY */
+       NETIF_F_TSO_ECN_BIT,            /* ... TCP ECN support */
+       NETIF_F_TSO6_BIT,               /* ... TCPv6 segmentation */
+       NETIF_F_FSO_BIT,                /* ... FCoE segmentation */
+       NETIF_F_GSO_RESERVED1,          /* ... free (fill GSO_MASK to 8 bits) */
+       /**/NETIF_F_GSO_LAST,           /* [can't be last bit, see GSO_MASK] */
+       NETIF_F_GSO_RESERVED2           /* ... free (fill GSO_MASK to 8 bits) */
+               = NETIF_F_GSO_LAST,
+
+       NETIF_F_FCOE_CRC_BIT,           /* FCoE CRC32 */
+       NETIF_F_SCTP_CSUM_BIT,          /* SCTP checksum offload */
+       NETIF_F_FCOE_MTU_BIT,           /* Supports max FCoE MTU, 2158 bytes*/
+       NETIF_F_NTUPLE_BIT,             /* N-tuple filters supported */
+       NETIF_F_RXHASH_BIT,             /* Receive hashing offload */
+       NETIF_F_RXCSUM_BIT,             /* Receive checksumming offload */
+       NETIF_F_NOCACHE_COPY_BIT,       /* Use no-cache copyfromuser */
+       NETIF_F_LOOPBACK_BIT,           /* Enable loopback */
+
+       /*
+        * Add your fresh new feature above and remember to update
+        * netdev_features_strings[] in net/core/ethtool.c and maybe
+        * some feature mask #defines below. Please also describe it
+        * in Documentation/networking/netdev-features.txt.
+        */
+
+       /**/NETDEV_FEATURE_COUNT
+};
+
+/* copy'n'paste compression ;) */
+#define __NETIF_F_BIT(bit)     ((netdev_features_t)1 << (bit))
+#define __NETIF_F(name)                __NETIF_F_BIT(NETIF_F_##name##_BIT)
+
+#define NETIF_F_FCOE_CRC       __NETIF_F(FCOE_CRC)
+#define NETIF_F_FCOE_MTU       __NETIF_F(FCOE_MTU)
+#define NETIF_F_FRAGLIST       __NETIF_F(FRAGLIST)
+#define NETIF_F_FSO            __NETIF_F(FSO)
+#define NETIF_F_GRO            __NETIF_F(GRO)
+#define NETIF_F_GSO            __NETIF_F(GSO)
+#define NETIF_F_GSO_ROBUST     __NETIF_F(GSO_ROBUST)
+#define NETIF_F_HIGHDMA                __NETIF_F(HIGHDMA)
+#define NETIF_F_HW_CSUM                __NETIF_F(HW_CSUM)
+#define NETIF_F_HW_VLAN_FILTER __NETIF_F(HW_VLAN_FILTER)
+#define NETIF_F_HW_VLAN_RX     __NETIF_F(HW_VLAN_RX)
+#define NETIF_F_HW_VLAN_TX     __NETIF_F(HW_VLAN_TX)
+#define NETIF_F_IP_CSUM                __NETIF_F(IP_CSUM)
+#define NETIF_F_IPV6_CSUM      __NETIF_F(IPV6_CSUM)
+#define NETIF_F_LLTX           __NETIF_F(LLTX)
+#define NETIF_F_LOOPBACK       __NETIF_F(LOOPBACK)
+#define NETIF_F_LRO            __NETIF_F(LRO)
+#define NETIF_F_NETNS_LOCAL    __NETIF_F(NETNS_LOCAL)
+#define NETIF_F_NOCACHE_COPY   __NETIF_F(NOCACHE_COPY)
+#define NETIF_F_NTUPLE         __NETIF_F(NTUPLE)
+#define NETIF_F_RXCSUM         __NETIF_F(RXCSUM)
+#define NETIF_F_RXHASH         __NETIF_F(RXHASH)
+#define NETIF_F_SCTP_CSUM      __NETIF_F(SCTP_CSUM)
+#define NETIF_F_SG             __NETIF_F(SG)
+#define NETIF_F_TSO6           __NETIF_F(TSO6)
+#define NETIF_F_TSO_ECN                __NETIF_F(TSO_ECN)
+#define NETIF_F_TSO            __NETIF_F(TSO)
+#define NETIF_F_UFO            __NETIF_F(UFO)
+#define NETIF_F_VLAN_CHALLENGED        __NETIF_F(VLAN_CHALLENGED)
+
+/* Features valid for ethtool to change */
+/* = all defined minus driver/device-class-related */
+#define NETIF_F_NEVER_CHANGE   (NETIF_F_VLAN_CHALLENGED | \
+                                NETIF_F_LLTX | NETIF_F_NETNS_LOCAL)
+
+/* remember that ((t)1 << t_BITS) is undefined in C99 */
+#define NETIF_F_ETHTOOL_BITS   ((__NETIF_F_BIT(NETDEV_FEATURE_COUNT - 1) | \
+               (__NETIF_F_BIT(NETDEV_FEATURE_COUNT - 1) - 1)) & \
+               ~NETIF_F_NEVER_CHANGE)
+
+/* Segmentation offload feature mask */
+#define NETIF_F_GSO_MASK       (__NETIF_F_BIT(NETIF_F_GSO_LAST + 1) - \
+               __NETIF_F_BIT(NETIF_F_GSO_SHIFT))
+
+/* List of features with software fallbacks. */
+#define NETIF_F_GSO_SOFTWARE   (NETIF_F_TSO | NETIF_F_TSO_ECN | \
+                                NETIF_F_TSO6 | NETIF_F_UFO)
+
+#define NETIF_F_GEN_CSUM       NETIF_F_HW_CSUM
+#define NETIF_F_V4_CSUM                (NETIF_F_GEN_CSUM | NETIF_F_IP_CSUM)
+#define NETIF_F_V6_CSUM                (NETIF_F_GEN_CSUM | NETIF_F_IPV6_CSUM)
+#define NETIF_F_ALL_CSUM       (NETIF_F_V4_CSUM | NETIF_F_V6_CSUM)
+
+#define NETIF_F_ALL_TSO        (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN)
+
+#define NETIF_F_ALL_FCOE       (NETIF_F_FCOE_CRC | NETIF_F_FCOE_MTU | \
+                                NETIF_F_FSO)
+
+/*
+ * If one device supports one of these features, then enable them
+ * for all in netdev_increment_features.
+ */
+#define NETIF_F_ONE_FOR_ALL    (NETIF_F_GSO_SOFTWARE | NETIF_F_GSO_ROBUST | \
+                                NETIF_F_SG | NETIF_F_HIGHDMA |         \
+                                NETIF_F_FRAGLIST | NETIF_F_VLAN_CHALLENGED)
+/*
+ * If one device doesn't support one of these features, then disable it
+ * for all in netdev_increment_features.
+ */
+#define NETIF_F_ALL_FOR_ALL    (NETIF_F_NOCACHE_COPY | NETIF_F_FSO)
+
+/* changeable features with no special hardware requirements */
+#define NETIF_F_SOFT_FEATURES  (NETIF_F_GSO | NETIF_F_GRO)
+
+#endif /* _LINUX_NETDEV_FEATURES_H */
index cbeb586..999bb26 100644 (file)
@@ -50,6 +50,9 @@
 #ifdef CONFIG_DCB
 #include <net/dcbnl.h>
 #endif
+#include <net/netprio_cgroup.h>
+
+#include <linux/netdev_features.h>
 
 struct vlan_group;
 struct netpoll_info;
@@ -212,6 +215,11 @@ enum {
 #include <linux/cache.h>
 #include <linux/skbuff.h>
 
+#ifdef CONFIG_RPS
+#include <linux/jump_label.h>
+extern struct jump_label_key rps_needed;
+#endif
+
 struct neighbour;
 struct neigh_parms;
 struct sk_buff;
@@ -272,16 +280,11 @@ struct hh_cache {
  *
  * We could use other alignment values, but we must maintain the
  * relationship HH alignment <= LL alignment.
- *
- * LL_ALLOCATED_SPACE also takes into account the tailroom the device
- * may need.
  */
 #define LL_RESERVED_SPACE(dev) \
        ((((dev)->hard_header_len+(dev)->needed_headroom)&~(HH_DATA_MOD - 1)) + HH_DATA_MOD)
 #define LL_RESERVED_SPACE_EXTRA(dev,extra) \
        ((((dev)->hard_header_len+(dev)->needed_headroom+(extra))&~(HH_DATA_MOD - 1)) + HH_DATA_MOD)
-#define LL_ALLOCATED_SPACE(dev) \
-       ((((dev)->hard_header_len+(dev)->needed_headroom+(dev)->needed_tailroom)&~(HH_DATA_MOD - 1)) + HH_DATA_MOD)
 
 struct header_ops {
        int     (*create) (struct sk_buff *skb, struct net_device *dev,
@@ -530,7 +533,7 @@ struct netdev_queue {
        struct Qdisc            *qdisc;
        unsigned long           state;
        struct Qdisc            *qdisc_sleeping;
-#if defined(CONFIG_RPS) || defined(CONFIG_XPS)
+#ifdef CONFIG_SYSFS
        struct kobject          kobj;
 #endif
 #if defined(CONFIG_XPS) && defined(CONFIG_NUMA)
@@ -545,6 +548,12 @@ struct netdev_queue {
         * please use this field instead of dev->trans_start
         */
        unsigned long           trans_start;
+
+       /*
+        * Number of TX timeouts for this queue
+        * (/sys/class/net/DEV/Q/trans_timeout)
+        */
+       unsigned long           trans_timeout;
 } ____cacheline_aligned_in_smp;
 
 static inline int netdev_queue_numa_node_read(const struct netdev_queue *q)
@@ -845,12 +854,13 @@ struct netdev_tc_txq {
  *     Called to release previously enslaved netdev.
  *
  *      Feature/offload setting functions.
- * u32 (*ndo_fix_features)(struct net_device *dev, u32 features);
+ * netdev_features_t (*ndo_fix_features)(struct net_device *dev,
+ *             netdev_features_t features);
  *     Adjusts the requested feature flags according to device-specific
  *     constraints, and returns the resulting flags. Must not modify
  *     the device state.
  *
- * int (*ndo_set_features)(struct net_device *dev, u32 features);
+ * int (*ndo_set_features)(struct net_device *dev, netdev_features_t features);
  *     Called to update device configuration to new features. Passed
  *     feature set might be less than what was returned by ndo_fix_features()).
  *     Must return >0 or -errno if it changed dev->features itself.
@@ -944,10 +954,10 @@ struct net_device_ops {
                                                 struct net_device *slave_dev);
        int                     (*ndo_del_slave)(struct net_device *dev,
                                                 struct net_device *slave_dev);
-       u32                     (*ndo_fix_features)(struct net_device *dev,
-                                                   u32 features);
+       netdev_features_t       (*ndo_fix_features)(struct net_device *dev,
+                                                   netdev_features_t features);
        int                     (*ndo_set_features)(struct net_device *dev,
-                                                   u32 features);
+                                                   netdev_features_t features);
 };
 
 /*
@@ -997,91 +1007,13 @@ struct net_device {
        struct list_head        unreg_list;
 
        /* currently active device features */
-       u32                     features;
+       netdev_features_t       features;
        /* user-changeable features */
-       u32                     hw_features;
+       netdev_features_t       hw_features;
        /* user-requested features */
-       u32                     wanted_features;
+       netdev_features_t       wanted_features;
        /* mask of features inheritable by VLAN devices */
-       u32                     vlan_features;
-
-       /* Net device feature bits; if you change something,
-        * also update netdev_features_strings[] in ethtool.c */
-
-#define NETIF_F_SG             1       /* Scatter/gather IO. */
-#define NETIF_F_IP_CSUM                2       /* Can checksum TCP/UDP over IPv4. */
-#define NETIF_F_NO_CSUM                4       /* Does not require checksum. F.e. loopack. */
-#define NETIF_F_HW_CSUM                8       /* Can checksum all the packets. */
-#define NETIF_F_IPV6_CSUM      16      /* Can checksum TCP/UDP over IPV6 */
-#define NETIF_F_HIGHDMA                32      /* Can DMA to high memory. */
-#define NETIF_F_FRAGLIST       64      /* Scatter/gather IO. */
-#define NETIF_F_HW_VLAN_TX     128     /* Transmit VLAN hw acceleration */
-#define NETIF_F_HW_VLAN_RX     256     /* Receive VLAN hw acceleration */
-#define NETIF_F_HW_VLAN_FILTER 512     /* Receive filtering on VLAN */
-#define NETIF_F_VLAN_CHALLENGED        1024    /* Device cannot handle VLAN packets */
-#define NETIF_F_GSO            2048    /* Enable software GSO. */
-#define NETIF_F_LLTX           4096    /* LockLess TX - deprecated. Please */
-                                       /* do not use LLTX in new drivers */
-#define NETIF_F_NETNS_LOCAL    8192    /* Does not change network namespaces */
-#define NETIF_F_GRO            16384   /* Generic receive offload */
-#define NETIF_F_LRO            32768   /* large receive offload */
-
-/* the GSO_MASK reserves bits 16 through 23 */
-#define NETIF_F_FCOE_CRC       (1 << 24) /* FCoE CRC32 */
-#define NETIF_F_SCTP_CSUM      (1 << 25) /* SCTP checksum offload */
-#define NETIF_F_FCOE_MTU       (1 << 26) /* Supports max FCoE MTU, 2158 bytes*/
-#define NETIF_F_NTUPLE         (1 << 27) /* N-tuple filters supported */
-#define NETIF_F_RXHASH         (1 << 28) /* Receive hashing offload */
-#define NETIF_F_RXCSUM         (1 << 29) /* Receive checksumming offload */
-#define NETIF_F_NOCACHE_COPY   (1 << 30) /* Use no-cache copyfromuser */
-#define NETIF_F_LOOPBACK       (1 << 31) /* Enable loopback */
-
-       /* Segmentation offload features */
-#define NETIF_F_GSO_SHIFT      16
-#define NETIF_F_GSO_MASK       0x00ff0000
-#define NETIF_F_TSO            (SKB_GSO_TCPV4 << NETIF_F_GSO_SHIFT)
-#define NETIF_F_UFO            (SKB_GSO_UDP << NETIF_F_GSO_SHIFT)
-#define NETIF_F_GSO_ROBUST     (SKB_GSO_DODGY << NETIF_F_GSO_SHIFT)
-#define NETIF_F_TSO_ECN                (SKB_GSO_TCP_ECN << NETIF_F_GSO_SHIFT)
-#define NETIF_F_TSO6           (SKB_GSO_TCPV6 << NETIF_F_GSO_SHIFT)
-#define NETIF_F_FSO            (SKB_GSO_FCOE << NETIF_F_GSO_SHIFT)
-
-       /* Features valid for ethtool to change */
-       /* = all defined minus driver/device-class-related */
-#define NETIF_F_NEVER_CHANGE   (NETIF_F_VLAN_CHALLENGED | \
-                                 NETIF_F_LLTX | NETIF_F_NETNS_LOCAL)
-#define NETIF_F_ETHTOOL_BITS   (0xff3fffff & ~NETIF_F_NEVER_CHANGE)
-
-       /* List of features with software fallbacks. */
-#define NETIF_F_GSO_SOFTWARE   (NETIF_F_TSO | NETIF_F_TSO_ECN | \
-                                NETIF_F_TSO6 | NETIF_F_UFO)
-
-
-#define NETIF_F_GEN_CSUM       (NETIF_F_NO_CSUM | NETIF_F_HW_CSUM)
-#define NETIF_F_V4_CSUM                (NETIF_F_GEN_CSUM | NETIF_F_IP_CSUM)
-#define NETIF_F_V6_CSUM                (NETIF_F_GEN_CSUM | NETIF_F_IPV6_CSUM)
-#define NETIF_F_ALL_CSUM       (NETIF_F_V4_CSUM | NETIF_F_V6_CSUM)
-
-#define NETIF_F_ALL_TSO        (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN)
-
-#define NETIF_F_ALL_FCOE       (NETIF_F_FCOE_CRC | NETIF_F_FCOE_MTU | \
-                                NETIF_F_FSO)
-
-       /*
-        * If one device supports one of these features, then enable them
-        * for all in netdev_increment_features.
-        */
-#define NETIF_F_ONE_FOR_ALL    (NETIF_F_GSO_SOFTWARE | NETIF_F_GSO_ROBUST | \
-                                NETIF_F_SG | NETIF_F_HIGHDMA |         \
-                                NETIF_F_FRAGLIST | NETIF_F_VLAN_CHALLENGED)
-       /*
-        * If one device doesn't support one of these features, then disable it
-        * for all in netdev_increment_features.
-        */
-#define NETIF_F_ALL_FOR_ALL    (NETIF_F_NOCACHE_COPY | NETIF_F_FSO)
-
-       /* changeable features with no special hardware requirements */
-#define NETIF_F_SOFT_FEATURES  (NETIF_F_GSO | NETIF_F_GRO)
+       netdev_features_t       vlan_features;
 
        /* Interface index. Unique device identifier    */
        int                     ifindex;
@@ -1184,9 +1116,11 @@ struct net_device {
 
        unsigned char           broadcast[MAX_ADDR_LEN];        /* hw bcast add */
 
-#if defined(CONFIG_RPS) || defined(CONFIG_XPS)
+#ifdef CONFIG_SYSFS
        struct kset             *queues_kset;
+#endif
 
+#ifdef CONFIG_RPS
        struct netdev_rx_queue  *_rx;
 
        /* Number of RX queues allocated at register_netdev() time */
@@ -1312,6 +1246,9 @@ struct net_device {
        /* max exchange id for FCoE LRO by ddp */
        unsigned int            fcoe_ddp_xid;
 #endif
+#if IS_ENABLED(CONFIG_NETPRIO_CGROUP)
+       struct netprio_map __rcu *priomap;
+#endif
        /* phy device may attach itself for hardware timestamping */
        struct phy_device *phydev;
 
@@ -1515,7 +1452,7 @@ struct packet_type {
                                         struct packet_type *,
                                         struct net_device *);
        struct sk_buff          *(*gso_segment)(struct sk_buff *skb,
-                                               u32 features);
+                                               netdev_features_t features);
        int                     (*gso_send_check)(struct sk_buff *skb);
        struct sk_buff          **(*gro_receive)(struct sk_buff **head,
                                               struct sk_buff *skb);
@@ -2520,7 +2457,8 @@ extern int                netdev_set_master(struct net_device *dev, struct net_device *master)
 extern int netdev_set_bond_master(struct net_device *dev,
                                  struct net_device *master);
 extern int skb_checksum_help(struct sk_buff *skb);
-extern struct sk_buff *skb_gso_segment(struct sk_buff *skb, u32 features);
+extern struct sk_buff *skb_gso_segment(struct sk_buff *skb,
+       netdev_features_t features);
 #ifdef CONFIG_BUG
 extern void netdev_rx_csum_fault(struct net_device *dev);
 #else
@@ -2547,11 +2485,13 @@ extern const char *netdev_drivername(const struct net_device *dev);
 
 extern void linkwatch_run_queue(void);
 
-static inline u32 netdev_get_wanted_features(struct net_device *dev)
+static inline netdev_features_t netdev_get_wanted_features(
+       struct net_device *dev)
 {
        return (dev->features & ~dev->hw_features) | dev->wanted_features;
 }
-u32 netdev_increment_features(u32 all, u32 one, u32 mask);
+netdev_features_t netdev_increment_features(netdev_features_t all,
+       netdev_features_t one, netdev_features_t mask);
 int __netdev_update_features(struct net_device *dev);
 void netdev_update_features(struct net_device *dev);
 void netdev_change_features(struct net_device *dev);
@@ -2559,21 +2499,31 @@ void netdev_change_features(struct net_device *dev);
 void netif_stacked_transfer_operstate(const struct net_device *rootdev,
                                        struct net_device *dev);
 
-u32 netif_skb_features(struct sk_buff *skb);
+netdev_features_t netif_skb_features(struct sk_buff *skb);
 
-static inline int net_gso_ok(u32 features, int gso_type)
+static inline int net_gso_ok(netdev_features_t features, int gso_type)
 {
-       int feature = gso_type << NETIF_F_GSO_SHIFT;
+       netdev_features_t feature = gso_type << NETIF_F_GSO_SHIFT;
+
+       /* check flags correspondence */
+       BUILD_BUG_ON(SKB_GSO_TCPV4   != (NETIF_F_TSO >> NETIF_F_GSO_SHIFT));
+       BUILD_BUG_ON(SKB_GSO_UDP     != (NETIF_F_UFO >> NETIF_F_GSO_SHIFT));
+       BUILD_BUG_ON(SKB_GSO_DODGY   != (NETIF_F_GSO_ROBUST >> NETIF_F_GSO_SHIFT));
+       BUILD_BUG_ON(SKB_GSO_TCP_ECN != (NETIF_F_TSO_ECN >> NETIF_F_GSO_SHIFT));
+       BUILD_BUG_ON(SKB_GSO_TCPV6   != (NETIF_F_TSO6 >> NETIF_F_GSO_SHIFT));
+       BUILD_BUG_ON(SKB_GSO_FCOE    != (NETIF_F_FSO >> NETIF_F_GSO_SHIFT));
+
        return (features & feature) == feature;
 }
 
-static inline int skb_gso_ok(struct sk_buff *skb, u32 features)
+static inline int skb_gso_ok(struct sk_buff *skb, netdev_features_t features)
 {
        return net_gso_ok(features, skb_shinfo(skb)->gso_type) &&
               (!skb_has_frag_list(skb) || (features & NETIF_F_FRAGLIST));
 }
 
-static inline int netif_needs_gso(struct sk_buff *skb, int features)
+static inline int netif_needs_gso(struct sk_buff *skb,
+       netdev_features_t features)
 {
        return skb_is_gso(skb) && (!skb_gso_ok(skb, features) ||
                unlikely(skb->ip_summed != CHECKSUM_PARTIAL));
@@ -2592,22 +2542,6 @@ static inline int netif_is_bond_slave(struct net_device *dev)
 
 extern struct pernet_operations __net_initdata loopback_net_ops;
 
-static inline u32 dev_ethtool_get_rx_csum(struct net_device *dev)
-{
-       if (dev->features & NETIF_F_RXCSUM)
-               return 1;
-       if (!dev->ethtool_ops || !dev->ethtool_ops->get_rx_csum)
-               return 0;
-       return dev->ethtool_ops->get_rx_csum(dev);
-}
-
-static inline u32 dev_ethtool_get_flags(struct net_device *dev)
-{
-       if (!dev->ethtool_ops || !dev->ethtool_ops->get_flags)
-               return 0;
-       return dev->ethtool_ops->get_flags(dev);
-}
-
 /* Logging, debugging and troubleshooting/diagnostic helpers. */
 
 /* netdev_printk helpers, similar to dev_printk */
index 857f502..b809265 100644 (file)
@@ -162,6 +162,24 @@ extern struct ctl_path nf_net_ipv4_netfilter_sysctl_path[];
 
 extern struct list_head nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
 
+#if defined(CONFIG_JUMP_LABEL)
+#include <linux/jump_label.h>
+extern struct jump_label_key nf_hooks_needed[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
+static inline bool nf_hooks_active(u_int8_t pf, unsigned int hook)
+{
+       if (__builtin_constant_p(pf) &&
+           __builtin_constant_p(hook))
+               return static_branch(&nf_hooks_needed[pf][hook]);
+
+       return !list_empty(&nf_hooks[pf][hook]);
+}
+#else
+static inline bool nf_hooks_active(u_int8_t pf, unsigned int hook)
+{
+       return !list_empty(&nf_hooks[pf][hook]);
+}
+#endif
+
 int nf_hook_slow(u_int8_t pf, unsigned int hook, struct sk_buff *skb,
                 struct net_device *indev, struct net_device *outdev,
                 int (*okfn)(struct sk_buff *), int thresh);
@@ -179,11 +197,9 @@ static inline int nf_hook_thresh(u_int8_t pf, unsigned int hook,
                                 struct net_device *outdev,
                                 int (*okfn)(struct sk_buff *), int thresh)
 {
-#ifndef CONFIG_NETFILTER_DEBUG
-       if (list_empty(&nf_hooks[pf][hook]))
-               return 1;
-#endif
-       return nf_hook_slow(pf, hook, skb, indev, outdev, okfn, thresh);
+       if (nf_hooks_active(pf, hook))
+               return nf_hook_slow(pf, hook, skb, indev, outdev, okfn, thresh);
+       return 1;
 }
 
 static inline int nf_hook(u_int8_t pf, unsigned int hook, struct sk_buff *skb,
index 8049bf7..f9261c2 100644 (file)
  * @NL80211_CMD_TDLS_OPER: Perform a high-level TDLS command (e.g. link setup).
  * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame.
  *
+ * @NL80211_CMD_UNEXPECTED_FRAME: Used by an application controlling an AP
+ *     (or GO) interface (i.e. hostapd) to ask for unexpected frames to
+ *     implement sending deauth to stations that send unexpected class 3
+ *     frames. Also used as the event sent by the kernel when such a frame
+ *     is received.
+ *     For the event, the %NL80211_ATTR_MAC attribute carries the TA and
+ *     other attributes like the interface index are present.
+ *     If used as the command it must have an interface index and you can
+ *     only unsubscribe from the event by closing the socket. Subscription
+ *     is also for %NL80211_CMD_UNEXPECTED_4ADDR_FRAME events.
+ *
+ * @NL80211_CMD_UNEXPECTED_4ADDR_FRAME: Sent as an event indicating that the
+ *     associated station identified by %NL80211_ATTR_MAC sent a 4addr frame
+ *     and wasn't already in a 4-addr VLAN. The event will be sent similarly
+ *     to the %NL80211_CMD_UNEXPECTED_FRAME event, to the same listener.
+ *
+ * @NL80211_CMD_PROBE_CLIENT: Probe an associated station on an AP interface
+ *     by sending a null data frame to it and reporting when the frame is
+ *     acknowleged. This is used to allow timing out inactive clients. Uses
+ *     %NL80211_ATTR_IFINDEX and %NL80211_ATTR_MAC. The command returns a
+ *     direct reply with an %NL80211_ATTR_COOKIE that is later used to match
+ *     up the event with the request. The event includes the same data and
+ *     has %NL80211_ATTR_ACK set if the frame was ACKed.
+ *
+ * @NL80211_CMD_REGISTER_BEACONS: Register this socket to receive beacons from
+ *     other BSSes when any interfaces are in AP mode. This helps implement
+ *     OLBC handling in hostapd. Beacons are reported in %NL80211_CMD_FRAME
+ *     messages. Note that per PHY only one application may register.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -638,6 +667,14 @@ enum nl80211_commands {
        NL80211_CMD_TDLS_OPER,
        NL80211_CMD_TDLS_MGMT,
 
+       NL80211_CMD_UNEXPECTED_FRAME,
+
+       NL80211_CMD_PROBE_CLIENT,
+
+       NL80211_CMD_REGISTER_BEACONS,
+
+       NL80211_CMD_UNEXPECTED_4ADDR_FRAME,
+
        /* add new commands above here */
 
        /* used to define NL80211_CMD_MAX below */
@@ -658,6 +695,8 @@ enum nl80211_commands {
 #define NL80211_CMD_DISASSOCIATE NL80211_CMD_DISASSOCIATE
 #define NL80211_CMD_REG_BEACON_HINT NL80211_CMD_REG_BEACON_HINT
 
+#define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS
+
 /* source-level API compatibility */
 #define NL80211_CMD_GET_MESH_PARAMS NL80211_CMD_GET_MESH_CONFIG
 #define NL80211_CMD_SET_MESH_PARAMS NL80211_CMD_SET_MESH_CONFIG
@@ -1109,6 +1148,28 @@ enum nl80211_commands {
  *     %NL80211_CMD_TDLS_MGMT. Otherwise %NL80211_CMD_TDLS_OPER should be
  *     used for asking the driver to perform a TDLS operation.
  *
+ * @NL80211_ATTR_DEVICE_AP_SME: This u32 attribute may be listed for devices
+ *     that have AP support to indicate that they have the AP SME integrated
+ *     with support for the features listed in this attribute, see
+ *     &enum nl80211_ap_sme_features.
+ *
+ * @NL80211_ATTR_DONT_WAIT_FOR_ACK: Used with %NL80211_CMD_FRAME, this tells
+ *     the driver to not wait for an acknowledgement. Note that due to this,
+ *     it will also not give a status callback nor return a cookie. This is
+ *     mostly useful for probe responses to save airtime.
+ *
+ * @NL80211_ATTR_FEATURE_FLAGS: This u32 attribute contains flags from
+ *     &enum nl80211_feature_flags and is advertised in wiphy information.
+ * @NL80211_ATTR_PROBE_RESP_OFFLOAD: Indicates that the HW responds to probe
+ *
+ *     requests while operating in AP-mode.
+ *     This attribute holds a bitmap of the supported protocols for
+ *     offloading (see &enum nl80211_probe_resp_offload_support_attr).
+ *
+ * @NL80211_ATTR_PROBE_RESP: Probe Response template data. Contains the entire
+ *     probe-response frame. The DA field in the 802.11 header is zero-ed out,
+ *     to be filled by the FW.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1337,6 +1398,16 @@ enum nl80211_attrs {
        NL80211_ATTR_TDLS_SUPPORT,
        NL80211_ATTR_TDLS_EXTERNAL_SETUP,
 
+       NL80211_ATTR_DEVICE_AP_SME,
+
+       NL80211_ATTR_DONT_WAIT_FOR_ACK,
+
+       NL80211_ATTR_FEATURE_FLAGS,
+
+       NL80211_ATTR_PROBE_RESP_OFFLOAD,
+
+       NL80211_ATTR_PROBE_RESP,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -1371,6 +1442,7 @@ enum nl80211_attrs {
 #define NL80211_ATTR_AKM_SUITES NL80211_ATTR_AKM_SUITES
 #define NL80211_ATTR_KEY NL80211_ATTR_KEY
 #define NL80211_ATTR_KEYS NL80211_ATTR_KEYS
+#define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS
 
 #define NL80211_MAX_SUPP_RATES                 32
 #define NL80211_MAX_SUPP_REG_RULES             32
@@ -2650,4 +2722,43 @@ enum nl80211_tdls_operation {
        NL80211_TDLS_DISABLE_LINK,
 };
 
+/*
+ * enum nl80211_ap_sme_features - device-integrated AP features
+ * Reserved for future use, no bits are defined in
+ * NL80211_ATTR_DEVICE_AP_SME yet.
+enum nl80211_ap_sme_features {
+};
+ */
+
+/**
+ * enum nl80211_feature_flags - device/driver features
+ * @NL80211_FEATURE_SK_TX_STATUS: This driver supports reflecting back
+ *     TX status to the socket error queue when requested with the
+ *     socket option.
+ */
+enum nl80211_feature_flags {
+       NL80211_FEATURE_SK_TX_STATUS    = 1 << 0,
+};
+
+/**
+ * enum nl80211_probe_resp_offload_support_attr - optional supported
+ *     protocols for probe-response offloading by the driver/FW.
+ *     To be used with the %NL80211_ATTR_PROBE_RESP_OFFLOAD attribute.
+ *     Each enum value represents a bit in the bitmap of supported
+ *     protocols. Typically a subset of probe-requests belonging to a
+ *     supported protocol will be excluded from offload and uploaded
+ *     to the host.
+ *
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS: Support for WPS ver. 1
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2: Support for WPS ver. 2
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P: Support for P2P
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U: Support for 802.11u
+ */
+enum nl80211_probe_resp_offload_support_attr {
+       NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS =        1<<0,
+       NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 =       1<<1,
+       NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P =        1<<2,
+       NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U =     1<<3,
+};
+
 #endif /* __LINUX_NL80211_H */
index 3fdf251..172ba70 100644 (file)
 
 #define PCI_VENDOR_ID_AZWAVE           0x1a3b
 
+#define PCI_VENDOR_ID_ASMEDIA          0x1b21
+
 #define PCI_VENDOR_ID_TEKRAM           0x1de1
 #define PCI_DEVICE_ID_TEKRAM_DC290     0xdc29
 
index f53a416..f48bfc8 100644 (file)
@@ -38,6 +38,7 @@
 #define PNPIPE_ENCAP           1
 #define PNPIPE_IFINDEX         2
 #define PNPIPE_HANDLE          3
+#define PNPIPE_INITSTATE       4
 
 #define PNADDR_ANY             0
 #define PNADDR_BROADCAST       0xFC
@@ -49,6 +50,7 @@
 
 /* ioctls */
 #define SIOCPNGETOBJECT                (SIOCPROTOPRIVATE + 0)
+#define SIOCPNENABLEPIPE       (SIOCPROTOPRIVATE + 13)
 #define SIOCPNADDRESOURCE      (SIOCPROTOPRIVATE + 14)
 #define SIOCPNDELRESOURCE      (SIOCPROTOPRIVATE + 15)
 
index 3605e94..04c0110 100644 (file)
@@ -121,6 +121,7 @@ extern const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev);
 extern void *pinctrl_dev_get_drvdata(struct pinctrl_dev *pctldev);
 #else
 
+struct pinctrl_dev;
 
 /* Sufficiently stupid default function when pinctrl is not in use */
 static inline bool pin_is_valid(struct pinctrl_dev *pctldev, int pin)
index f15acb6..5c4c8b1 100644 (file)
@@ -447,6 +447,7 @@ struct dev_pm_info {
        unsigned int            async_suspend:1;
        bool                    is_prepared:1;  /* Owned by the PM core */
        bool                    is_suspended:1; /* Ditto */
+       bool                    ignore_children:1;
        spinlock_t              lock;
 #ifdef CONFIG_PM_SLEEP
        struct list_head        entry;
@@ -464,7 +465,6 @@ struct dev_pm_info {
        atomic_t                usage_count;
        atomic_t                child_count;
        unsigned int            disable_depth:3;
-       unsigned int            ignore_children:1;
        unsigned int            idle_notification:1;
        unsigned int            request_pending:1;
        unsigned int            deferred_resume:1;
index d8d9036..d3085e7 100644 (file)
@@ -52,11 +52,6 @@ static inline bool pm_children_suspended(struct device *dev)
                || !atomic_read(&dev->power.child_count);
 }
 
-static inline void pm_suspend_ignore_children(struct device *dev, bool enable)
-{
-       dev->power.ignore_children = enable;
-}
-
 static inline void pm_runtime_get_noresume(struct device *dev)
 {
        atomic_inc(&dev->power.usage_count);
@@ -130,7 +125,6 @@ static inline void pm_runtime_allow(struct device *dev) {}
 static inline void pm_runtime_forbid(struct device *dev) {}
 
 static inline bool pm_children_suspended(struct device *dev) { return false; }
-static inline void pm_suspend_ignore_children(struct device *dev, bool en) {}
 static inline void pm_runtime_get_noresume(struct device *dev) {}
 static inline void pm_runtime_put_noidle(struct device *dev) {}
 static inline bool device_run_wake(struct device *dev) { return false; }
index 0efa1f1..369273a 100644 (file)
@@ -67,6 +67,7 @@ enum {
        SCIx_IRDA_REGTYPE,
        SCIx_SCIFA_REGTYPE,
        SCIx_SCIFB_REGTYPE,
+       SCIx_SH2_SCIF_FIFODATA_REGTYPE,
        SCIx_SH3_SCIF_REGTYPE,
        SCIx_SH4_SCIF_REGTYPE,
        SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
index 3ccf186..a20831c 100644 (file)
@@ -52,7 +52,6 @@ struct clk {
 
        unsigned long           arch_flags;
        void                    *priv;
-       struct dentry           *dentry;
        struct clk_mapping      *mapping;
        struct cpufreq_frequency_table *freq_table;
        unsigned int            nr_freqs;
@@ -94,6 +93,9 @@ int clk_rate_table_find(struct clk *clk,
 long clk_rate_div_range_round(struct clk *clk, unsigned int div_min,
                              unsigned int div_max, unsigned long rate);
 
+long clk_rate_mult_range_round(struct clk *clk, unsigned int mult_min,
+                              unsigned int mult_max, unsigned long rate);
+
 long clk_round_parent(struct clk *clk, unsigned long target,
                      unsigned long *best_freq, unsigned long *parent_freq,
                      unsigned int div_min, unsigned int div_max);
index bc8c920..8446789 100644 (file)
@@ -104,4 +104,80 @@ struct pinmux_info {
 int register_pinmux(struct pinmux_info *pip);
 int unregister_pinmux(struct pinmux_info *pip);
 
+/* helper macro for port */
+#define PORT_1(fn, pfx, sfx) fn(pfx, sfx)
+
+#define PORT_10(fn, pfx, sfx) \
+       PORT_1(fn, pfx##0, sfx), PORT_1(fn, pfx##1, sfx),       \
+       PORT_1(fn, pfx##2, sfx), PORT_1(fn, pfx##3, sfx),       \
+       PORT_1(fn, pfx##4, sfx), PORT_1(fn, pfx##5, sfx),       \
+       PORT_1(fn, pfx##6, sfx), PORT_1(fn, pfx##7, sfx),       \
+       PORT_1(fn, pfx##8, sfx), PORT_1(fn, pfx##9, sfx)
+
+#define PORT_90(fn, pfx, sfx) \
+       PORT_10(fn, pfx##1, sfx), PORT_10(fn, pfx##2, sfx),     \
+       PORT_10(fn, pfx##3, sfx), PORT_10(fn, pfx##4, sfx),     \
+       PORT_10(fn, pfx##5, sfx), PORT_10(fn, pfx##6, sfx),     \
+       PORT_10(fn, pfx##7, sfx), PORT_10(fn, pfx##8, sfx),     \
+       PORT_10(fn, pfx##9, sfx)
+
+#define _PORT_ALL(pfx, sfx) pfx##_##sfx
+#define _GPIO_PORT(pfx, sfx) PINMUX_GPIO(GPIO_PORT##pfx, PORT##pfx##_DATA)
+#define PORT_ALL(str)  CPU_ALL_PORT(_PORT_ALL, PORT, str)
+#define GPIO_PORT_ALL()        CPU_ALL_PORT(_GPIO_PORT, , unused)
+#define GPIO_FN(str) PINMUX_GPIO(GPIO_FN_##str, str##_MARK)
+
+/* helper macro for pinmux_enum_t */
+#define PORT_DATA_I(nr)        \
+       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0, PORT##nr##_IN)
+
+#define PORT_DATA_I_PD(nr)     \
+       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0,    \
+                   PORT##nr##_IN, PORT##nr##_IN_PD)
+
+#define PORT_DATA_I_PU(nr)     \
+       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0,    \
+                   PORT##nr##_IN, PORT##nr##_IN_PU)
+
+#define PORT_DATA_I_PU_PD(nr)  \
+       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0,                    \
+                   PORT##nr##_IN, PORT##nr##_IN_PD, PORT##nr##_IN_PU)
+
+#define PORT_DATA_O(nr)                \
+       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0, PORT##nr##_OUT)
+
+#define PORT_DATA_IO(nr)       \
+       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0, PORT##nr##_OUT,    \
+                   PORT##nr##_IN)
+
+#define PORT_DATA_IO_PD(nr)    \
+       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0, PORT##nr##_OUT,    \
+                   PORT##nr##_IN, PORT##nr##_IN_PD)
+
+#define PORT_DATA_IO_PU(nr)    \
+       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0, PORT##nr##_OUT,    \
+                   PORT##nr##_IN, PORT##nr##_IN_PU)
+
+#define PORT_DATA_IO_PU_PD(nr) \
+       PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0, PORT##nr##_OUT,    \
+                   PORT##nr##_IN, PORT##nr##_IN_PD, PORT##nr##_IN_PU)
+
+/* helper macro for top 4 bits in PORTnCR */
+#define _PCRH(in, in_pd, in_pu, out)   \
+       0, (out), (in), 0,              \
+       0, 0, 0, 0,                     \
+       0, 0, (in_pd), 0,               \
+       0, 0, (in_pu), 0
+
+#define PORTCR(nr, reg)                                                        \
+       {                                                               \
+               PINMUX_CFG_REG("PORT" nr "CR", reg, 8, 4) {             \
+                       _PCRH(PORT##nr##_IN, PORT##nr##_IN_PD,          \
+                             PORT##nr##_IN_PU, PORT##nr##_OUT),        \
+                               PORT##nr##_FN0, PORT##nr##_FN1,         \
+                               PORT##nr##_FN2, PORT##nr##_FN3,         \
+                               PORT##nr##_FN4, PORT##nr##_FN5,         \
+                               PORT##nr##_FN6, PORT##nr##_FN7 }        \
+       }
+
 #endif /* __SH_PFC_H */
index fe86488..cec0657 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/dmaengine.h>
 #include <linux/hrtimer.h>
 #include <linux/dma-mapping.h>
+#include <linux/netdev_features.h>
 
 /* Don't change this without changing skb_csum_unnecessary! */
 #define CHECKSUM_NONE 0
@@ -87,7 +88,6 @@
  *     at device setup time.
  *     NETIF_F_HW_CSUM - it is clever device, it is able to checksum
  *                       everything.
- *     NETIF_F_NO_CSUM - loopback or reliable single hop media.
  *     NETIF_F_IP_CSUM - device is dumb. It is able to csum only
  *                       TCP/UDP over IPv4. Sigh. Vendors like this
  *                       way by an unknown reason. Though, see comment above
@@ -218,6 +218,9 @@ enum {
 
        /* device driver supports TX zero-copy buffers */
        SKBTX_DEV_ZEROCOPY = 1 << 4,
+
+       /* generate wifi status information (where possible) */
+       SKBTX_WIFI_STATUS = 1 << 5,
 };
 
 /*
@@ -352,6 +355,8 @@ typedef unsigned char *sk_buff_data_t;
  *     @ooo_okay: allow the mapping of a socket to a queue to be changed
  *     @l4_rxhash: indicate rxhash is a canonical 4-tuple hash over transport
  *             ports.
+ *     @wifi_acked_valid: wifi_acked was set
+ *     @wifi_acked: whether frame was acked on wifi or not
  *     @dma_cookie: a cookie to one of several possible DMA operations
  *             done by skb DMA functions
  *     @secmark: security marking
@@ -445,10 +450,11 @@ struct sk_buff {
 #endif
        __u8                    ooo_okay:1;
        __u8                    l4_rxhash:1;
+       __u8                    wifi_acked_valid:1;
+       __u8                    wifi_acked:1;
+       /* 10/12 bit hole (depending on ndisc_nodetype presence) */
        kmemcheck_bitfield_end(flags2);
 
-       /* 0/13 bit hole */
-
 #ifdef CONFIG_NET_DMA
        dma_cookie_t            dma_cookie;
 #endif
@@ -540,6 +546,7 @@ extern void consume_skb(struct sk_buff *skb);
 extern void           __kfree_skb(struct sk_buff *skb);
 extern struct sk_buff *__alloc_skb(unsigned int size,
                                   gfp_t priority, int fclone, int node);
+extern struct sk_buff *build_skb(void *data);
 static inline struct sk_buff *alloc_skb(unsigned int size,
                                        gfp_t priority)
 {
@@ -1662,38 +1669,6 @@ static inline struct sk_buff *netdev_alloc_skb_ip_align(struct net_device *dev,
 }
 
 /**
- *     __netdev_alloc_page - allocate a page for ps-rx on a specific device
- *     @dev: network device to receive on
- *     @gfp_mask: alloc_pages_node mask
- *
- *     Allocate a new page. dev currently unused.
- *
- *     %NULL is returned if there is no free memory.
- */
-static inline struct page *__netdev_alloc_page(struct net_device *dev, gfp_t gfp_mask)
-{
-       return alloc_pages_node(NUMA_NO_NODE, gfp_mask, 0);
-}
-
-/**
- *     netdev_alloc_page - allocate a page for ps-rx on a specific device
- *     @dev: network device to receive on
- *
- *     Allocate a new page. dev currently unused.
- *
- *     %NULL is returned if there is no free memory.
- */
-static inline struct page *netdev_alloc_page(struct net_device *dev)
-{
-       return __netdev_alloc_page(dev, GFP_ATOMIC);
-}
-
-static inline void netdev_free_page(struct net_device *dev, struct page *page)
-{
-       __free_page(page);
-}
-
-/**
  * skb_frag_page - retrieve the page refered to by a paged fragment
  * @frag: the paged fragment
  *
@@ -2105,7 +2080,8 @@ extern void              skb_split(struct sk_buff *skb,
 extern int            skb_shift(struct sk_buff *tgt, struct sk_buff *skb,
                                 int shiftlen);
 
-extern struct sk_buff *skb_segment(struct sk_buff *skb, u32 features);
+extern struct sk_buff *skb_segment(struct sk_buff *skb,
+                                  netdev_features_t features);
 
 static inline void *skb_header_pointer(const struct sk_buff *skb, int offset,
                                       int len, void *buffer)
@@ -2263,6 +2239,15 @@ static inline void skb_tx_timestamp(struct sk_buff *skb)
        sw_tx_timestamp(skb);
 }
 
+/**
+ * skb_complete_wifi_ack - deliver skb with wifi status
+ *
+ * @skb: the original outgoing packet
+ * @acked: ack status
+ *
+ */
+void skb_complete_wifi_ack(struct sk_buff *skb, bool acked);
+
 extern __sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len);
 extern __sum16 __skb_checksum_complete(struct sk_buff *skb);
 
index 3d8f9c4..f15fd98 100644 (file)
@@ -237,7 +237,7 @@ static inline bool __rpc_copy_addr6(struct sockaddr *dst,
        struct sockaddr_in6 *dsin6 = (struct sockaddr_in6 *) dst;
 
        dsin6->sin6_family = ssin6->sin6_family;
-       ipv6_addr_copy(&dsin6->sin6_addr, &ssin6->sin6_addr);
+       dsin6->sin6_addr = ssin6->sin6_addr;
        return true;
 }
 #else  /* !(CONFIG_IPV6 || CONFIG_IPV6_MODULE) */
index add4790..63f98d0 100644 (file)
  *     vdev: the virtio_device
  *     This gives the final feature bits for the device: it can change
  *     the dev->feature bits if it wants.
+ * @bus_name: return the bus name associated with the device
+ *     vdev: the virtio_device
+ *      This returns a pointer to the bus name a la pci_name from which
+ *      the caller can then copy.
  */
 typedef void vq_callback_t(struct virtqueue *);
 struct virtio_config_ops {
@@ -117,6 +121,7 @@ struct virtio_config_ops {
        void (*del_vqs)(struct virtio_device *);
        u32 (*get_features)(struct virtio_device *vdev);
        void (*finalize_features)(struct virtio_device *vdev);
+       const char *(*bus_name)(struct virtio_device *vdev);
 };
 
 /* If driver didn't advertise the feature, it will never appear. */
@@ -182,5 +187,14 @@ struct virtqueue *virtio_find_single_vq(struct virtio_device *vdev,
                return ERR_PTR(err);
        return vq;
 }
+
+static inline
+const char *virtio_bus_name(struct virtio_device *vdev)
+{
+       if (!vdev->config->bus_name)
+               return "virtio";
+       return vdev->config->bus_name(vdev);
+}
+
 #endif /* __KERNEL__ */
 #endif /* _LINUX_VIRTIO_CONFIG_H */
index 687fb11..4bde182 100644 (file)
@@ -119,7 +119,7 @@ unmap_kernel_range(unsigned long addr, unsigned long size)
 #endif
 
 /* Allocate/destroy a 'vmalloc' VM area. */
-extern struct vm_struct *alloc_vm_area(size_t size);
+extern struct vm_struct *alloc_vm_area(size_t size, pte_t **ptes);
 extern void free_vm_area(struct vm_struct *area);
 
 /* for /dev/kmem */
index e86af08..835f3b2 100644 (file)
@@ -77,6 +77,33 @@ struct bt_power {
 #define BT_POWER_FORCE_ACTIVE_OFF 0
 #define BT_POWER_FORCE_ACTIVE_ON  1
 
+#define BT_CHANNEL_POLICY      10
+
+/* BR/EDR only (default policy)
+ *   AMP controllers cannot be used.
+ *   Channel move requests from the remote device are denied.
+ *   If the L2CAP channel is currently using AMP, move the channel to BR/EDR.
+ */
+#define BT_CHANNEL_POLICY_BREDR_ONLY           0
+
+/* BR/EDR Preferred
+ *   Allow use of AMP controllers.
+ *   If the L2CAP channel is currently on AMP, move it to BR/EDR.
+ *   Channel move requests from the remote device are allowed.
+ */
+#define BT_CHANNEL_POLICY_BREDR_PREFERRED      1
+
+/* AMP Preferred
+ *   Allow use of AMP controllers
+ *   If the L2CAP channel is currently on BR/EDR and AMP controller
+ *     resources are available, initiate a channel move to AMP.
+ *   Channel move requests from the remote device are allowed.
+ *   If the L2CAP socket has not been connected yet, try to create
+ *     and configure the channel directly on an AMP controller rather
+ *     than BR/EDR.
+ */
+#define BT_CHANNEL_POLICY_AMP_PREFERRED                2
+
 __printf(2, 3)
 int bt_printk(const char *level, const char *fmt, ...);
 
@@ -158,7 +185,7 @@ struct bt_skb_cb {
        __u8 pkt_type;
        __u8 incoming;
        __u16 expect;
-       __u8 tx_seq;
+       __u16 tx_seq;
        __u8 retries;
        __u8 sar;
        unsigned short channel;
index aaf79af..139ce2a 100644 (file)
@@ -264,6 +264,13 @@ enum {
 #define HCI_LK_SMP_IRK                 0x82
 #define HCI_LK_SMP_CSRK                        0x83
 
+/* ---- HCI Error Codes ---- */
+#define HCI_ERROR_AUTH_FAILURE         0x05
+#define HCI_ERROR_REJ_BAD_ADDR         0x0f
+#define HCI_ERROR_REMOTE_USER_TERM     0x13
+#define HCI_ERROR_LOCAL_HOST_TERM      0x16
+#define HCI_ERROR_PAIRING_NOT_ALLOWED  0x18
+
 /* -----  HCI Commands ---- */
 #define HCI_OP_NOP                     0x0000
 
@@ -726,6 +733,21 @@ struct hci_cp_write_page_scan_activity {
        #define PAGE_SCAN_TYPE_STANDARD         0x00
        #define PAGE_SCAN_TYPE_INTERLACED       0x01
 
+#define HCI_OP_READ_LOCAL_AMP_INFO     0x1409
+struct hci_rp_read_local_amp_info {
+       __u8     status;
+       __u8     amp_status;
+       __le32   total_bw;
+       __le32   max_bw;
+       __le32   min_latency;
+       __le32   max_pdu;
+       __u8     amp_type;
+       __le16   pal_cap;
+       __le16   max_assoc_size;
+       __le32   max_flush_to;
+       __le32   be_flush_to;
+} __packed;
+
 #define HCI_OP_LE_SET_EVENT_MASK       0x2001
 struct hci_cp_le_set_event_mask {
        __u8     mask[8];
index 3779ea3..f333e76 100644 (file)
@@ -32,6 +32,9 @@
 #define HCI_PROTO_L2CAP        0
 #define HCI_PROTO_SCO  1
 
+/* HCI priority */
+#define HCI_PRIO_MAX   7
+
 /* HCI Core structures */
 struct inquiry_data {
        bdaddr_t        bdaddr;
@@ -64,6 +67,12 @@ struct hci_conn_hash {
        unsigned int     le_num;
 };
 
+struct hci_chan_hash {
+       struct list_head list;
+       spinlock_t       lock;
+       unsigned int     num;
+};
+
 struct bdaddr_list {
        struct list_head list;
        bdaddr_t bdaddr;
@@ -150,6 +159,17 @@ struct hci_dev {
        __u16           sniff_min_interval;
        __u16           sniff_max_interval;
 
+       __u8            amp_status;
+       __u32           amp_total_bw;
+       __u32           amp_max_bw;
+       __u32           amp_min_latency;
+       __u32           amp_max_pdu;
+       __u8            amp_type;
+       __u16           amp_pal_cap;
+       __u16           amp_assoc_size;
+       __u32           amp_max_flush_to;
+       __u32           amp_be_flush_to;
+
        unsigned int    auto_accept_delay;
 
        unsigned long   quirks;
@@ -173,8 +193,10 @@ struct hci_dev {
        struct workqueue_struct *workqueue;
 
        struct work_struct      power_on;
-       struct work_struct      power_off;
-       struct timer_list       off_timer;
+       struct delayed_work     power_off;
+
+       __u16                   discov_timeout;
+       struct delayed_work     discov_off;
 
        struct timer_list       cmd_timer;
        struct tasklet_struct   cmd_task;
@@ -195,6 +217,8 @@ struct hci_dev {
 
        __u16                   init_last_cmd;
 
+       struct list_head        mgmt_pending;
+
        struct inquiry_cache    inq_cache;
        struct hci_conn_hash    conn_hash;
        struct list_head        blacklist;
@@ -273,6 +297,7 @@ struct hci_conn {
        unsigned int    sent;
 
        struct sk_buff_head data_q;
+       struct hci_chan_hash chan_hash;
 
        struct timer_list disc_timer;
        struct timer_list idle_timer;
@@ -295,6 +320,14 @@ struct hci_conn {
        void (*disconn_cfm_cb)  (struct hci_conn *conn, u8 reason);
 };
 
+struct hci_chan {
+       struct list_head list;
+
+       struct hci_conn *conn;
+       struct sk_buff_head data_q;
+       unsigned int    sent;
+};
+
 extern struct hci_proto *hci_proto[];
 extern struct list_head hci_dev_list;
 extern struct list_head hci_cb_list;
@@ -455,6 +488,28 @@ static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
        return NULL;
 }
 
+static inline void hci_chan_hash_init(struct hci_conn *c)
+{
+       struct hci_chan_hash *h = &c->chan_hash;
+       INIT_LIST_HEAD(&h->list);
+       spin_lock_init(&h->lock);
+       h->num = 0;
+}
+
+static inline void hci_chan_hash_add(struct hci_conn *c, struct hci_chan *chan)
+{
+       struct hci_chan_hash *h = &c->chan_hash;
+       list_add(&chan->list, &h->list);
+       h->num++;
+}
+
+static inline void hci_chan_hash_del(struct hci_conn *c, struct hci_chan *chan)
+{
+       struct hci_chan_hash *h = &c->chan_hash;
+       list_del(&chan->list);
+       h->num--;
+}
+
 void hci_acl_connect(struct hci_conn *conn);
 void hci_acl_disconn(struct hci_conn *conn, __u8 reason);
 void hci_add_sco(struct hci_conn *conn, __u16 handle);
@@ -466,6 +521,10 @@ int hci_conn_del(struct hci_conn *conn);
 void hci_conn_hash_flush(struct hci_dev *hdev);
 void hci_conn_check_pending(struct hci_dev *hdev);
 
+struct hci_chan *hci_chan_create(struct hci_conn *conn);
+int hci_chan_del(struct hci_chan *chan);
+void hci_chan_hash_flush(struct hci_conn *conn);
+
 struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
                                                __u8 sec_level, __u8 auth_type);
 int hci_conn_check_link_mode(struct hci_conn *conn);
@@ -545,7 +604,7 @@ struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst);
 struct hci_dev *hci_alloc_dev(void);
 void hci_free_dev(struct hci_dev *hdev);
 int hci_register_dev(struct hci_dev *hdev);
-int hci_unregister_dev(struct hci_dev *hdev);
+void hci_unregister_dev(struct hci_dev *hdev);
 int hci_suspend_dev(struct hci_dev *hdev);
 int hci_resume_dev(struct hci_dev *hdev);
 int hci_dev_open(__u16 dev);
@@ -599,8 +658,9 @@ int hci_recv_frame(struct sk_buff *skb);
 int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count);
 int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count);
 
-int hci_register_sysfs(struct hci_dev *hdev);
-void hci_unregister_sysfs(struct hci_dev *hdev);
+void hci_init_sysfs(struct hci_dev *hdev);
+int hci_add_sysfs(struct hci_dev *hdev);
+void hci_del_sysfs(struct hci_dev *hdev);
 void hci_conn_init_sysfs(struct hci_conn *conn);
 void hci_conn_add_sysfs(struct hci_conn *conn);
 void hci_conn_del_sysfs(struct hci_conn *conn);
@@ -676,7 +736,7 @@ static inline void hci_proto_connect_cfm(struct hci_conn *conn, __u8 status)
 static inline int hci_proto_disconn_ind(struct hci_conn *conn)
 {
        register struct hci_proto *hp;
-       int reason = 0x13;
+       int reason = HCI_ERROR_REMOTE_USER_TERM;
 
        hp = hci_proto[HCI_PROTO_L2CAP];
        if (hp && hp->disconn_ind)
@@ -836,7 +896,7 @@ int hci_register_notifier(struct notifier_block *nb);
 int hci_unregister_notifier(struct notifier_block *nb);
 
 int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param);
-void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
+void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags);
 void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
 
 void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode);
@@ -849,34 +909,41 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb,
 
 /* Management interface */
 int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len);
-int mgmt_index_added(u16 index);
-int mgmt_index_removed(u16 index);
-int mgmt_powered(u16 index, u8 powered);
-int mgmt_discoverable(u16 index, u8 discoverable);
-int mgmt_connectable(u16 index, u8 connectable);
-int mgmt_new_key(u16 index, struct link_key *key, u8 persistent);
-int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 link_type);
-int mgmt_disconnected(u16 index, bdaddr_t *bdaddr);
-int mgmt_disconnect_failed(u16 index);
-int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status);
-int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure);
-int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
-int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
-int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value,
-                                                       u8 confirm_hint);
-int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
-int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr,
+int mgmt_index_added(struct hci_dev *hdev);
+int mgmt_index_removed(struct hci_dev *hdev);
+int mgmt_powered(struct hci_dev *hdev, u8 powered);
+int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable);
+int mgmt_connectable(struct hci_dev *hdev, u8 connectable);
+int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status);
+int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
+                                                               u8 persistent);
+int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
+int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
+int mgmt_disconnect_failed(struct hci_dev *hdev);
+int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type,
                                                                u8 status);
-int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status);
-int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status);
-int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
+int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure);
+int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
                                                                u8 status);
-int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
-                                                               u8 *eir);
-int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name);
-int mgmt_discovering(u16 index, u8 discovering);
-int mgmt_device_blocked(u16 index, bdaddr_t *bdaddr);
-int mgmt_device_unblocked(u16 index, bdaddr_t *bdaddr);
+int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                                               u8 status);
+int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                               __le32 value, u8 confirm_hint);
+int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                                               u8 status);
+int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
+                                               bdaddr_t *bdaddr, u8 status);
+int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status);
+int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status);
+int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
+                                               u8 *randomizer, u8 status);
+int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type,
+                                       u8 *dev_class, s8 rssi, u8 *eir);
+int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name);
+int mgmt_inquiry_failed(struct hci_dev *hdev, u8 status);
+int mgmt_discovering(struct hci_dev *hdev, u8 discovering);
+int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr);
+int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr);
 
 /* HCI info for socket */
 #define hci_pi(sk) ((struct hci_pinfo *) sk)
@@ -915,4 +982,7 @@ void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
 void hci_le_ltk_reply(struct hci_conn *conn, u8 ltk[16]);
 void hci_le_ltk_neg_reply(struct hci_conn *conn);
 
+int hci_do_inquiry(struct hci_dev *hdev, u8 length);
+int hci_cancel_inquiry(struct hci_dev *hdev);
+
 #endif /* __HCI_CORE_H */
index ab90ae0..875021a 100644 (file)
 #ifndef __L2CAP_H
 #define __L2CAP_H
 
+#include <asm/unaligned.h>
+
 /* L2CAP defaults */
 #define L2CAP_DEFAULT_MTU              672
 #define L2CAP_DEFAULT_MIN_MTU          48
 #define L2CAP_DEFAULT_FLUSH_TO         0xffff
 #define L2CAP_DEFAULT_TX_WINDOW                63
+#define L2CAP_DEFAULT_EXT_WINDOW       0x3FFF
 #define L2CAP_DEFAULT_MAX_TX           3
 #define L2CAP_DEFAULT_RETRANS_TO       2000    /* 2 seconds */
 #define L2CAP_DEFAULT_MONITOR_TO       12000   /* 12 seconds */
 #define L2CAP_DEFAULT_MAX_PDU_SIZE     1009    /* Sized for 3-DH5 packet */
 #define L2CAP_DEFAULT_ACK_TO           200
 #define L2CAP_LE_DEFAULT_MTU           23
+#define L2CAP_DEFAULT_MAX_SDU_SIZE     0xFFFF
+#define L2CAP_DEFAULT_SDU_ITIME                0xFFFFFFFF
+#define L2CAP_DEFAULT_ACC_LAT          0xFFFFFFFF
 
-#define L2CAP_CONN_TIMEOUT     (40000) /* 40 seconds */
-#define L2CAP_INFO_TIMEOUT     (4000)  /*  4 seconds */
+#define L2CAP_DISC_TIMEOUT             (100)
+#define L2CAP_DISC_REJ_TIMEOUT         (5000)  /*  5 seconds */
+#define L2CAP_ENC_TIMEOUT              (5000)  /*  5 seconds */
+#define L2CAP_CONN_TIMEOUT             (40000) /* 40 seconds */
+#define L2CAP_INFO_TIMEOUT             (4000)  /*  4 seconds */
 
 /* L2CAP socket address */
 struct sockaddr_l2 {
@@ -88,52 +97,82 @@ struct l2cap_conninfo {
 #define L2CAP_ECHO_RSP         0x09
 #define L2CAP_INFO_REQ         0x0a
 #define L2CAP_INFO_RSP         0x0b
+#define L2CAP_CREATE_CHAN_REQ  0x0c
+#define L2CAP_CREATE_CHAN_RSP  0x0d
+#define L2CAP_MOVE_CHAN_REQ    0x0e
+#define L2CAP_MOVE_CHAN_RSP    0x0f
+#define L2CAP_MOVE_CHAN_CFM    0x10
+#define L2CAP_MOVE_CHAN_CFM_RSP        0x11
 #define L2CAP_CONN_PARAM_UPDATE_REQ    0x12
 #define L2CAP_CONN_PARAM_UPDATE_RSP    0x13
 
-/* L2CAP feature mask */
+/* L2CAP extended feature mask */
 #define L2CAP_FEAT_FLOWCTL     0x00000001
 #define L2CAP_FEAT_RETRANS     0x00000002
+#define L2CAP_FEAT_BIDIR_QOS   0x00000004
 #define L2CAP_FEAT_ERTM                0x00000008
 #define L2CAP_FEAT_STREAMING   0x00000010
 #define L2CAP_FEAT_FCS         0x00000020
+#define L2CAP_FEAT_EXT_FLOW    0x00000040
 #define L2CAP_FEAT_FIXED_CHAN  0x00000080
+#define L2CAP_FEAT_EXT_WINDOW  0x00000100
+#define L2CAP_FEAT_UCD         0x00000200
 
 /* L2CAP checksum option */
 #define L2CAP_FCS_NONE         0x00
 #define L2CAP_FCS_CRC16                0x01
 
+/* L2CAP fixed channels */
+#define L2CAP_FC_L2CAP         0x02
+#define L2CAP_FC_A2MP          0x08
+
 /* L2CAP Control Field bit masks */
-#define L2CAP_CTRL_SAR               0xC000
-#define L2CAP_CTRL_REQSEQ            0x3F00
-#define L2CAP_CTRL_TXSEQ             0x007E
-#define L2CAP_CTRL_RETRANS           0x0080
-#define L2CAP_CTRL_FINAL             0x0080
-#define L2CAP_CTRL_POLL              0x0010
-#define L2CAP_CTRL_SUPERVISE         0x000C
-#define L2CAP_CTRL_FRAME_TYPE        0x0001 /* I- or S-Frame */
-
-#define L2CAP_CTRL_TXSEQ_SHIFT      1
-#define L2CAP_CTRL_REQSEQ_SHIFT     8
-#define L2CAP_CTRL_SAR_SHIFT       14
+#define L2CAP_CTRL_SAR                 0xC000
+#define L2CAP_CTRL_REQSEQ              0x3F00
+#define L2CAP_CTRL_TXSEQ               0x007E
+#define L2CAP_CTRL_SUPERVISE           0x000C
+
+#define L2CAP_CTRL_RETRANS             0x0080
+#define L2CAP_CTRL_FINAL               0x0080
+#define L2CAP_CTRL_POLL                        0x0010
+#define L2CAP_CTRL_FRAME_TYPE          0x0001 /* I- or S-Frame */
+
+#define L2CAP_CTRL_TXSEQ_SHIFT         1
+#define L2CAP_CTRL_SUPER_SHIFT         2
+#define L2CAP_CTRL_REQSEQ_SHIFT                8
+#define L2CAP_CTRL_SAR_SHIFT           14
+
+/* L2CAP Extended Control Field bit mask */
+#define L2CAP_EXT_CTRL_TXSEQ           0xFFFC0000
+#define L2CAP_EXT_CTRL_SAR             0x00030000
+#define L2CAP_EXT_CTRL_SUPERVISE       0x00030000
+#define L2CAP_EXT_CTRL_REQSEQ          0x0000FFFC
+
+#define L2CAP_EXT_CTRL_POLL            0x00040000
+#define L2CAP_EXT_CTRL_FINAL           0x00000002
+#define L2CAP_EXT_CTRL_FRAME_TYPE      0x00000001 /* I- or S-Frame */
+
+#define L2CAP_EXT_CTRL_REQSEQ_SHIFT    2
+#define L2CAP_EXT_CTRL_SAR_SHIFT       16
+#define L2CAP_EXT_CTRL_SUPER_SHIFT     16
+#define L2CAP_EXT_CTRL_TXSEQ_SHIFT     18
 
 /* L2CAP Supervisory Function */
-#define L2CAP_SUPER_RCV_READY           0x0000
-#define L2CAP_SUPER_REJECT              0x0004
-#define L2CAP_SUPER_RCV_NOT_READY       0x0008
-#define L2CAP_SUPER_SELECT_REJECT       0x000C
+#define L2CAP_SUPER_RR         0x00
+#define L2CAP_SUPER_REJ                0x01
+#define L2CAP_SUPER_RNR                0x02
+#define L2CAP_SUPER_SREJ       0x03
 
 /* L2CAP Segmentation and Reassembly */
-#define L2CAP_SDU_UNSEGMENTED       0x0000
-#define L2CAP_SDU_START             0x4000
-#define L2CAP_SDU_END               0x8000
-#define L2CAP_SDU_CONTINUE          0xC000
+#define L2CAP_SAR_UNSEGMENTED  0x00
+#define L2CAP_SAR_START                0x01
+#define L2CAP_SAR_END          0x02
+#define L2CAP_SAR_CONTINUE     0x03
 
 /* L2CAP Command rej. reasons */
-#define L2CAP_REJ_NOT_UNDERSTOOD      0x0000
-#define L2CAP_REJ_MTU_EXCEEDED        0x0001
-#define L2CAP_REJ_INVALID_CID         0x0002
-
+#define L2CAP_REJ_NOT_UNDERSTOOD       0x0000
+#define L2CAP_REJ_MTU_EXCEEDED         0x0001
+#define L2CAP_REJ_INVALID_CID          0x0002
 
 /* L2CAP structures */
 struct l2cap_hdr {
@@ -141,6 +180,12 @@ struct l2cap_hdr {
        __le16     cid;
 } __packed;
 #define L2CAP_HDR_SIZE         4
+#define L2CAP_ENH_HDR_SIZE     6
+#define L2CAP_EXT_HDR_SIZE     8
+
+#define L2CAP_FCS_SIZE         2
+#define L2CAP_SDULEN_SIZE      2
+#define L2CAP_PSMLEN_SIZE      2
 
 struct l2cap_cmd_hdr {
        __u8       code;
@@ -185,14 +230,15 @@ struct l2cap_conn_rsp {
 #define L2CAP_CID_DYN_START    0x0040
 #define L2CAP_CID_DYN_END      0xffff
 
-/* connect result */
+/* connect/create channel results */
 #define L2CAP_CR_SUCCESS       0x0000
 #define L2CAP_CR_PEND          0x0001
 #define L2CAP_CR_BAD_PSM       0x0002
 #define L2CAP_CR_SEC_BLOCK     0x0003
 #define L2CAP_CR_NO_MEM                0x0004
+#define L2CAP_CR_BAD_AMP       0x0005
 
-/* connect status */
+/* connect/create channel status */
 #define L2CAP_CS_NO_INFO       0x0000
 #define L2CAP_CS_AUTHEN_PEND   0x0001
 #define L2CAP_CS_AUTHOR_PEND   0x0002
@@ -214,6 +260,8 @@ struct l2cap_conf_rsp {
 #define L2CAP_CONF_UNACCEPT    0x0001
 #define L2CAP_CONF_REJECT      0x0002
 #define L2CAP_CONF_UNKNOWN     0x0003
+#define L2CAP_CONF_PENDING     0x0004
+#define L2CAP_CONF_EFS_REJECT  0x0005
 
 struct l2cap_conf_opt {
        __u8       type;
@@ -230,6 +278,8 @@ struct l2cap_conf_opt {
 #define L2CAP_CONF_QOS         0x03
 #define L2CAP_CONF_RFC         0x04
 #define L2CAP_CONF_FCS         0x05
+#define L2CAP_CONF_EFS         0x06
+#define L2CAP_CONF_EWS         0x07
 
 #define L2CAP_CONF_MAX_SIZE    22
 
@@ -248,6 +298,21 @@ struct l2cap_conf_rfc {
 #define L2CAP_MODE_ERTM                0x03
 #define L2CAP_MODE_STREAMING   0x04
 
+struct l2cap_conf_efs {
+       __u8    id;
+       __u8    stype;
+       __le16  msdu;
+       __le32  sdu_itime;
+       __le32  acc_lat;
+       __le32  flush_to;
+} __packed;
+
+#define L2CAP_SERV_NOTRAFIC    0x00
+#define L2CAP_SERV_BESTEFFORT  0x01
+#define L2CAP_SERV_GUARANTEED  0x02
+
+#define L2CAP_BESTEFFORT_ID    0x01
+
 struct l2cap_disconn_req {
        __le16     dcid;
        __le16     scid;
@@ -268,14 +333,57 @@ struct l2cap_info_rsp {
        __u8        data[0];
 } __packed;
 
+struct l2cap_create_chan_req {
+       __le16      psm;
+       __le16      scid;
+       __u8        amp_id;
+} __packed;
+
+struct l2cap_create_chan_rsp {
+       __le16      dcid;
+       __le16      scid;
+       __le16      result;
+       __le16      status;
+} __packed;
+
+struct l2cap_move_chan_req {
+       __le16      icid;
+       __u8        dest_amp_id;
+} __packed;
+
+struct l2cap_move_chan_rsp {
+       __le16      icid;
+       __le16      result;
+} __packed;
+
+#define L2CAP_MR_SUCCESS       0x0000
+#define L2CAP_MR_PEND          0x0001
+#define L2CAP_MR_BAD_ID                0x0002
+#define L2CAP_MR_SAME_ID       0x0003
+#define L2CAP_MR_NOT_SUPP      0x0004
+#define L2CAP_MR_COLLISION     0x0005
+#define L2CAP_MR_NOT_ALLOWED   0x0006
+
+struct l2cap_move_chan_cfm {
+       __le16      icid;
+       __le16      result;
+} __packed;
+
+#define L2CAP_MC_CONFIRMED     0x0000
+#define L2CAP_MC_UNCONFIRMED   0x0001
+
+struct l2cap_move_chan_cfm_rsp {
+       __le16      icid;
+} __packed;
+
 /* info type */
-#define L2CAP_IT_CL_MTU     0x0001
-#define L2CAP_IT_FEAT_MASK  0x0002
-#define L2CAP_IT_FIXED_CHAN 0x0003
+#define L2CAP_IT_CL_MTU                0x0001
+#define L2CAP_IT_FEAT_MASK     0x0002
+#define L2CAP_IT_FIXED_CHAN    0x0003
 
 /* info result */
-#define L2CAP_IR_SUCCESS    0x0000
-#define L2CAP_IR_NOTSUPP    0x0001
+#define L2CAP_IR_SUCCESS       0x0000
+#define L2CAP_IR_NOTSUPP       0x0001
 
 struct l2cap_conn_param_update_req {
        __le16      min;
@@ -294,7 +402,7 @@ struct l2cap_conn_param_update_rsp {
 
 /* ----- L2CAP channels and connections ----- */
 struct srej_list {
-       __u   tx_seq;
+       __u16   tx_seq;
        struct list_head list;
 };
 
@@ -316,14 +424,11 @@ struct l2cap_chan {
        __u16           flush_to;
        __u8            mode;
        __u8            chan_type;
+       __u8            chan_policy;
 
        __le16          sport;
 
        __u8            sec_level;
-       __u8            role_switch;
-       __u8            force_reliable;
-       __u8            flushable;
-       __u8            force_active;
 
        __u8            ident;
 
@@ -334,7 +439,8 @@ struct l2cap_chan {
 
        __u8            fcs;
 
-       __u8            tx_win;
+       __u16           tx_win;
+       __u16           tx_win_max;
        __u8            max_tx;
        __u16           retrans_timeout;
        __u16           monitor_timeout;
@@ -342,25 +448,40 @@ struct l2cap_chan {
 
        unsigned long   conf_state;
        unsigned long   conn_state;
-
-       __u8            next_tx_seq;
-       __u8            expected_ack_seq;
-       __u8            expected_tx_seq;
-       __u8            buffer_seq;
-       __u8            buffer_seq_srej;
-       __u8            srej_save_reqseq;
-       __u8            frames_sent;
-       __u8            unacked_frames;
+       unsigned long   flags;
+
+       __u16           next_tx_seq;
+       __u16           expected_ack_seq;
+       __u16           expected_tx_seq;
+       __u16           buffer_seq;
+       __u16           buffer_seq_srej;
+       __u16           srej_save_reqseq;
+       __u16           frames_sent;
+       __u16           unacked_frames;
        __u8            retry_count;
        __u8            num_acked;
        __u16           sdu_len;
        struct sk_buff  *sdu;
        struct sk_buff  *sdu_last_frag;
 
-       __u           remote_tx_win;
+       __u16           remote_tx_win;
        __u8            remote_max_tx;
        __u16           remote_mps;
 
+       __u8            local_id;
+       __u8            local_stype;
+       __u16           local_msdu;
+       __u32           local_sdu_itime;
+       __u32           local_acc_lat;
+       __u32           local_flush_to;
+
+       __u8            remote_id;
+       __u8            remote_stype;
+       __u16           remote_msdu;
+       __u32           remote_sdu_itime;
+       __u32           remote_acc_lat;
+       __u32           remote_flush_to;
+
        struct timer_list       chan_timer;
        struct timer_list       retrans_timer;
        struct timer_list       monitor_timer;
@@ -388,6 +509,7 @@ struct l2cap_ops {
 
 struct l2cap_conn {
        struct hci_conn *hcon;
+       struct hci_chan *hchan;
 
        bdaddr_t        *dst;
        bdaddr_t        *src;
@@ -442,6 +564,9 @@ enum {
        CONF_CONNECT_PEND,
        CONF_NO_FCS_RECV,
        CONF_STATE2_DEVICE,
+       CONF_EWS_RECV,
+       CONF_LOC_CONF_PEND,
+       CONF_REM_CONF_PEND,
 };
 
 #define L2CAP_CONF_MAX_CONF_REQ 2
@@ -459,6 +584,16 @@ enum {
        CONN_RNR_SENT,
 };
 
+/* Definitions for flags in l2cap_chan */
+enum {
+       FLAG_ROLE_SWITCH,
+       FLAG_FORCE_ACTIVE,
+       FLAG_FORCE_RELIABLE,
+       FLAG_FLUSHABLE,
+       FLAG_EXT_CTRL,
+       FLAG_EFS_ENABLE,
+};
+
 #define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t))
 #define __clear_chan_timer(c) l2cap_clear_timer(c, &c->chan_timer)
 #define __set_retrans_timer(c) l2cap_set_timer(c, &c->retrans_timer, \
@@ -471,6 +606,22 @@ enum {
                L2CAP_DEFAULT_ACK_TO);
 #define __clear_ack_timer(c) l2cap_clear_timer(c, &c->ack_timer)
 
+static inline int __seq_offset(struct l2cap_chan *chan, __u16 seq1, __u16 seq2)
+{
+       int offset;
+
+       offset = (seq1 - seq2) % (chan->tx_win_max + 1);
+       if (offset < 0)
+               offset += (chan->tx_win_max + 1);
+
+       return offset;
+}
+
+static inline __u16 __next_seq(struct l2cap_chan *chan, __u16 seq)
+{
+       return (seq + 1) % (chan->tx_win_max + 1);
+}
+
 static inline int l2cap_tx_window_full(struct l2cap_chan *ch)
 {
        int sub;
@@ -483,13 +634,165 @@ static inline int l2cap_tx_window_full(struct l2cap_chan *ch)
        return sub == ch->remote_tx_win;
 }
 
-#define __get_txseq(ctrl)      (((ctrl) & L2CAP_CTRL_TXSEQ) >> 1)
-#define __get_reqseq(ctrl)     (((ctrl) & L2CAP_CTRL_REQSEQ) >> 8)
-#define __is_iframe(ctrl)      (!((ctrl) & L2CAP_CTRL_FRAME_TYPE))
-#define __is_sframe(ctrl)      ((ctrl) & L2CAP_CTRL_FRAME_TYPE)
-#define __is_sar_start(ctrl)   (((ctrl) & L2CAP_CTRL_SAR) == L2CAP_SDU_START)
+static inline __u16 __get_reqseq(struct l2cap_chan *chan, __u32 ctrl)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return (ctrl & L2CAP_EXT_CTRL_REQSEQ) >>
+                                               L2CAP_EXT_CTRL_REQSEQ_SHIFT;
+       else
+               return (ctrl & L2CAP_CTRL_REQSEQ) >> L2CAP_CTRL_REQSEQ_SHIFT;
+}
+
+static inline __u32 __set_reqseq(struct l2cap_chan *chan, __u32 reqseq)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return (reqseq << L2CAP_EXT_CTRL_REQSEQ_SHIFT) &
+                                                       L2CAP_EXT_CTRL_REQSEQ;
+       else
+               return (reqseq << L2CAP_CTRL_REQSEQ_SHIFT) & L2CAP_CTRL_REQSEQ;
+}
+
+static inline __u16 __get_txseq(struct l2cap_chan *chan, __u32 ctrl)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return (ctrl & L2CAP_EXT_CTRL_TXSEQ) >>
+                                               L2CAP_EXT_CTRL_TXSEQ_SHIFT;
+       else
+               return (ctrl & L2CAP_CTRL_TXSEQ) >> L2CAP_CTRL_TXSEQ_SHIFT;
+}
+
+static inline __u32 __set_txseq(struct l2cap_chan *chan, __u32 txseq)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return (txseq << L2CAP_EXT_CTRL_TXSEQ_SHIFT) &
+                                                       L2CAP_EXT_CTRL_TXSEQ;
+       else
+               return (txseq << L2CAP_CTRL_TXSEQ_SHIFT) & L2CAP_CTRL_TXSEQ;
+}
+
+static inline bool __is_sframe(struct l2cap_chan *chan, __u32 ctrl)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return ctrl & L2CAP_EXT_CTRL_FRAME_TYPE;
+       else
+               return ctrl & L2CAP_CTRL_FRAME_TYPE;
+}
+
+static inline __u32 __set_sframe(struct l2cap_chan *chan)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return L2CAP_EXT_CTRL_FRAME_TYPE;
+       else
+               return L2CAP_CTRL_FRAME_TYPE;
+}
+
+static inline __u8 __get_ctrl_sar(struct l2cap_chan *chan, __u32 ctrl)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return (ctrl & L2CAP_EXT_CTRL_SAR) >> L2CAP_EXT_CTRL_SAR_SHIFT;
+       else
+               return (ctrl & L2CAP_CTRL_SAR) >> L2CAP_CTRL_SAR_SHIFT;
+}
+
+static inline __u32 __set_ctrl_sar(struct l2cap_chan *chan, __u32 sar)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return (sar << L2CAP_EXT_CTRL_SAR_SHIFT) & L2CAP_EXT_CTRL_SAR;
+       else
+               return (sar << L2CAP_CTRL_SAR_SHIFT) & L2CAP_CTRL_SAR;
+}
+
+static inline bool __is_sar_start(struct l2cap_chan *chan, __u32 ctrl)
+{
+       return __get_ctrl_sar(chan, ctrl) == L2CAP_SAR_START;
+}
+
+static inline __u32 __get_sar_mask(struct l2cap_chan *chan)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return L2CAP_EXT_CTRL_SAR;
+       else
+               return L2CAP_CTRL_SAR;
+}
+
+static inline __u8 __get_ctrl_super(struct l2cap_chan *chan, __u32 ctrl)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return (ctrl & L2CAP_EXT_CTRL_SUPERVISE) >>
+                                               L2CAP_EXT_CTRL_SUPER_SHIFT;
+       else
+               return (ctrl & L2CAP_CTRL_SUPERVISE) >> L2CAP_CTRL_SUPER_SHIFT;
+}
+
+static inline __u32 __set_ctrl_super(struct l2cap_chan *chan, __u32 super)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return (super << L2CAP_EXT_CTRL_SUPER_SHIFT) &
+                                               L2CAP_EXT_CTRL_SUPERVISE;
+       else
+               return (super << L2CAP_CTRL_SUPER_SHIFT) &
+                                                       L2CAP_CTRL_SUPERVISE;
+}
+
+static inline __u32 __set_ctrl_final(struct l2cap_chan *chan)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return L2CAP_EXT_CTRL_FINAL;
+       else
+               return L2CAP_CTRL_FINAL;
+}
+
+static inline bool __is_ctrl_final(struct l2cap_chan *chan, __u32 ctrl)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return ctrl & L2CAP_EXT_CTRL_FINAL;
+       else
+               return ctrl & L2CAP_CTRL_FINAL;
+}
+
+static inline __u32 __set_ctrl_poll(struct l2cap_chan *chan)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return L2CAP_EXT_CTRL_POLL;
+       else
+               return L2CAP_CTRL_POLL;
+}
+
+static inline bool __is_ctrl_poll(struct l2cap_chan *chan, __u32 ctrl)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return ctrl & L2CAP_EXT_CTRL_POLL;
+       else
+               return ctrl & L2CAP_CTRL_POLL;
+}
+
+static inline __u32 __get_control(struct l2cap_chan *chan, void *p)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return get_unaligned_le32(p);
+       else
+               return get_unaligned_le16(p);
+}
+
+static inline void __put_control(struct l2cap_chan *chan, __u32 control,
+                                                               void *p)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return put_unaligned_le32(control, p);
+       else
+               return put_unaligned_le16(control, p);
+}
+
+static inline __u8 __ctrl_size(struct l2cap_chan *chan)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return L2CAP_EXT_HDR_SIZE - L2CAP_HDR_SIZE;
+       else
+               return L2CAP_ENH_HDR_SIZE - L2CAP_HDR_SIZE;
+}
 
 extern int disable_ertm;
+extern int enable_hs;
 
 int l2cap_init_sockets(void);
 void l2cap_cleanup_sockets(void);
@@ -504,7 +807,8 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk);
 void l2cap_chan_close(struct l2cap_chan *chan, int reason);
 void l2cap_chan_destroy(struct l2cap_chan *chan);
 int l2cap_chan_connect(struct l2cap_chan *chan);
-int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len);
+int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
+                                                               u32 priority);
 void l2cap_chan_busy(struct l2cap_chan *chan, int busy);
 
 #endif /* __L2CAP_H */
index d66da0f..3e320c9 100644 (file)
@@ -69,6 +69,10 @@ struct mgmt_mode {
 #define MGMT_OP_SET_POWERED            0x0005
 
 #define MGMT_OP_SET_DISCOVERABLE       0x0006
+struct mgmt_cp_set_discoverable {
+       __u8 val;
+       __u16 timeout;
+} __packed;
 
 #define MGMT_OP_SET_CONNECTABLE                0x0007
 
@@ -96,24 +100,22 @@ struct mgmt_cp_set_service_cache {
        __u8 enable;
 } __packed;
 
-struct mgmt_key_info {
+struct mgmt_link_key_info {
        bdaddr_t bdaddr;
        u8 type;
        u8 val[16];
        u8 pin_len;
-       u8 dlen;
-       u8 data[0];
 } __packed;
 
-#define MGMT_OP_LOAD_KEYS              0x000D
-struct mgmt_cp_load_keys {
+#define MGMT_OP_LOAD_LINK_KEYS         0x000D
+struct mgmt_cp_load_link_keys {
        __u8 debug_keys;
        __le16 key_count;
-       struct mgmt_key_info keys[0];
+       struct mgmt_link_key_info keys[0];
 } __packed;
 
-#define MGMT_OP_REMOVE_KEY             0x000E
-struct mgmt_cp_remove_key {
+#define MGMT_OP_REMOVE_KEYS            0x000E
+struct mgmt_cp_remove_keys {
        bdaddr_t bdaddr;
        __u8 disconnect;
 } __packed;
@@ -126,10 +128,20 @@ struct mgmt_rp_disconnect {
        bdaddr_t bdaddr;
 } __packed;
 
+#define MGMT_ADDR_BREDR                        0x00
+#define MGMT_ADDR_LE                   0x01
+#define MGMT_ADDR_BREDR_LE             0x02
+#define MGMT_ADDR_INVALID              0xff
+
+struct mgmt_addr_info {
+       bdaddr_t bdaddr;
+       __u8 type;
+} __packed;
+
 #define MGMT_OP_GET_CONNECTIONS                0x0010
 struct mgmt_rp_get_connections {
        __le16 conn_count;
-       bdaddr_t conn[0];
+       struct mgmt_addr_info addr[0];
 } __packed;
 
 #define MGMT_OP_PIN_CODE_REPLY         0x0011
@@ -245,26 +257,19 @@ struct mgmt_ev_controller_error {
 
 #define MGMT_EV_PAIRABLE               0x0009
 
-#define MGMT_EV_NEW_KEY                        0x000A
-struct mgmt_ev_new_key {
+#define MGMT_EV_NEW_LINK_KEY           0x000A
+struct mgmt_ev_new_link_key {
        __u8 store_hint;
-       struct mgmt_key_info key;
+       struct mgmt_link_key_info key;
 } __packed;
 
 #define MGMT_EV_CONNECTED              0x000B
-struct mgmt_ev_connected {
-       bdaddr_t bdaddr;
-       __u8 link_type;
-} __packed;
 
 #define MGMT_EV_DISCONNECTED           0x000C
-struct mgmt_ev_disconnected {
-       bdaddr_t bdaddr;
-} __packed;
 
 #define MGMT_EV_CONNECT_FAILED         0x000D
 struct mgmt_ev_connect_failed {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
        __u8 status;
 } __packed;
 
@@ -294,7 +299,7 @@ struct mgmt_ev_local_name_changed {
 
 #define MGMT_EV_DEVICE_FOUND           0x0012
 struct mgmt_ev_device_found {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
        __u8 dev_class[3];
        __s8 rssi;
        __u8 eir[HCI_MAX_EIR_LENGTH];
index 92cf1c2..8d7ba09 100644 (file)
@@ -391,6 +391,8 @@ struct cfg80211_crypto_settings {
  * @assocresp_ies: extra information element(s) to add into (Re)Association
  *     Response frames or %NULL
  * @assocresp_ies_len: length of assocresp_ies in octets
+ * @probe_resp_len: length of probe response template (@probe_resp)
+ * @probe_resp: probe response template (AP mode only)
  */
 struct beacon_parameters {
        u8 *head, *tail;
@@ -408,6 +410,8 @@ struct beacon_parameters {
        size_t proberesp_ies_len;
        const u8 *assocresp_ies;
        size_t assocresp_ies_len;
+       int probe_resp_len;
+       u8 *probe_resp;
 };
 
 /**
@@ -456,6 +460,9 @@ enum station_parameters_apply_mask {
  *     as the AC bitmap in the QoS info field
  * @max_sp: max Service Period. same format as the MAX_SP in the
  *     QoS info field (but already shifted down)
+ * @sta_modify_mask: bitmap indicating which parameters changed
+ *     (for those that don't have a natural "no change" value),
+ *     see &enum station_parameters_apply_mask
  */
 struct station_parameters {
        u8 *supported_rates;
@@ -615,6 +622,7 @@ struct sta_bss_parameters {
  *     user space MLME/SME implementation. The information is provided for
  *     the cfg80211_new_sta() calls to notify user space of the IEs.
  * @assoc_req_ies_len: Length of assoc_req_ies buffer in octets.
+ * @sta_flags: station flags mask & values
  */
 struct station_info {
        u32 filled;
@@ -1338,6 +1346,9 @@ struct cfg80211_gtk_rekey_data {
  *     doesn't verify much. Note, however, that the passed netdev may be
  *     %NULL as well if the user requested changing the channel for the
  *     device itself, or for a monitor interface.
+ * @get_channel: Get the current operating channel, should return %NULL if
+ *     there's no single defined operating channel if for example the
+ *     device implements channel hopping for multi-channel virtual interfaces.
  *
  * @scan: Request to do a scan. If returning zero, the scan request is given
  *     the driver, and will be valid until passed to cfg80211_scan_done().
@@ -1428,6 +1439,9 @@ struct cfg80211_gtk_rekey_data {
  *
  * @tdls_mgmt: Transmit a TDLS management frame.
  * @tdls_oper: Perform a high-level TDLS operation (e.g. TDLS link setup).
+ *
+ * @probe_client: probe an associated client, must return a cookie that it
+ *     later passes to cfg80211_probe_status().
  */
 struct cfg80211_ops {
        int     (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -1581,7 +1595,7 @@ struct cfg80211_ops {
                          enum nl80211_channel_type channel_type,
                          bool channel_type_valid, unsigned int wait,
                          const u8 *buf, size_t len, bool no_cck,
-                         u64 *cookie);
+                         bool dont_wait_for_ack, u64 *cookie);
        int     (*mgmt_tx_cancel_wait)(struct wiphy *wiphy,
                                       struct net_device *dev,
                                       u64 cookie);
@@ -1617,6 +1631,11 @@ struct cfg80211_ops {
                             u16 status_code, const u8 *buf, size_t len);
        int     (*tdls_oper)(struct wiphy *wiphy, struct net_device *dev,
                             u8 *peer, enum nl80211_tdls_operation oper);
+
+       int     (*probe_client)(struct wiphy *wiphy, struct net_device *dev,
+                               const u8 *peer, u64 *cookie);
+
+       struct ieee80211_channel *(*get_channel)(struct wiphy *wiphy);
 };
 
 /*
@@ -1675,6 +1694,12 @@ struct cfg80211_ops {
  *     teardown packets should be sent through the @NL80211_CMD_TDLS_MGMT
  *     command. When this flag is not set, @NL80211_CMD_TDLS_OPER should be
  *     used for asking the driver/firmware to perform a TDLS operation.
+ * @WIPHY_FLAG_HAVE_AP_SME: device integrates AP SME
+ * @WIPHY_FLAG_REPORTS_OBSS: the device will report beacons from other BSSes
+ *     when there are virtual interfaces in AP mode by calling
+ *     cfg80211_report_obss_beacon().
+ * @WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD: When operating as an AP, the device
+ *     responds to probe-requests in hardware.
  */
 enum wiphy_flags {
        WIPHY_FLAG_CUSTOM_REGULATORY            = BIT(0),
@@ -1693,6 +1718,9 @@ enum wiphy_flags {
        WIPHY_FLAG_AP_UAPSD                     = BIT(14),
        WIPHY_FLAG_SUPPORTS_TDLS                = BIT(15),
        WIPHY_FLAG_TDLS_EXTERNAL_SETUP          = BIT(16),
+       WIPHY_FLAG_HAVE_AP_SME                  = BIT(17),
+       WIPHY_FLAG_REPORTS_OBSS                 = BIT(18),
+       WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD        = BIT(19),
 };
 
 /**
@@ -1865,6 +1893,7 @@ struct wiphy_wowlan_support {
  * @software_iftypes: bitmask of software interface types, these are not
  *     subject to any restrictions since they are purely managed in SW.
  * @flags: wiphy flags, see &enum wiphy_flags
+ * @features: features advertised to nl80211, see &enum nl80211_feature_flags.
  * @bss_priv_size: each BSS struct has private data allocated with it,
  *     this variable determines its size
  * @max_scan_ssids: maximum number of SSIDs the device can scan for in
@@ -1903,6 +1932,8 @@ struct wiphy_wowlan_support {
  *     may request, if implemented.
  *
  * @wowlan: WoWLAN support information
+ *
+ * @ap_sme_capa: AP SME capabilities, flags from &enum nl80211_ap_sme_features.
  */
 struct wiphy {
        /* assign these fields before you register the wiphy */
@@ -1924,7 +1955,9 @@ struct wiphy {
        /* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */
        u16 interface_modes;
 
-       u32 flags;
+       u32 flags, features;
+
+       u32 ap_sme_capa;
 
        enum cfg80211_signal_type signal_type;
 
@@ -1956,6 +1989,13 @@ struct wiphy {
        u32 available_antennas_tx;
        u32 available_antennas_rx;
 
+       /*
+        * Bitmap of supported protocols for probe response offloading
+        * see &enum nl80211_probe_resp_offload_support_attr. Only valid
+        * when the wiphy flag @WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD is set.
+        */
+       u32 probe_resp_offload;
+
        /* If multiple wiphys are registered and you're handed e.g.
         * a regular netdev with assigned ieee80211_ptr, you won't
         * know whether it points to a wiphy your driver has registered
@@ -2179,6 +2219,8 @@ struct wireless_dev {
 
        int beacon_interval;
 
+       u32 ap_unexpected_nlpid;
+
 #ifdef CONFIG_CFG80211_WEXT
        /* wext data */
        struct {
@@ -2632,8 +2674,10 @@ void cfg80211_sched_scan_stopped(struct wiphy *wiphy);
  *
  * This informs cfg80211 that BSS information was found and
  * the BSS should be updated/added.
+ *
+ * NOTE: Returns a referenced struct, must be released with cfg80211_put_bss()!
  */
-struct cfg80211_bss*
+struct cfg80211_bss * __must_check
 cfg80211_inform_bss_frame(struct wiphy *wiphy,
                          struct ieee80211_channel *channel,
                          struct ieee80211_mgmt *mgmt, size_t len,
@@ -2655,8 +2699,10 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
  *
  * This informs cfg80211 that BSS information was found and
  * the BSS should be updated/added.
+ *
+ * NOTE: Returns a referenced struct, must be released with cfg80211_put_bss()!
  */
-struct cfg80211_bss*
+struct cfg80211_bss * __must_check
 cfg80211_inform_bss(struct wiphy *wiphy,
                    struct ieee80211_channel *channel,
                    const u8 *bssid,
@@ -3185,6 +3231,64 @@ void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid,
 void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
                                     const u8 *bssid, bool preauth, gfp_t gfp);
 
+/**
+ * cfg80211_rx_spurious_frame - inform userspace about a spurious frame
+ * @dev: The device the frame matched to
+ * @addr: the transmitter address
+ * @gfp: context flags
+ *
+ * This function is used in AP mode (only!) to inform userspace that
+ * a spurious class 3 frame was received, to be able to deauth the
+ * sender.
+ * Returns %true if the frame was passed to userspace (or this failed
+ * for a reason other than not having a subscription.)
+ */
+bool cfg80211_rx_spurious_frame(struct net_device *dev,
+                               const u8 *addr, gfp_t gfp);
+
+/**
+ * cfg80211_rx_unexpected_4addr_frame - inform about unexpected WDS frame
+ * @dev: The device the frame matched to
+ * @addr: the transmitter address
+ * @gfp: context flags
+ *
+ * This function is used in AP mode (only!) to inform userspace that
+ * an associated station sent a 4addr frame but that wasn't expected.
+ * It is allowed and desirable to send this event only once for each
+ * station to avoid event flooding.
+ * Returns %true if the frame was passed to userspace (or this failed
+ * for a reason other than not having a subscription.)
+ */
+bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev,
+                                       const u8 *addr, gfp_t gfp);
+
+/**
+ * cfg80211_probe_status - notify userspace about probe status
+ * @dev: the device the probe was sent on
+ * @addr: the address of the peer
+ * @cookie: the cookie filled in @probe_client previously
+ * @acked: indicates whether probe was acked or not
+ * @gfp: allocation flags
+ */
+void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
+                          u64 cookie, bool acked, gfp_t gfp);
+
+/**
+ * cfg80211_report_obss_beacon - report beacon from other APs
+ * @wiphy: The wiphy that received the beacon
+ * @frame: the frame
+ * @len: length of the frame
+ * @freq: frequency the frame was received on
+ * @gfp: allocation flags
+ *
+ * Use this function to report to userspace when a beacon was
+ * received. It is not useful to call this when there is no
+ * netdev that is in AP/GO mode.
+ */
+void cfg80211_report_obss_beacon(struct wiphy *wiphy,
+                                const u8 *frame, size_t len,
+                                int freq, gfp_t gfp);
+
 /* Logging, debugging and troubleshooting/diagnostic helpers. */
 
 /* wiphy_printk helpers, similar to dev_printk */
index f0698b9..75d6156 100644 (file)
@@ -31,8 +31,8 @@ struct icmp_err {
 extern const struct icmp_err icmp_err_convert[];
 #define ICMP_INC_STATS(net, field)     SNMP_INC_STATS((net)->mib.icmp_statistics, field)
 #define ICMP_INC_STATS_BH(net, field)  SNMP_INC_STATS_BH((net)->mib.icmp_statistics, field)
-#define ICMPMSGOUT_INC_STATS(net, field)       SNMP_INC_STATS((net)->mib.icmpmsg_statistics, field+256)
-#define ICMPMSGIN_INC_STATS_BH(net, field)     SNMP_INC_STATS_BH((net)->mib.icmpmsg_statistics, field)
+#define ICMPMSGOUT_INC_STATS(net, field)       SNMP_INC_STATS_ATOMIC_LONG((net)->mib.icmpmsg_statistics, field+256)
+#define ICMPMSGIN_INC_STATS_BH(net, field)     SNMP_INC_STATS_ATOMIC_LONG((net)->mib.icmpmsg_statistics, field)
 
 struct dst_entry;
 struct net_proto_family;
index 7e2c4d4..7139254 100644 (file)
@@ -271,14 +271,6 @@ enum ieee80211_radiotap_type {
 #define IEEE80211_RADIOTAP_MCS_FEC_LDPC                0x10
 
 
-/* Ugly macro to convert literal channel numbers into their mhz equivalents
- * There are certianly some conditions that will break this (like feeding it '30')
- * but they shouldn't arise since nothing talks on channel 30. */
-#define ieee80211chan2mhz(x) \
-       (((x) <= 14) ? \
-       (((x) == 14) ? 2484 : ((x) * 5) + 2407) : \
-       ((x) + 1000) * 5)
-
 /* helpers */
 static inline int ieee80211_get_radiotap_len(unsigned char *data)
 {
index d52685d..ee59f8b 100644 (file)
  * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
  * Maxim Osipov <maxim.osipov@siemens.com>
  * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
  */
 
 #ifndef NET_IEEE802154_H
 #define NET_IEEE802154_H
 
+#define IEEE802154_MTU                 127
+
 #define IEEE802154_FC_TYPE_BEACON      0x0     /* Frame is beacon */
 #define        IEEE802154_FC_TYPE_DATA         0x1     /* Frame is data */
 #define IEEE802154_FC_TYPE_ACK         0x2     /* Frame is acknowledgment */
@@ -56,6 +59,9 @@
        (((x) & IEEE802154_FC_DAMODE_MASK) >> IEEE802154_FC_DAMODE_SHIFT)
 
 
+/* MAC footer size */
+#define IEEE802154_MFR_SIZE    2 /* 2 octets */
+
 /* MAC's Command Frames Identifiers */
 #define IEEE802154_CMD_ASSOCIATION_REQ         0x01
 #define IEEE802154_CMD_ASSOCIATION_RESP                0x02
index e6db62e..dbf9aab 100644 (file)
@@ -143,9 +143,9 @@ static inline void *inet_csk_ca(const struct sock *sk)
        return (void *)inet_csk(sk)->icsk_ca_priv;
 }
 
-extern struct sock *inet_csk_clone(struct sock *sk,
-                                  const struct request_sock *req,
-                                  const gfp_t priority);
+extern struct sock *inet_csk_clone_lock(const struct sock *sk,
+                                       const struct request_sock *req,
+                                       const gfp_t priority);
 
 enum inet_csk_ack_state_t {
        ICSK_ACK_SCHED  = 1,
index 78c83e6..73a5c26 100644 (file)
@@ -86,7 +86,7 @@ static inline struct inet_peer *inet_getpeer_v6(const struct in6_addr *v6daddr,
 {
        struct inetpeer_addr daddr;
 
-       ipv6_addr_copy((struct in6_addr *)daddr.addr.a6, v6daddr);
+       *(struct in6_addr *)daddr.addr.a6 = *v6daddr;
        daddr.family = AF_INET6;
        return inet_getpeer(&daddr, create);
 }
index eca0ef7..fd1561e 100644 (file)
@@ -450,7 +450,7 @@ extern int ip_options_rcv_srr(struct sk_buff *skb);
  *     Functions provided by ip_sockglue.c
  */
 
-extern int     ip_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);
+extern void    ipv4_pktinfo_prepare(struct sk_buff *skb);
 extern void    ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb);
 extern int     ip_cmsg_send(struct net *net,
                             struct msghdr *msg, struct ipcm_cookie *ipc);
index 873d5be..48fd12e 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/netfilter.h>           /* for union nf_inet_addr */
 #include <linux/ip.h>
 #include <linux/ipv6.h>                        /* for struct ipv6hdr */
-#include <net/ipv6.h>                  /* for ipv6_addr_copy */
+#include <net/ipv6.h>
 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
 #include <net/netfilter/nf_conntrack.h>
 #endif
@@ -119,8 +119,8 @@ ip_vs_fill_iphdr(int af, const void *nh, struct ip_vs_iphdr *iphdr)
                const struct ipv6hdr *iph = nh;
                iphdr->len = sizeof(struct ipv6hdr);
                iphdr->protocol = iph->nexthdr;
-               ipv6_addr_copy(&iphdr->saddr.in6, &iph->saddr);
-               ipv6_addr_copy(&iphdr->daddr.in6, &iph->daddr);
+               iphdr->saddr.in6 = iph->saddr;
+               iphdr->daddr.in6 = iph->daddr;
        } else
 #endif
        {
@@ -137,7 +137,7 @@ static inline void ip_vs_addr_copy(int af, union nf_inet_addr *dst,
 {
 #ifdef CONFIG_IP_VS_IPV6
        if (af == AF_INET6)
-               ipv6_addr_copy(&dst->in6, &src->in6);
+               dst->in6 = src->in6;
        else
 #endif
        dst->ip = src->ip;
index a366a8a..f35188e 100644 (file)
@@ -132,6 +132,15 @@ extern struct ctl_path net_ipv6_ctl_path[];
        SNMP_INC_STATS##modifier((net)->mib.statname##_statistics, (field));\
 })
 
+/* per device and per net counters are atomic_long_t */
+#define _DEVINC_ATOMIC_ATOMIC(net, statname, idev, field)              \
+({                                                                     \
+       struct inet6_dev *_idev = (idev);                               \
+       if (likely(_idev != NULL))                                      \
+               SNMP_INC_STATS_ATOMIC_LONG((_idev)->stats.statname##dev, (field)); \
+       SNMP_INC_STATS_ATOMIC_LONG((net)->mib.statname##_statistics, (field));\
+})
+
 #define _DEVADD(net, statname, modifier, idev, field, val)             \
 ({                                                                     \
        struct inet6_dev *_idev = (idev);                               \
@@ -168,11 +177,11 @@ extern struct ctl_path net_ipv6_ctl_path[];
                _DEVINCATOMIC(net, icmpv6, _BH, idev, field)
 
 #define ICMP6MSGOUT_INC_STATS(net, idev, field)                \
-       _DEVINCATOMIC(net, icmpv6msg, , idev, field +256)
+       _DEVINC_ATOMIC_ATOMIC(net, icmpv6msg, idev, field +256)
 #define ICMP6MSGOUT_INC_STATS_BH(net, idev, field)     \
-       _DEVINCATOMIC(net, icmpv6msg, _BH, idev, field +256)
+       _DEVINC_ATOMIC_ATOMIC(net, icmpv6msg, idev, field +256)
 #define ICMP6MSGIN_INC_STATS_BH(net, idev, field)      \
-       _DEVINCATOMIC(net, icmpv6msg, _BH, idev, field)
+       _DEVINC_ATOMIC_ATOMIC(net, icmpv6msg, idev, field)
 
 struct ip6_ra_chain {
        struct ip6_ra_chain     *next;
@@ -300,11 +309,6 @@ ipv6_masked_addr_cmp(const struct in6_addr *a1, const struct in6_addr *m,
                  ((a1->s6_addr32[3] ^ a2->s6_addr32[3]) & m->s6_addr32[3]));
 }
 
-static inline void ipv6_addr_copy(struct in6_addr *a1, const struct in6_addr *a2)
-{
-       memcpy(a1, a2, sizeof(struct in6_addr));
-}
-
 static inline void ipv6_addr_prefix(struct in6_addr *pfx, 
                                    const struct in6_addr *addr,
                                    int plen)
index 72eddd1..0756049 100644 (file)
@@ -166,6 +166,7 @@ struct ieee80211_low_level_stats {
  *     that it is only ever disabled for station mode.
  * @BSS_CHANGED_IDLE: Idle changed for this BSS/interface.
  * @BSS_CHANGED_SSID: SSID changed for this BSS (AP mode)
+ * @BSS_CHANGED_AP_PROBE_RESP: Probe Response changed for this BSS (AP mode)
  */
 enum ieee80211_bss_change {
        BSS_CHANGED_ASSOC               = 1<<0,
@@ -184,6 +185,7 @@ enum ieee80211_bss_change {
        BSS_CHANGED_QOS                 = 1<<13,
        BSS_CHANGED_IDLE                = 1<<14,
        BSS_CHANGED_SSID                = 1<<15,
+       BSS_CHANGED_AP_PROBE_RESP       = 1<<16,
 
        /* when adding here, make sure to change ieee80211_reconfig */
 };
@@ -518,7 +520,7 @@ struct ieee80211_tx_rate {
  * @flags: transmit info flags, defined above
  * @band: the band to transmit on (use for checking for races)
  * @antenna_sel_tx: antenna to use, 0 for automatic diversity
- * @pad: padding, ignore
+ * @ack_frame_id: internal frame ID for TX status, used internally
  * @control: union for control data
  * @status: union for status data
  * @driver_data: array of driver_data pointers
@@ -535,8 +537,7 @@ struct ieee80211_tx_info {
 
        u8 antenna_sel_tx;
 
-       /* 2 byte hole */
-       u8 pad[2];
+       u16 ack_frame_id;
 
        union {
                struct {
@@ -901,6 +902,10 @@ static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif)
  * @IEEE80211_KEY_FLAG_SW_MGMT: This flag should be set by the driver for a
  *     CCMP key if it requires CCMP encryption of management frames (MFP) to
  *     be done in software.
+ * @IEEE80211_KEY_FLAG_PUT_IV_SPACE: This flag should be set by the driver
+ *     for a CCMP key if space should be prepared for the IV, but the IV
+ *     itself should not be generated. Do not set together with
+ *     @IEEE80211_KEY_FLAG_GENERATE_IV on the same key.
  */
 enum ieee80211_key_flags {
        IEEE80211_KEY_FLAG_WMM_STA      = 1<<0,
@@ -908,6 +913,7 @@ enum ieee80211_key_flags {
        IEEE80211_KEY_FLAG_GENERATE_MMIC= 1<<2,
        IEEE80211_KEY_FLAG_PAIRWISE     = 1<<3,
        IEEE80211_KEY_FLAG_SW_MGMT      = 1<<4,
+       IEEE80211_KEY_FLAG_PUT_IV_SPACE = 1<<5,
 };
 
 /**
@@ -1304,6 +1310,16 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
 }
 
 /**
+ * ieee80211_free_txskb - free TX skb
+ * @hw: the hardware
+ * @skb: the skb
+ *
+ * Free a transmit skb. Use this funtion when some failure
+ * to transmit happened and thus status cannot be reported.
+ */
+void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
+
+/**
  * DOC: Hardware crypto acceleration
  *
  * mac80211 is capable of taking advantage of many hardware
@@ -2661,6 +2677,19 @@ static inline struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
 }
 
 /**
+ * ieee80211_proberesp_get - retrieve a Probe Response template
+ * @hw: pointer obtained from ieee80211_alloc_hw().
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ *
+ * Creates a Probe Response template which can, for example, be uploaded to
+ * hardware. The destination address should be set by the caller.
+ *
+ * Can only be called in AP mode.
+ */
+struct sk_buff *ieee80211_proberesp_get(struct ieee80211_hw *hw,
+                                       struct ieee80211_vif *vif);
+
+/**
  * ieee80211_pspoll_get - retrieve a PS Poll template
  * @hw: pointer obtained from ieee80211_alloc_hw().
  * @vif: &struct ieee80211_vif pointer from the add_interface callback.
index 2720884..7ae5acf 100644 (file)
@@ -59,7 +59,7 @@ struct neigh_parms {
        int     reachable_time;
        int     delay_probe_time;
 
-       int     queue_len;
+       int     queue_len_bytes;
        int     ucast_probes;
        int     app_probes;
        int     mcast_probes;
@@ -99,6 +99,7 @@ struct neighbour {
        rwlock_t                lock;
        atomic_t                refcnt;
        struct sk_buff_head     arp_queue;
+       unsigned int            arp_queue_len_bytes;
        struct timer_list       timer;
        unsigned long           used;
        atomic_t                probes;
index 0b44112..30f6728 100644 (file)
@@ -10,7 +10,7 @@ struct netns_mib {
        DEFINE_SNMP_STAT(struct udp_mib, udp_statistics);
        DEFINE_SNMP_STAT(struct udp_mib, udplite_statistics);
        DEFINE_SNMP_STAT(struct icmp_mib, icmp_statistics);
-       DEFINE_SNMP_STAT(struct icmpmsg_mib, icmpmsg_statistics);
+       DEFINE_SNMP_STAT_ATOMIC(struct icmpmsg_mib, icmpmsg_statistics);
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
        struct proc_dir_entry *proc_net_devsnmp6;
@@ -18,7 +18,7 @@ struct netns_mib {
        DEFINE_SNMP_STAT(struct udp_mib, udplite_stats_in6);
        DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics);
        DEFINE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics);
-       DEFINE_SNMP_STAT(struct icmpv6msg_mib, icmpv6msg_statistics);
+       DEFINE_SNMP_STAT_ATOMIC(struct icmpv6msg_mib, icmpv6msg_statistics);
 #endif
 #ifdef CONFIG_XFRM_STATISTICS
        DEFINE_SNMP_STAT(struct linux_xfrm_mib, xfrm_statistics);
diff --git a/include/net/netprio_cgroup.h b/include/net/netprio_cgroup.h
new file mode 100644 (file)
index 0000000..e503b87
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * netprio_cgroup.h                    Control Group Priority set
+ *
+ *
+ * Authors:    Neil Horman <nhorman@tuxdriver.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.
+ *
+ */
+
+#ifndef _NETPRIO_CGROUP_H
+#define _NETPRIO_CGROUP_H
+#include <linux/module.h>
+#include <linux/cgroup.h>
+#include <linux/hardirq.h>
+#include <linux/rcupdate.h>
+
+
+struct netprio_map {
+       struct rcu_head rcu;
+       u32 priomap_len;
+       u32 priomap[];
+};
+
+#ifdef CONFIG_CGROUPS
+
+struct cgroup_netprio_state {
+       struct cgroup_subsys_state css;
+       u32 prioidx;
+};
+
+#ifndef CONFIG_NETPRIO_CGROUP
+extern int net_prio_subsys_id;
+#endif
+
+extern void sock_update_netprioidx(struct sock *sk);
+
+static inline struct cgroup_netprio_state
+               *task_netprio_state(struct task_struct *p)
+{
+#if IS_ENABLED(CONFIG_NETPRIO_CGROUP)
+       return container_of(task_subsys_state(p, net_prio_subsys_id),
+                           struct cgroup_netprio_state, css);
+#else
+       return NULL;
+#endif
+}
+
+#else
+
+#define sock_update_netprioidx(sk)
+#endif
+
+#endif  /* _NET_CLS_CGROUP_H */
index 39b85bc..cdbe671 100644 (file)
 /* NCI Status Codes */
 #define        NCI_STATUS_OK                                           0x00
 #define        NCI_STATUS_REJECTED                                     0x01
-#define        NCI_STATUS_MESSAGE_CORRUPTED                            0x02
-#define        NCI_STATUS_BUFFER_FULL                                  0x03
-#define        NCI_STATUS_FAILED                                       0x04
-#define        NCI_STATUS_NOT_INITIALIZED                              0x05
-#define        NCI_STATUS_SYNTAX_ERROR                                 0x06
-#define        NCI_STATUS_SEMANTIC_ERROR                               0x07
-#define        NCI_STATUS_UNKNOWN_GID                                  0x08
-#define        NCI_STATUS_UNKNOWN_OID                                  0x09
-#define        NCI_STATUS_INVALID_PARAM                                0x0a
-#define        NCI_STATUS_MESSAGE_SIZE_EXCEEDED                        0x0b
+#define        NCI_STATUS_RF_FRAME_CORRUPTED                           0x02
+#define        NCI_STATUS_FAILED                                       0x03
+#define        NCI_STATUS_NOT_INITIALIZED                              0x04
+#define        NCI_STATUS_SYNTAX_ERROR                                 0x05
+#define        NCI_STATUS_SEMANTIC_ERROR                               0x06
+#define        NCI_STATUS_UNKNOWN_GID                                  0x07
+#define        NCI_STATUS_UNKNOWN_OID                                  0x08
+#define        NCI_STATUS_INVALID_PARAM                                0x09
+#define        NCI_STATUS_MESSAGE_SIZE_EXCEEDED                        0x0a
 /* Discovery Specific Status Codes */
 #define        NCI_STATUS_DISCOVERY_ALREADY_STARTED                    0xa0
 #define        NCI_STATUS_DISCOVERY_TARGET_ACTIVATION_FAILED           0xa1
+#define        NCI_STATUS_DISCOVERY_TEAR_DOWN                          0xa2
 /* RF Interface Specific Status Codes */
 #define        NCI_STATUS_RF_TRANSMISSION_ERROR                        0xb0
 #define        NCI_STATUS_RF_PROTOCOL_ERROR                            0xb1
 #define        NCI_STATUS_RF_TIMEOUT_ERROR                             0xb2
-#define        NCI_STATUS_RF_LINK_LOSS_ERROR                           0xb3
 /* NFCEE Interface Specific Status Codes */
 #define        NCI_STATUS_MAX_ACTIVE_NFCEE_INTERFACES_REACHED          0xc0
 #define        NCI_STATUS_NFCEE_INTERFACE_ACTIVATION_FAILED            0xc1
 #define NCI_NFC_A_ACTIVE_LISTEN_MODE                           0x83
 #define NCI_NFC_F_ACTIVE_LISTEN_MODE                           0x85
 
+/* NCI RF Technologies */
+#define NCI_NFC_RF_TECHNOLOGY_A                                        0x00
+#define NCI_NFC_RF_TECHNOLOGY_B                                        0x01
+#define NCI_NFC_RF_TECHNOLOGY_F                                        0x02
+#define NCI_NFC_RF_TECHNOLOGY_15693                            0x03
+
+/* NCI Bit Rates */
+#define NCI_NFC_BIT_RATE_106                                   0x00
+#define NCI_NFC_BIT_RATE_212                                   0x01
+#define NCI_NFC_BIT_RATE_424                                   0x02
+#define NCI_NFC_BIT_RATE_848                                   0x03
+#define NCI_NFC_BIT_RATE_1696                                  0x04
+#define NCI_NFC_BIT_RATE_3392                                  0x05
+#define NCI_NFC_BIT_RATE_6784                                  0x06
+
 /* NCI RF Protocols */
 #define NCI_RF_PROTOCOL_UNKNOWN                                        0x00
 #define NCI_RF_PROTOCOL_T1T                                    0x01
 #define NCI_RF_PROTOCOL_NFC_DEP                                        0x05
 
 /* NCI RF Interfaces */
-#define NCI_RF_INTERFACE_RFU                                   0x00
+#define NCI_RF_INTERFACE_NFCEE_DIRECT                          0x00
 #define        NCI_RF_INTERFACE_FRAME                                  0x01
 #define        NCI_RF_INTERFACE_ISO_DEP                                0x02
 #define        NCI_RF_INTERFACE_NFC_DEP                                0x03
 
+/* NCI Reset types */
+#define NCI_RESET_TYPE_KEEP_CONFIG                             0x00
+#define NCI_RESET_TYPE_RESET_CONFIG                            0x01
+
+/* NCI Static RF connection ID */
+#define NCI_STATIC_RF_CONN_ID                                  0x00
+
+/* NCI Data Flow Control */
+#define NCI_DATA_FLOW_CONTROL_NOT_USED                         0xff
+
 /* NCI RF_DISCOVER_MAP_CMD modes */
 #define NCI_DISC_MAP_MODE_POLL                                 0x01
 #define NCI_DISC_MAP_MODE_LISTEN                               0x02
 #define        NCI_DISCOVERY_TYPE_POLL_F_PASSIVE                       0x02
 #define        NCI_DISCOVERY_TYPE_POLL_A_ACTIVE                        0x03
 #define        NCI_DISCOVERY_TYPE_POLL_F_ACTIVE                        0x05
-#define        NCI_DISCOVERY_TYPE_WAKEUP_A_PASSIVE                     0x06
-#define        NCI_DISCOVERY_TYPE_WAKEUP_B_PASSIVE                     0x07
 #define        NCI_DISCOVERY_TYPE_WAKEUP_A_ACTIVE                      0x09
 #define        NCI_DISCOVERY_TYPE_LISTEN_A_PASSIVE                     0x80
 #define        NCI_DISCOVERY_TYPE_LISTEN_B_PASSIVE                     0x81
 #define        NCI_DEACTIVATE_TYPE_IDLE_MODE                           0x00
 #define        NCI_DEACTIVATE_TYPE_SLEEP_MODE                          0x01
 #define        NCI_DEACTIVATE_TYPE_SLEEP_AF_MODE                       0x02
-#define        NCI_DEACTIVATE_TYPE_RF_LINK_LOSS                        0x03
-#define        NCI_DEACTIVATE_TYPE_DISCOVERY_ERROR                     0x04
+#define        NCI_DEACTIVATE_TYPE_DISCOVERY                           0x03
 
 /* Message Type (MT) */
 #define NCI_MT_DATA_PKT                                                0x00
@@ -169,18 +190,11 @@ struct nci_data_hdr {
 /* -----  NCI Commands ---- */
 /* ------------------------ */
 #define NCI_OP_CORE_RESET_CMD          nci_opcode_pack(NCI_GID_CORE, 0x00)
-
-#define NCI_OP_CORE_INIT_CMD           nci_opcode_pack(NCI_GID_CORE, 0x01)
-
-#define NCI_OP_CORE_SET_CONFIG_CMD     nci_opcode_pack(NCI_GID_CORE, 0x02)
-
-#define NCI_OP_CORE_CONN_CREATE_CMD    nci_opcode_pack(NCI_GID_CORE, 0x04)
-struct nci_core_conn_create_cmd {
-       __u8    target_handle;
-       __u8    num_target_specific_params;
+struct nci_core_reset_cmd {
+       __u8    reset_type;
 } __packed;
 
-#define NCI_OP_CORE_CONN_CLOSE_CMD     nci_opcode_pack(NCI_GID_CORE, 0x06)
+#define NCI_OP_CORE_INIT_CMD           nci_opcode_pack(NCI_GID_CORE, 0x01)
 
 #define NCI_OP_RF_DISCOVER_MAP_CMD     nci_opcode_pack(NCI_GID_RF_MGMT, 0x00)
 struct disc_map_config {
@@ -218,6 +232,7 @@ struct nci_rf_deactivate_cmd {
 struct nci_core_reset_rsp {
        __u8    status;
        __u8    nci_ver;
+       __u8    config_status;
 } __packed;
 
 #define NCI_OP_CORE_INIT_RSP           nci_opcode_pack(NCI_GID_CORE, 0x01)
@@ -232,24 +247,14 @@ struct nci_core_init_rsp_1 {
 struct nci_core_init_rsp_2 {
        __u8    max_logical_connections;
        __le16  max_routing_table_size;
-       __u8    max_control_packet_payload_length;
-       __le16  rf_sending_buffer_size;
-       __le16  rf_receiving_buffer_size;
-       __le16  manufacturer_id;
-} __packed;
-
-#define NCI_OP_CORE_SET_CONFIG_RSP     nci_opcode_pack(NCI_GID_CORE, 0x02)
-
-#define NCI_OP_CORE_CONN_CREATE_RSP    nci_opcode_pack(NCI_GID_CORE, 0x04)
-struct nci_core_conn_create_rsp {
-       __u8    status;
-       __u8    max_pkt_payload_size;
+       __u8    max_ctrl_pkt_payload_len;
+       __le16  max_size_for_large_params;
+       __u8    max_data_pkt_payload_size;
        __u8    initial_num_credits;
-       __u8    conn_id;
+       __u8    manufact_id;
+       __le32  manufact_specific_info;
 } __packed;
 
-#define NCI_OP_CORE_CONN_CLOSE_RSP     nci_opcode_pack(NCI_GID_CORE, 0x06)
-
 #define NCI_OP_RF_DISCOVER_MAP_RSP     nci_opcode_pack(NCI_GID_RF_MGMT, 0x00)
 
 #define NCI_OP_RF_DISCOVER_RSP         nci_opcode_pack(NCI_GID_RF_MGMT, 0x03)
@@ -270,12 +275,7 @@ struct nci_core_conn_credit_ntf {
        struct conn_credit_entry        conn_entries[NCI_MAX_NUM_CONN];
 } __packed;
 
-#define NCI_OP_RF_FIELD_INFO_NTF       nci_opcode_pack(NCI_GID_CORE, 0x08)
-struct nci_rf_field_info_ntf {
-       __u8    rf_field_status;
-} __packed;
-
-#define NCI_OP_RF_ACTIVATE_NTF         nci_opcode_pack(NCI_GID_RF_MGMT, 0x05)
+#define NCI_OP_RF_INTF_ACTIVATED_NTF   nci_opcode_pack(NCI_GID_RF_MGMT, 0x05)
 struct rf_tech_specific_params_nfca_poll {
        __u16   sens_res;
        __u8    nfcid1_len;     /* 0, 4, 7, or 10 Bytes */
@@ -289,17 +289,20 @@ struct activation_params_nfca_poll_iso_dep {
        __u8    rats_res[20];
 };
 
-struct nci_rf_activate_ntf {
-       __u8    target_handle;
+struct nci_rf_intf_activated_ntf {
+       __u8    rf_discovery_id;
+       __u8    rf_interface_type;
        __u8    rf_protocol;
-       __u8    rf_tech_and_mode;
+       __u8    activation_rf_tech_and_mode;
        __u8    rf_tech_specific_params_len;
 
        union {
                struct rf_tech_specific_params_nfca_poll nfca_poll;
        } rf_tech_specific_params;
 
-       __u8    rf_interface_type;
+       __u8    data_exch_rf_tech_and_mode;
+       __u8    data_exch_tx_bit_rate;
+       __u8    data_exch_rx_bit_rate;
        __u8    activation_params_len;
 
        union {
@@ -309,5 +312,9 @@ struct nci_rf_activate_ntf {
 } __packed;
 
 #define NCI_OP_RF_DEACTIVATE_NTF       nci_opcode_pack(NCI_GID_RF_MGMT, 0x06)
+struct nci_rf_deactivate_ntf {
+       __u8    type;
+       __u8    reason;
+} __packed;
 
 #endif /* __NCI_H */
index b8b4bbd..c92b69d 100644 (file)
@@ -109,15 +109,12 @@ struct nci_dev {
                                [NCI_MAX_SUPPORTED_RF_INTERFACES];
        __u8                    max_logical_connections;
        __u16                   max_routing_table_size;
-       __u8                    max_control_packet_payload_length;
-       __u16                   rf_sending_buffer_size;
-       __u16                   rf_receiving_buffer_size;
-       __u16                   manufacturer_id;
-
-       /* received during NCI_OP_CORE_CONN_CREATE_RSP for static conn 0 */
-       __u8                    max_pkt_payload_size;
+       __u8                    max_ctrl_pkt_payload_len;
+       __u16                   max_size_for_large_params;
+       __u8                    max_data_pkt_payload_size;
        __u8                    initial_num_credits;
-       __u8                    conn_id;
+       __u8                    manufact_id;
+       __u32                   manufact_specific_info;
 
        /* stored during nci_data_exchange */
        data_exchange_cb_t      data_exchange_cb;
index 6f7eb80..e182e13 100644 (file)
@@ -38,7 +38,7 @@ struct net_protocol {
        void                    (*err_handler)(struct sk_buff *skb, u32 info);
        int                     (*gso_send_check)(struct sk_buff *skb);
        struct sk_buff         *(*gso_segment)(struct sk_buff *skb,
-                                              u32 features);
+                                              netdev_features_t features);
        struct sk_buff        **(*gro_receive)(struct sk_buff **head,
                                               struct sk_buff *skb);
        int                     (*gro_complete)(struct sk_buff *skb);
@@ -57,7 +57,7 @@ struct inet6_protocol {
 
        int     (*gso_send_check)(struct sk_buff *skb);
        struct sk_buff *(*gso_segment)(struct sk_buff *skb,
-                                      u32 features);
+                                      netdev_features_t features);
        struct sk_buff **(*gro_receive)(struct sk_buff **head,
                                        struct sk_buff *skb);
        int     (*gro_complete)(struct sk_buff *skb);
index e90e7a9..3382615 100644 (file)
@@ -1085,6 +1085,7 @@ void sctp_transport_burst_reset(struct sctp_transport *);
 unsigned long sctp_transport_timeout(struct sctp_transport *);
 void sctp_transport_reset(struct sctp_transport *);
 void sctp_transport_update_pmtu(struct sctp_transport *, u32);
+void sctp_transport_immediate_rtx(struct sctp_transport *);
 
 
 /* This is the structure we use to queue packets as they come into
index 8f0f9ac..2f65e16 100644 (file)
@@ -67,7 +67,7 @@ struct icmp_mib {
 
 #define ICMPMSG_MIB_MAX        __ICMPMSG_MIB_MAX
 struct icmpmsg_mib {
-       unsigned long   mibs[ICMPMSG_MIB_MAX];
+       atomic_long_t   mibs[ICMPMSG_MIB_MAX];
 };
 
 /* ICMP6 (IPv6-ICMP) */
@@ -84,7 +84,7 @@ struct icmpv6_mib_device {
 #define ICMP6MSG_MIB_MAX  __ICMP6MSG_MIB_MAX
 /* per network ns counters */
 struct icmpv6msg_mib {
-       unsigned long   mibs[ICMP6MSG_MIB_MAX];
+       atomic_long_t   mibs[ICMP6MSG_MIB_MAX];
 };
 /* per device counters, (shared on all cpus) */
 struct icmpv6msg_mib_device {
index abb6e0f..8ac338c 100644 (file)
@@ -306,8 +306,8 @@ struct sock {
        kmemcheck_bitfield_end(flags);
        int                     sk_wmem_queued;
        gfp_t                   sk_allocation;
-       int                     sk_route_caps;
-       int                     sk_route_nocaps;
+       netdev_features_t       sk_route_caps;
+       netdev_features_t       sk_route_nocaps;
        int                     sk_gso_type;
        unsigned int            sk_gso_max_size;
        int                     sk_rcvlowat;
@@ -320,6 +320,9 @@ struct sock {
        unsigned short          sk_ack_backlog;
        unsigned short          sk_max_ack_backlog;
        __u32                   sk_priority;
+#ifdef CONFIG_CGROUPS
+       __u32                   sk_cgrp_prioidx;
+#endif
        struct pid              *sk_peer_pid;
        const struct cred       *sk_peer_cred;
        long                    sk_rcvtimeo;
@@ -563,6 +566,7 @@ enum sock_flags {
        SOCK_FASYNC, /* fasync() active */
        SOCK_RXQ_OVFL,
        SOCK_ZEROCOPY, /* buffers from userspace */
+       SOCK_WIFI_STATUS, /* push wifi status to userspace */
 };
 
 static inline void sock_copy_flags(struct sock *nsk, struct sock *osk)
@@ -1089,8 +1093,8 @@ extern struct sock                *sk_alloc(struct net *net, int family,
                                          struct proto *prot);
 extern void                    sk_free(struct sock *sk);
 extern void                    sk_release_kernel(struct sock *sk);
-extern struct sock             *sk_clone(const struct sock *sk,
-                                         const gfp_t priority);
+extern struct sock             *sk_clone_lock(const struct sock *sk,
+                                              const gfp_t priority);
 
 extern struct sk_buff          *sock_wmalloc(struct sock *sk,
                                              unsigned long size, int force,
@@ -1393,7 +1397,7 @@ static inline int sk_can_gso(const struct sock *sk)
 
 extern void sk_setup_caps(struct sock *sk, struct dst_entry *dst);
 
-static inline void sk_nocaps_add(struct sock *sk, int flags)
+static inline void sk_nocaps_add(struct sock *sk, netdev_features_t flags)
 {
        sk->sk_route_nocaps |= flags;
        sk->sk_route_caps &= ~flags;
@@ -1714,6 +1718,8 @@ static inline int sock_intr_errno(long timeo)
 
 extern void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
        struct sk_buff *skb);
+extern void __sock_recv_wifi_status(struct msghdr *msg, struct sock *sk,
+       struct sk_buff *skb);
 
 static __inline__ void
 sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
@@ -1741,6 +1747,9 @@ sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
                __sock_recv_timestamp(msg, sk, skb);
        else
                sk->sk_stamp = kt;
+
+       if (sock_flag(sk, SOCK_WIFI_STATUS) && skb->wifi_acked_valid)
+               __sock_recv_wifi_status(msg, sk, skb);
 }
 
 extern void __sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk,
index bb18c4d..113160b 100644 (file)
@@ -1430,7 +1430,8 @@ extern struct request_sock_ops tcp6_request_sock_ops;
 extern void tcp_v4_destroy_sock(struct sock *sk);
 
 extern int tcp_v4_gso_send_check(struct sk_buff *skb);
-extern struct sk_buff *tcp_tso_segment(struct sk_buff *skb, u32 features);
+extern struct sk_buff *tcp_tso_segment(struct sk_buff *skb,
+                                      netdev_features_t features);
 extern struct sk_buff **tcp_gro_receive(struct sk_buff **head,
                                        struct sk_buff *skb);
 extern struct sk_buff **tcp4_gro_receive(struct sk_buff **head,
index 3b285f4..f54a515 100644 (file)
@@ -258,5 +258,6 @@ extern void udp4_proc_exit(void);
 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, u32 features);
+extern struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb,
+       netdev_features_t features);
 #endif /* _UDP_H */
index b203e14..89174e2 100644 (file)
@@ -827,6 +827,14 @@ static inline bool addr_match(const void *token1, const void *token2,
        return true;
 }
 
+static inline bool addr4_match(__be32 a1, __be32 a2, u8 prefixlen)
+{
+       /* C99 6.5.7 (3): u32 << 32 is undefined behaviour */
+       if (prefixlen == 0)
+               return true;
+       return !((a1 ^ a2) & htonl(0xFFFFFFFFu << (32 - prefixlen)));
+}
+
 static __inline__
 __be16 xfrm_flowi_sport(const struct flowi *fl, const union flowi_uli *uli)
 {
@@ -1209,8 +1217,8 @@ void xfrm_flowi_addr_get(const struct flowi *fl,
                memcpy(&daddr->a4, &fl->u.ip4.daddr, sizeof(daddr->a4));
                break;
        case AF_INET6:
-               ipv6_addr_copy((struct in6_addr *)&saddr->a6, &fl->u.ip6.saddr);
-               ipv6_addr_copy((struct in6_addr *)&daddr->a6, &fl->u.ip6.daddr);
+               *(struct in6_addr *)saddr->a6 = fl->u.ip6.saddr;
+               *(struct in6_addr *)daddr->a6 = fl->u.ip6.daddr;
                break;
        }
 }
index a785a3b..438c256 100644 (file)
@@ -29,8 +29,7 @@
 static inline int xen_must_unplug_nics(void) {
 #if (defined(CONFIG_XEN_NETDEV_FRONTEND) || \
                defined(CONFIG_XEN_NETDEV_FRONTEND_MODULE)) && \
-               (defined(CONFIG_XEN_PLATFORM_PCI) || \
-                defined(CONFIG_XEN_PLATFORM_PCI_MODULE))
+               defined(CONFIG_XEN_PVHVM)
         return 1;
 #else
         return 0;
@@ -40,8 +39,7 @@ static inline int xen_must_unplug_nics(void) {
 static inline int xen_must_unplug_disks(void) {
 #if (defined(CONFIG_XEN_BLKDEV_FRONTEND) || \
                defined(CONFIG_XEN_BLKDEV_FRONTEND_MODULE)) && \
-               (defined(CONFIG_XEN_PLATFORM_PCI) || \
-                defined(CONFIG_XEN_PLATFORM_PCI_MODULE))
+               defined(CONFIG_XEN_PVHVM)
         return 1;
 #else
         return 0;
index aa57d5d..b5f4742 100644 (file)
@@ -115,7 +115,7 @@ static int misrouted_irq(int irq)
        struct irq_desc *desc;
        int i, ok = 0;
 
-       if (atomic_inc_return(&irq_poll_active) == 1)
+       if (atomic_inc_return(&irq_poll_active) != 1)
                goto out;
 
        irq_poll_cpu = smp_processor_id();
index b4511b6..196c012 100644 (file)
@@ -55,6 +55,8 @@ enum {
 
 static int hibernation_mode = HIBERNATION_SHUTDOWN;
 
+static bool freezer_test_done;
+
 static const struct platform_hibernation_ops *hibernation_ops;
 
 /**
@@ -347,6 +349,17 @@ int hibernation_snapshot(int platform_mode)
        if (error)
                goto Close;
 
+       if (hibernation_test(TEST_FREEZER) ||
+               hibernation_testmode(HIBERNATION_TESTPROC)) {
+
+               /*
+                * Indicate to the caller that we are returning due to a
+                * successful freezer test.
+                */
+               freezer_test_done = true;
+               goto Close;
+       }
+
        error = dpm_prepare(PMSG_FREEZE);
        if (error)
                goto Complete_devices;
@@ -641,15 +654,13 @@ int hibernate(void)
        if (error)
                goto Finish;
 
-       if (hibernation_test(TEST_FREEZER))
-               goto Thaw;
-
-       if (hibernation_testmode(HIBERNATION_TESTPROC))
-               goto Thaw;
-
        error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM);
        if (error)
                goto Thaw;
+       if (freezer_test_done) {
+               freezer_test_done = false;
+               goto Thaw;
+       }
 
        if (in_suspend) {
                unsigned int flags = 0;
index 71f49fe..36e0f09 100644 (file)
@@ -290,13 +290,14 @@ static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
                if (*s && len == strlen(*s) && !strncmp(buf, *s, len))
                        break;
        }
-       if (state < PM_SUSPEND_MAX && *s)
+       if (state < PM_SUSPEND_MAX && *s) {
                error = enter_state(state);
                if (error) {
                        suspend_stats.fail++;
                        dpm_save_failed_errno(error);
                } else
                        suspend_stats.success++;
+       }
 #endif
 
  Exit:
index 56db751..995e3bd 100644 (file)
@@ -70,6 +70,7 @@ static struct pm_qos_constraints cpu_dma_constraints = {
 };
 static struct pm_qos_object cpu_dma_pm_qos = {
        .constraints = &cpu_dma_constraints,
+       .name = "cpu_dma_latency",
 };
 
 static BLOCKING_NOTIFIER_HEAD(network_lat_notifier);
index 993599e..8e75003 100644 (file)
@@ -777,6 +777,18 @@ char *uuid_string(char *buf, char *end, const u8 *addr,
        return string(buf, end, uuid, spec);
 }
 
+static
+char *netdev_feature_string(char *buf, char *end, const u8 *addr,
+                     struct printf_spec spec)
+{
+       spec.flags |= SPECIAL | SMALL | ZEROPAD;
+       if (spec.field_width == -1)
+               spec.field_width = 2 + 2 * sizeof(netdev_features_t);
+       spec.base = 16;
+
+       return number(buf, end, *(const netdev_features_t *)addr, spec);
+}
+
 int kptr_restrict __read_mostly;
 
 /*
@@ -824,6 +836,7 @@ int kptr_restrict __read_mostly;
  *       Do not use this feature without some mechanism to verify the
  *       correctness of the format string and va_list arguments.
  * - 'K' For a kernel pointer that should be hidden from unprivileged users
+ * - 'NF' For a netdev_features_t
  *
  * Note: The difference between 'S' and 'F' is that on ia64 and ppc64
  * function pointers are really function descriptors, which contain a
@@ -896,6 +909,12 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
                       has_capability_noaudit(current, CAP_SYSLOG))))
                        ptr = NULL;
                break;
+       case 'N':
+               switch (fmt[1]) {
+               case 'F':
+                       return netdev_feature_string(buf, end, ptr, spec);
+               }
+               break;
        }
        spec.flags |= SMALL;
        if (spec.field_width == -1) {
index a086064..71034f4 100644 (file)
@@ -724,6 +724,14 @@ void bdi_destroy(struct backing_dev_info *bdi)
 
        bdi_unregister(bdi);
 
+       /*
+        * If bdi_unregister() had already been called earlier, the
+        * wakeup_timer could still be armed because bdi_prune_sb()
+        * can race with the bdi_wakeup_thread_delayed() calls from
+        * __mark_inode_dirty().
+        */
+       del_timer_sync(&bdi->wb.wakeup_timer);
+
        for (i = 0; i < NR_BDI_STAT_ITEMS; i++)
                percpu_counter_destroy(&bdi->bdi_stat[i]);
 
index dae27ba..bb28a5f 100644 (file)
@@ -2422,6 +2422,8 @@ retry_avoidcopy:
         * anon_vma prepared.
         */
        if (unlikely(anon_vma_prepare(vma))) {
+               page_cache_release(new_page);
+               page_cache_release(old_page);
                /* Caller expects lock to be held */
                spin_lock(&mm->page_table_lock);
                return VM_FAULT_OOM;
index 73419c5..b982290 100644 (file)
@@ -454,7 +454,7 @@ void  __attribute__((weak)) vmalloc_sync_all(void)
  *     between processes, it syncs the pagetable across all
  *     processes.
  */
-struct vm_struct *alloc_vm_area(size_t size)
+struct vm_struct *alloc_vm_area(size_t size, pte_t **ptes)
 {
        BUG();
        return NULL;
index 471dedb..76f2c5a 100644 (file)
@@ -185,6 +185,11 @@ unsigned int oom_badness(struct task_struct *p, struct mem_cgroup *mem,
        if (!p)
                return 0;
 
+       if (p->signal->oom_score_adj == OOM_SCORE_ADJ_MIN) {
+               task_unlock(p);
+               return 0;
+       }
+
        /*
         * The memory controller may have a limit of 0 bytes, so avoid a divide
         * by zero, if necessary.
index b669aa6..3231bf3 100644 (file)
@@ -2141,23 +2141,30 @@ void  __attribute__((weak)) vmalloc_sync_all(void)
 
 static int f(pte_t *pte, pgtable_t table, unsigned long addr, void *data)
 {
-       /* apply_to_page_range() does all the hard work. */
+       pte_t ***p = data;
+
+       if (p) {
+               *(*p) = pte;
+               (*p)++;
+       }
        return 0;
 }
 
 /**
  *     alloc_vm_area - allocate a range of kernel address space
  *     @size:          size of the area
+ *     @ptes:          returns the PTEs for the address space
  *
  *     Returns:        NULL on failure, vm_struct on success
  *
  *     This function reserves a range of kernel address space, and
  *     allocates pagetables to map that range.  No actual mappings
- *     are created.  If the kernel address space is not shared
- *     between processes, it syncs the pagetable across all
- *     processes.
+ *     are created.
+ *
+ *     If @ptes is non-NULL, pointers to the PTEs (in init_mm)
+ *     allocated for the VM area are returned.
  */
-struct vm_struct *alloc_vm_area(size_t size)
+struct vm_struct *alloc_vm_area(size_t size, pte_t **ptes)
 {
        struct vm_struct *area;
 
@@ -2171,19 +2178,11 @@ struct vm_struct *alloc_vm_area(size_t size)
         * of kernel virtual address space and mapped into init_mm.
         */
        if (apply_to_page_range(&init_mm, (unsigned long)area->addr,
-                               area->size, f, NULL)) {
+                               size, f, ptes ? &ptes : NULL)) {
                free_vm_area(area);
                return NULL;
        }
 
-       /*
-        * If the allocated address space is passed to a hypercall
-        * before being used then we cannot rely on a page fault to
-        * trigger an update of the page tables.  So sync all the page
-        * tables here.
-        */
-       vmalloc_sync_all();
-
        return area;
 }
 EXPORT_SYMBOL_GPL(alloc_vm_area);
index bc25286..2b5fcde 100644 (file)
@@ -591,18 +591,17 @@ static void vlan_dev_uninit(struct net_device *dev)
        }
 }
 
-static u32 vlan_dev_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t vlan_dev_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        struct net_device *real_dev = vlan_dev_info(dev)->real_dev;
        u32 old_features = features;
 
-       features &= real_dev->features;
        features &= real_dev->vlan_features;
+       features |= NETIF_F_RXCSUM;
+       features &= real_dev->features;
 
        features |= old_features & NETIF_F_SOFT_FEATURES;
-
-       if (dev_ethtool_get_rx_csum(real_dev))
-               features |= NETIF_F_RXCSUM;
        features |= NETIF_F_LLTX;
 
        return features;
index a073148..63d2c5d 100644 (file)
@@ -232,6 +232,13 @@ config XPS
        depends on SMP && SYSFS && USE_GENERIC_SMP_HELPERS
        default y
 
+config NETPRIO_CGROUP
+       tristate "Network priority cgroup"
+       depends on CGROUPS
+       ---help---
+         Cgroup subsystem for use in assigning processes to network priorities on
+         a per-interface basis
+
 config HAVE_BPF_JIT
        bool
 
index d07223c..53b0aa1 100644 (file)
@@ -489,15 +489,11 @@ free_skb:
  */
 static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg)
 {
-       struct sk_buff_head queue;
-       int err;
        struct br2684_vcc *brvcc;
-       struct sk_buff *skb, *tmp;
-       struct sk_buff_head *rq;
        struct br2684_dev *brdev;
        struct net_device *net_dev;
        struct atm_backend_br2684 be;
-       unsigned long flags;
+       int err;
 
        if (copy_from_user(&be, arg, sizeof be))
                return -EFAULT;
@@ -550,23 +546,6 @@ static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg)
        atmvcc->push = br2684_push;
        atmvcc->pop = br2684_pop;
 
-       __skb_queue_head_init(&queue);
-       rq = &sk_atm(atmvcc)->sk_receive_queue;
-
-       spin_lock_irqsave(&rq->lock, flags);
-       skb_queue_splice_init(rq, &queue);
-       spin_unlock_irqrestore(&rq->lock, flags);
-
-       skb_queue_walk_safe(&queue, skb, tmp) {
-               struct net_device *dev;
-
-               br2684_push(atmvcc, skb);
-               dev = skb->dev;
-
-               dev->stats.rx_bytes -= skb->len;
-               dev->stats.rx_packets--;
-       }
-
        /* initialize netdev carrier state */
        if (atmvcc->dev->signal == ATM_PHY_SIG_LOST)
                netif_carrier_off(net_dev);
@@ -574,6 +553,10 @@ static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg)
                netif_carrier_on(net_dev);
 
        __module_get(THIS_MODULE);
+
+       /* re-process everything received between connection setup and
+          backend setup */
+       vcc_process_recv_queue(atmvcc);
        return 0;
 
 error:
index 8523940..11439a7 100644 (file)
@@ -189,6 +189,13 @@ static void clip_push(struct atm_vcc *vcc, struct sk_buff *skb)
        struct clip_vcc *clip_vcc = CLIP_VCC(vcc);
 
        pr_debug("\n");
+
+       if (!clip_devs) {
+               atm_return(vcc, skb->truesize);
+               kfree_skb(skb);
+               return;
+       }
+
        if (!skb) {
                pr_debug("removing VCC %p\n", clip_vcc);
                if (clip_vcc->entry)
@@ -329,7 +336,7 @@ static struct neigh_table clip_tbl = {
                .gc_staletime           = 60 * HZ,
                .reachable_time         = 30 * HZ,
                .delay_probe_time       = 5 * HZ,
-               .queue_len              = 3,
+               .queue_len_bytes        = 64 * 1024,
                .ucast_probes           = 3,
                .mcast_probes           = 3,
                .anycast_delay          = 1 * HZ,
@@ -448,10 +455,7 @@ static netdev_tx_t clip_start_xmit(struct sk_buff *skb,
 
 static int clip_mkip(struct atm_vcc *vcc, int timeout)
 {
-       struct sk_buff_head *rq, queue;
        struct clip_vcc *clip_vcc;
-       struct sk_buff *skb, *tmp;
-       unsigned long flags;
 
        if (!vcc->push)
                return -EBADFD;
@@ -472,29 +476,9 @@ static int clip_mkip(struct atm_vcc *vcc, int timeout)
        vcc->push = clip_push;
        vcc->pop = clip_pop;
 
-       __skb_queue_head_init(&queue);
-       rq = &sk_atm(vcc)->sk_receive_queue;
-
-       spin_lock_irqsave(&rq->lock, flags);
-       skb_queue_splice_init(rq, &queue);
-       spin_unlock_irqrestore(&rq->lock, flags);
-
        /* re-process everything received between connection setup and MKIP */
-       skb_queue_walk_safe(&queue, skb, tmp) {
-               if (!clip_devs) {
-                       atm_return(vcc, skb->truesize);
-                       kfree_skb(skb);
-               } else {
-                       struct net_device *dev = skb->dev;
-                       unsigned int len = skb->len;
-
-                       skb_get(skb);
-                       clip_push(vcc, skb);
-                       dev->stats.rx_packets--;
-                       dev->stats.rx_bytes -= len;
-                       kfree_skb(skb);
-               }
-       }
+       vcc_process_recv_queue(vcc);
+
        return 0;
 }
 
index 14ff9fe..b4b44db 100644 (file)
@@ -214,6 +214,26 @@ void vcc_release_async(struct atm_vcc *vcc, int reply)
 }
 EXPORT_SYMBOL(vcc_release_async);
 
+void vcc_process_recv_queue(struct atm_vcc *vcc)
+{
+       struct sk_buff_head queue, *rq;
+       struct sk_buff *skb, *tmp;
+       unsigned long flags;
+
+       __skb_queue_head_init(&queue);
+       rq = &sk_atm(vcc)->sk_receive_queue;
+
+       spin_lock_irqsave(&rq->lock, flags);
+       skb_queue_splice_init(rq, &queue);
+       spin_unlock_irqrestore(&rq->lock, flags);
+
+       skb_queue_walk_safe(&queue, skb, tmp) {
+               __skb_unlink(skb, &queue);
+               vcc->push(vcc, skb);
+       }
+}
+EXPORT_SYMBOL(vcc_process_recv_queue);
+
 void atm_dev_signal_change(struct atm_dev *dev, char signal)
 {
        pr_debug("%s signal=%d dev=%p number=%d dev->signal=%d\n",
@@ -502,8 +522,11 @@ int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
 
        if (sock->state != SS_CONNECTED)
                return -ENOTCONN;
-       if (flags & ~MSG_DONTWAIT)              /* only handle MSG_DONTWAIT */
+
+       /* only handle MSG_DONTWAIT and MSG_PEEK */
+       if (flags & ~(MSG_DONTWAIT | MSG_PEEK))
                return -EOPNOTSUPP;
+
        vcc = ATM_SD(sock);
        if (test_bit(ATM_VF_RELEASED, &vcc->flags) ||
            test_bit(ATM_VF_CLOSE, &vcc->flags) ||
@@ -524,8 +547,13 @@ int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
        if (error)
                return error;
        sock_recv_ts_and_drops(msg, sk, skb);
-       pr_debug("%d -= %d\n", atomic_read(&sk->sk_rmem_alloc), skb->truesize);
-       atm_return(vcc, skb->truesize);
+
+       if (!(flags & MSG_PEEK)) {
+               pr_debug("%d -= %d\n", atomic_read(&sk->sk_rmem_alloc),
+                        skb->truesize);
+               atm_return(vcc, skb->truesize);
+       }
+
        skb_free_datagram(sk, skb);
        return copied;
 }
index f48a76b..cc3c2da 100644 (file)
@@ -24,6 +24,7 @@ int vcc_setsockopt(struct socket *sock, int level, int optname,
                   char __user *optval, unsigned int optlen);
 int vcc_getsockopt(struct socket *sock, int level, int optname,
                   char __user *optval, int __user *optlen);
+void vcc_process_recv_queue(struct atm_vcc *vcc);
 
 int atmpvc_init(void);
 void atmpvc_exit(void);
index db4a11c..df35d9a 100644 (file)
@@ -303,6 +303,10 @@ static int pppoatm_assign_vcc(struct atm_vcc *atmvcc, void __user *arg)
        atmvcc->push = pppoatm_push;
        atmvcc->pop = pppoatm_pop;
        __module_get(THIS_MODULE);
+
+       /* re-process everything received between connection setup and
+          backend setup */
+       vcc_process_recv_queue(atmvcc);
        return 0;
 }
 
index 91bcd3a..a6cd856 100644 (file)
@@ -65,15 +65,13 @@ static DECLARE_RWSEM(bnep_session_sem);
 static struct bnep_session *__bnep_get_session(u8 *dst)
 {
        struct bnep_session *s;
-       struct list_head *p;
 
        BT_DBG("");
 
-       list_for_each(p, &bnep_session_list) {
-               s = list_entry(p, struct bnep_session, list);
+       list_for_each_entry(s, &bnep_session_list, list)
                if (!compare_ether_addr(dst, s->eh.h_source))
                        return s;
-       }
+
        return NULL;
 }
 
@@ -667,17 +665,14 @@ static void __bnep_copy_ci(struct bnep_conninfo *ci, struct bnep_session *s)
 
 int bnep_get_connlist(struct bnep_connlist_req *req)
 {
-       struct list_head *p;
+       struct bnep_session *s;
        int err = 0, n = 0;
 
        down_read(&bnep_session_sem);
 
-       list_for_each(p, &bnep_session_list) {
-               struct bnep_session *s;
+       list_for_each_entry(s, &bnep_session_list, list) {
                struct bnep_conninfo ci;
 
-               s = list_entry(p, struct bnep_session, list);
-
                __bnep_copy_ci(&ci, s);
 
                if (copy_to_user(req->ci, &ci, sizeof(ci))) {
index 7d00ddf..9e8940b 100644 (file)
@@ -53,15 +53,13 @@ static LIST_HEAD(cmtp_session_list);
 static struct cmtp_session *__cmtp_get_session(bdaddr_t *bdaddr)
 {
        struct cmtp_session *session;
-       struct list_head *p;
 
        BT_DBG("");
 
-       list_for_each(p, &cmtp_session_list) {
-               session = list_entry(p, struct cmtp_session, list);
+       list_for_each_entry(session, &cmtp_session_list, list)
                if (!bacmp(bdaddr, &session->bdaddr))
                        return session;
-       }
+
        return NULL;
 }
 
@@ -431,19 +429,16 @@ int cmtp_del_connection(struct cmtp_conndel_req *req)
 
 int cmtp_get_connlist(struct cmtp_connlist_req *req)
 {
-       struct list_head *p;
+       struct cmtp_session *session;
        int err = 0, n = 0;
 
        BT_DBG("");
 
        down_read(&cmtp_session_sem);
 
-       list_for_each(p, &cmtp_session_list) {
-               struct cmtp_session *session;
+       list_for_each_entry(session, &cmtp_session_list, list) {
                struct cmtp_conninfo ci;
 
-               session = list_entry(p, struct cmtp_session, list);
-
                __cmtp_copy_session(session, &ci);
 
                if (copy_to_user(req->ci, &ci, sizeof(ci))) {
index c1c597e..de0b93e 100644 (file)
@@ -374,6 +374,8 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
 
        skb_queue_head_init(&conn->data_q);
 
+       hci_chan_hash_init(conn);
+
        setup_timer(&conn->disc_timer, hci_conn_timeout, (unsigned long)conn);
        setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn);
        setup_timer(&conn->auto_accept_timer, hci_conn_auto_accept,
@@ -432,6 +434,8 @@ int hci_conn_del(struct hci_conn *conn)
 
        tasklet_disable(&hdev->tx_task);
 
+       hci_chan_hash_flush(conn);
+
        hci_conn_hash_del(hdev, conn);
        if (hdev->notify)
                hdev->notify(hdev, HCI_NOTIFY_CONN_DEL);
@@ -453,16 +457,13 @@ int hci_conn_del(struct hci_conn *conn)
 struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
 {
        int use_src = bacmp(src, BDADDR_ANY);
-       struct hci_dev *hdev = NULL;
-       struct list_head *p;
+       struct hci_dev *hdev = NULL, *d;
 
        BT_DBG("%s -> %s", batostr(src), batostr(dst));
 
        read_lock_bh(&hci_dev_list_lock);
 
-       list_for_each(p, &hci_dev_list) {
-               struct hci_dev *d = list_entry(p, struct hci_dev, list);
-
+       list_for_each_entry(d, &hci_dev_list, list) {
                if (!test_bit(HCI_UP, &d->flags) || test_bit(HCI_RAW, &d->flags))
                        continue;
 
@@ -673,7 +674,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
                goto encrypt;
 
 auth:
-       if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
+       if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
                return 0;
 
        if (!hci_conn_auth(conn, sec_level, auth_type))
@@ -819,7 +820,7 @@ void hci_conn_hash_flush(struct hci_dev *hdev)
 
                c->state = BT_CLOSED;
 
-               hci_proto_disconn_cfm(c, 0x16);
+               hci_proto_disconn_cfm(c, HCI_ERROR_LOCAL_HOST_TERM);
                hci_conn_del(c);
        }
 }
@@ -855,10 +856,10 @@ EXPORT_SYMBOL(hci_conn_put_device);
 
 int hci_get_conn_list(void __user *arg)
 {
+       register struct hci_conn *c;
        struct hci_conn_list_req req, *cl;
        struct hci_conn_info *ci;
        struct hci_dev *hdev;
-       struct list_head *p;
        int n = 0, size, err;
 
        if (copy_from_user(&req, arg, sizeof(req)))
@@ -882,10 +883,7 @@ int hci_get_conn_list(void __user *arg)
        ci = cl->conn_info;
 
        hci_dev_lock_bh(hdev);
-       list_for_each(p, &hdev->conn_hash.list) {
-               register struct hci_conn *c;
-               c = list_entry(p, struct hci_conn, list);
-
+       list_for_each_entry(c, &hdev->conn_hash.list, list) {
                bacpy(&(ci + n)->bdaddr, &c->dst);
                (ci + n)->handle = c->handle;
                (ci + n)->type  = c->type;
@@ -956,3 +954,52 @@ int hci_get_auth_info(struct hci_dev *hdev, void __user *arg)
 
        return copy_to_user(arg, &req, sizeof(req)) ? -EFAULT : 0;
 }
+
+struct hci_chan *hci_chan_create(struct hci_conn *conn)
+{
+       struct hci_dev *hdev = conn->hdev;
+       struct hci_chan *chan;
+
+       BT_DBG("%s conn %p", hdev->name, conn);
+
+       chan = kzalloc(sizeof(struct hci_chan), GFP_ATOMIC);
+       if (!chan)
+               return NULL;
+
+       chan->conn = conn;
+       skb_queue_head_init(&chan->data_q);
+
+       tasklet_disable(&hdev->tx_task);
+       hci_chan_hash_add(conn, chan);
+       tasklet_enable(&hdev->tx_task);
+
+       return chan;
+}
+
+int hci_chan_del(struct hci_chan *chan)
+{
+       struct hci_conn *conn = chan->conn;
+       struct hci_dev *hdev = conn->hdev;
+
+       BT_DBG("%s conn %p chan %p", hdev->name, conn, chan);
+
+       tasklet_disable(&hdev->tx_task);
+       hci_chan_hash_del(conn, chan);
+       tasklet_enable(&hdev->tx_task);
+
+       skb_queue_purge(&chan->data_q);
+       kfree(chan);
+
+       return 0;
+}
+
+void hci_chan_hash_flush(struct hci_conn *conn)
+{
+       struct hci_chan_hash *h = &conn->chan_hash;
+       struct hci_chan *chan, *tmp;
+
+       BT_DBG("conn %p", conn);
+
+       list_for_each_entry_safe(chan, tmp, &h->list, list)
+               hci_chan_del(chan);
+}
index be84ae3..fb3feeb 100644 (file)
@@ -319,8 +319,7 @@ static void hci_linkpol_req(struct hci_dev *hdev, unsigned long opt)
  * Device is held on return. */
 struct hci_dev *hci_dev_get(int index)
 {
-       struct hci_dev *hdev = NULL;
-       struct list_head *p;
+       struct hci_dev *hdev = NULL, *d;
 
        BT_DBG("%d", index);
 
@@ -328,8 +327,7 @@ struct hci_dev *hci_dev_get(int index)
                return NULL;
 
        read_lock(&hci_dev_list_lock);
-       list_for_each(p, &hci_dev_list) {
-               struct hci_dev *d = list_entry(p, struct hci_dev, list);
+       list_for_each_entry(d, &hci_dev_list, list) {
                if (d->id == index) {
                        hdev = hci_dev_hold(d);
                        break;
@@ -551,8 +549,11 @@ int hci_dev_open(__u16 dev)
                hci_dev_hold(hdev);
                set_bit(HCI_UP, &hdev->flags);
                hci_notify(hdev, HCI_DEV_UP);
-               if (!test_bit(HCI_SETUP, &hdev->flags))
-                       mgmt_powered(hdev->id, 1);
+               if (!test_bit(HCI_SETUP, &hdev->flags)) {
+                       hci_dev_lock_bh(hdev);
+                       mgmt_powered(hdev, 1);
+                       hci_dev_unlock_bh(hdev);
+               }
        } else {
                /* Init failed, cleanup */
                tasklet_kill(&hdev->rx_task);
@@ -597,6 +598,14 @@ static int hci_dev_do_close(struct hci_dev *hdev)
        tasklet_kill(&hdev->rx_task);
        tasklet_kill(&hdev->tx_task);
 
+       if (hdev->discov_timeout > 0) {
+               cancel_delayed_work(&hdev->discov_off);
+               hdev->discov_timeout = 0;
+       }
+
+       if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
+               cancel_delayed_work(&hdev->power_off);
+
        hci_dev_lock_bh(hdev);
        inquiry_cache_flush(hdev);
        hci_conn_hash_flush(hdev);
@@ -636,7 +645,9 @@ static int hci_dev_do_close(struct hci_dev *hdev)
         * and no tasks are scheduled. */
        hdev->close(hdev);
 
-       mgmt_powered(hdev->id, 0);
+       hci_dev_lock_bh(hdev);
+       mgmt_powered(hdev, 0);
+       hci_dev_unlock_bh(hdev);
 
        /* Clear flags */
        hdev->flags = 0;
@@ -794,9 +805,9 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg)
 
 int hci_get_dev_list(void __user *arg)
 {
+       struct hci_dev *hdev;
        struct hci_dev_list_req *dl;
        struct hci_dev_req *dr;
-       struct list_head *p;
        int n = 0, size, err;
        __u16 dev_num;
 
@@ -815,12 +826,9 @@ int hci_get_dev_list(void __user *arg)
        dr = dl->dev_req;
 
        read_lock_bh(&hci_dev_list_lock);
-       list_for_each(p, &hci_dev_list) {
-               struct hci_dev *hdev;
-
-               hdev = list_entry(p, struct hci_dev, list);
-
-               hci_del_off_timer(hdev);
+       list_for_each_entry(hdev, &hci_dev_list, list) {
+               if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
+                       cancel_delayed_work(&hdev->power_off);
 
                if (!test_bit(HCI_MGMT, &hdev->flags))
                        set_bit(HCI_PAIRABLE, &hdev->flags);
@@ -855,7 +863,8 @@ int hci_get_dev_info(void __user *arg)
        if (!hdev)
                return -ENODEV;
 
-       hci_del_off_timer(hdev);
+       if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
+               cancel_delayed_work_sync(&hdev->power_off);
 
        if (!test_bit(HCI_MGMT, &hdev->flags))
                set_bit(HCI_PAIRABLE, &hdev->flags);
@@ -912,6 +921,7 @@ struct hci_dev *hci_alloc_dev(void)
        if (!hdev)
                return NULL;
 
+       hci_init_sysfs(hdev);
        skb_queue_head_init(&hdev->driver_init);
 
        return hdev;
@@ -938,39 +948,41 @@ static void hci_power_on(struct work_struct *work)
                return;
 
        if (test_bit(HCI_AUTO_OFF, &hdev->flags))
-               mod_timer(&hdev->off_timer,
-                               jiffies + msecs_to_jiffies(AUTO_OFF_TIMEOUT));
+               queue_delayed_work(hdev->workqueue, &hdev->power_off,
+                                       msecs_to_jiffies(AUTO_OFF_TIMEOUT));
 
        if (test_and_clear_bit(HCI_SETUP, &hdev->flags))
-               mgmt_index_added(hdev->id);
+               mgmt_index_added(hdev);
 }
 
 static void hci_power_off(struct work_struct *work)
 {
-       struct hci_dev *hdev = container_of(work, struct hci_dev, power_off);
+       struct hci_dev *hdev = container_of(work, struct hci_dev,
+                                                       power_off.work);
 
        BT_DBG("%s", hdev->name);
 
+       clear_bit(HCI_AUTO_OFF, &hdev->flags);
+
        hci_dev_close(hdev->id);
 }
 
-static void hci_auto_off(unsigned long data)
+static void hci_discov_off(struct work_struct *work)
 {
-       struct hci_dev *hdev = (struct hci_dev *) data;
+       struct hci_dev *hdev;
+       u8 scan = SCAN_PAGE;
+
+       hdev = container_of(work, struct hci_dev, discov_off.work);
 
        BT_DBG("%s", hdev->name);
 
-       clear_bit(HCI_AUTO_OFF, &hdev->flags);
+       hci_dev_lock_bh(hdev);
 
-       queue_work(hdev->workqueue, &hdev->power_off);
-}
+       hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
 
-void hci_del_off_timer(struct hci_dev *hdev)
-{
-       BT_DBG("%s", hdev->name);
+       hdev->discov_timeout = 0;
 
-       clear_bit(HCI_AUTO_OFF, &hdev->flags);
-       del_timer(&hdev->off_timer);
+       hci_dev_unlock_bh(hdev);
 }
 
 int hci_uuids_clear(struct hci_dev *hdev)
@@ -1007,16 +1019,11 @@ int hci_link_keys_clear(struct hci_dev *hdev)
 
 struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
 {
-       struct list_head *p;
-
-       list_for_each(p, &hdev->link_keys) {
-               struct link_key *k;
-
-               k = list_entry(p, struct link_key, list);
+       struct link_key *k;
 
+       list_for_each_entry(k, &hdev->link_keys, list)
                if (bacmp(bdaddr, &k->bdaddr) == 0)
                        return k;
-       }
 
        return NULL;
 }
@@ -1138,7 +1145,7 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
 
        persistent = hci_persistent_key(hdev, conn, type, old_key_type);
 
-       mgmt_new_key(hdev->id, key, persistent);
+       mgmt_new_link_key(hdev, key, persistent);
 
        if (!persistent) {
                list_del(&key->list);
@@ -1181,7 +1188,7 @@ int hci_add_ltk(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
        memcpy(id->rand, rand, sizeof(id->rand));
 
        if (new_key)
-               mgmt_new_key(hdev->id, key, old_key_type);
+               mgmt_new_link_key(hdev, key, old_key_type);
 
        return 0;
 }
@@ -1279,16 +1286,11 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
 struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev,
                                                bdaddr_t *bdaddr)
 {
-       struct list_head *p;
-
-       list_for_each(p, &hdev->blacklist) {
-               struct bdaddr_list *b;
-
-               b = list_entry(p, struct bdaddr_list, list);
+       struct bdaddr_list *b;
 
+       list_for_each_entry(b, &hdev->blacklist, list)
                if (bacmp(bdaddr, &b->bdaddr) == 0)
                        return b;
-       }
 
        return NULL;
 }
@@ -1327,7 +1329,7 @@ int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr)
 
        list_add(&entry->list, &hdev->blacklist);
 
-       return mgmt_device_blocked(hdev->id, bdaddr);
+       return mgmt_device_blocked(hdev, bdaddr);
 }
 
 int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr)
@@ -1346,7 +1348,7 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr)
        list_del(&entry->list);
        kfree(entry);
 
-       return mgmt_device_unblocked(hdev->id, bdaddr);
+       return mgmt_device_unblocked(hdev, bdaddr);
 }
 
 static void hci_clear_adv_cache(unsigned long arg)
@@ -1425,7 +1427,7 @@ int hci_add_adv_entry(struct hci_dev *hdev,
 int hci_register_dev(struct hci_dev *hdev)
 {
        struct list_head *head = &hci_dev_list, *p;
-       int i, id = 0;
+       int i, id, error;
 
        BT_DBG("%p name %s bus %d owner %p", hdev, hdev->name,
                                                hdev->bus, hdev->owner);
@@ -1433,6 +1435,11 @@ int hci_register_dev(struct hci_dev *hdev)
        if (!hdev->open || !hdev->close || !hdev->destruct)
                return -EINVAL;
 
+       /* Do not allow HCI_AMP devices to register at index 0,
+        * so the index can be used as the AMP controller ID.
+        */
+       id = (hdev->dev_type == HCI_BREDR) ? 0 : 1;
+
        write_lock_bh(&hci_dev_list_lock);
 
        /* Find first available device id */
@@ -1479,6 +1486,8 @@ int hci_register_dev(struct hci_dev *hdev)
 
        hci_conn_hash_init(hdev);
 
+       INIT_LIST_HEAD(&hdev->mgmt_pending);
+
        INIT_LIST_HEAD(&hdev->blacklist);
 
        INIT_LIST_HEAD(&hdev->uuids);
@@ -1492,8 +1501,9 @@ int hci_register_dev(struct hci_dev *hdev)
                                                (unsigned long) hdev);
 
        INIT_WORK(&hdev->power_on, hci_power_on);
-       INIT_WORK(&hdev->power_off, hci_power_off);
-       setup_timer(&hdev->off_timer, hci_auto_off, (unsigned long) hdev);
+       INIT_DELAYED_WORK(&hdev->power_off, hci_power_off);
+
+       INIT_DELAYED_WORK(&hdev->discov_off, hci_discov_off);
 
        memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
 
@@ -1502,10 +1512,14 @@ int hci_register_dev(struct hci_dev *hdev)
        write_unlock_bh(&hci_dev_list_lock);
 
        hdev->workqueue = create_singlethread_workqueue(hdev->name);
-       if (!hdev->workqueue)
-               goto nomem;
+       if (!hdev->workqueue) {
+               error = -ENOMEM;
+               goto err;
+       }
 
-       hci_register_sysfs(hdev);
+       error = hci_add_sysfs(hdev);
+       if (error < 0)
+               goto err_wqueue;
 
        hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev,
                                RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops, hdev);
@@ -1524,17 +1538,19 @@ int hci_register_dev(struct hci_dev *hdev)
 
        return id;
 
-nomem:
+err_wqueue:
+       destroy_workqueue(hdev->workqueue);
+err:
        write_lock_bh(&hci_dev_list_lock);
        list_del(&hdev->list);
        write_unlock_bh(&hci_dev_list_lock);
 
-       return -ENOMEM;
+       return error;
 }
 EXPORT_SYMBOL(hci_register_dev);
 
 /* Unregister HCI device */
-int hci_unregister_dev(struct hci_dev *hdev)
+void hci_unregister_dev(struct hci_dev *hdev)
 {
        int i;
 
@@ -1550,8 +1566,15 @@ int hci_unregister_dev(struct hci_dev *hdev)
                kfree_skb(hdev->reassembly[i]);
 
        if (!test_bit(HCI_INIT, &hdev->flags) &&
-                                       !test_bit(HCI_SETUP, &hdev->flags))
-               mgmt_index_removed(hdev->id);
+                                       !test_bit(HCI_SETUP, &hdev->flags)) {
+               hci_dev_lock_bh(hdev);
+               mgmt_index_removed(hdev);
+               hci_dev_unlock_bh(hdev);
+       }
+
+       /* mgmt_index_removed should take care of emptying the
+        * pending list */
+       BUG_ON(!list_empty(&hdev->mgmt_pending));
 
        hci_notify(hdev, HCI_DEV_UNREG);
 
@@ -1560,9 +1583,8 @@ int hci_unregister_dev(struct hci_dev *hdev)
                rfkill_destroy(hdev->rfkill);
        }
 
-       hci_unregister_sysfs(hdev);
+       hci_del_sysfs(hdev);
 
-       hci_del_off_timer(hdev);
        del_timer(&hdev->adv_timer);
 
        destroy_workqueue(hdev->workqueue);
@@ -1576,8 +1598,6 @@ int hci_unregister_dev(struct hci_dev *hdev)
        hci_dev_unlock_bh(hdev);
 
        __hci_dev_put(hdev);
-
-       return 0;
 }
 EXPORT_SYMBOL(hci_unregister_dev);
 
@@ -1948,23 +1968,18 @@ static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags)
        hdr->dlen   = cpu_to_le16(len);
 }
 
-void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
+static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue,
+                               struct sk_buff *skb, __u16 flags)
 {
        struct hci_dev *hdev = conn->hdev;
        struct sk_buff *list;
 
-       BT_DBG("%s conn %p flags 0x%x", hdev->name, conn, flags);
-
-       skb->dev = (void *) hdev;
-       bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
-       hci_add_acl_hdr(skb, conn->handle, flags);
-
        list = skb_shinfo(skb)->frag_list;
        if (!list) {
                /* Non fragmented */
                BT_DBG("%s nonfrag skb %p len %d", hdev->name, skb, skb->len);
 
-               skb_queue_tail(&conn->data_q, skb);
+               skb_queue_tail(queue, skb);
        } else {
                /* Fragmented */
                BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
@@ -1972,9 +1987,9 @@ void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
                skb_shinfo(skb)->frag_list = NULL;
 
                /* Queue all fragments atomically */
-               spin_lock_bh(&conn->data_q.lock);
+               spin_lock_bh(&queue->lock);
 
-               __skb_queue_tail(&conn->data_q, skb);
+               __skb_queue_tail(queue, skb);
 
                flags &= ~ACL_START;
                flags |= ACL_CONT;
@@ -1987,11 +2002,25 @@ void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
 
                        BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
 
-                       __skb_queue_tail(&conn->data_q, skb);
+                       __skb_queue_tail(queue, skb);
                } while (list);
 
-               spin_unlock_bh(&conn->data_q.lock);
+               spin_unlock_bh(&queue->lock);
        }
+}
+
+void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags)
+{
+       struct hci_conn *conn = chan->conn;
+       struct hci_dev *hdev = conn->hdev;
+
+       BT_DBG("%s chan %p flags 0x%x", hdev->name, chan, flags);
+
+       skb->dev = (void *) hdev;
+       bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
+       hci_add_acl_hdr(skb, conn->handle, flags);
+
+       hci_queue_acl(conn, &chan->data_q, skb, flags);
 
        tasklet_schedule(&hdev->tx_task);
 }
@@ -2026,16 +2055,12 @@ EXPORT_SYMBOL(hci_send_sco);
 static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote)
 {
        struct hci_conn_hash *h = &hdev->conn_hash;
-       struct hci_conn *conn = NULL;
+       struct hci_conn *conn = NULL, *c;
        int num = 0, min = ~0;
-       struct list_head *p;
 
        /* We don't have to lock device here. Connections are always
         * added and removed with TX task disabled. */
-       list_for_each(p, &h->list) {
-               struct hci_conn *c;
-               c = list_entry(p, struct hci_conn, list);
-
+       list_for_each_entry(c, &h->list, list) {
                if (c->type != type || skb_queue_empty(&c->data_q))
                        continue;
 
@@ -2084,14 +2109,12 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
 static inline void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
 {
        struct hci_conn_hash *h = &hdev->conn_hash;
-       struct list_head *p;
-       struct hci_conn  *c;
+       struct hci_conn *c;
 
        BT_ERR("%s link tx timeout", hdev->name);
 
        /* Kill stalled connections */
-       list_for_each(p, &h->list) {
-               c = list_entry(p, struct hci_conn, list);
+       list_for_each_entry(c, &h->list, list) {
                if (c->type == type && c->sent) {
                        BT_ERR("%s killing stalled connection %s",
                                hdev->name, batostr(&c->dst));
@@ -2100,11 +2123,137 @@ static inline void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
        }
 }
 
-static inline void hci_sched_acl(struct hci_dev *hdev)
+static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
+                                               int *quote)
 {
+       struct hci_conn_hash *h = &hdev->conn_hash;
+       struct hci_chan *chan = NULL;
+       int num = 0, min = ~0, cur_prio = 0;
        struct hci_conn *conn;
+       int cnt, q, conn_num = 0;
+
+       BT_DBG("%s", hdev->name);
+
+       list_for_each_entry(conn, &h->list, list) {
+               struct hci_chan_hash *ch;
+               struct hci_chan *tmp;
+
+               if (conn->type != type)
+                       continue;
+
+               if (conn->state != BT_CONNECTED && conn->state != BT_CONFIG)
+                       continue;
+
+               conn_num++;
+
+               ch = &conn->chan_hash;
+
+               list_for_each_entry(tmp, &ch->list, list) {
+                       struct sk_buff *skb;
+
+                       if (skb_queue_empty(&tmp->data_q))
+                               continue;
+
+                       skb = skb_peek(&tmp->data_q);
+                       if (skb->priority < cur_prio)
+                               continue;
+
+                       if (skb->priority > cur_prio) {
+                               num = 0;
+                               min = ~0;
+                               cur_prio = skb->priority;
+                       }
+
+                       num++;
+
+                       if (conn->sent < min) {
+                               min  = conn->sent;
+                               chan = tmp;
+                       }
+               }
+
+               if (hci_conn_num(hdev, type) == conn_num)
+                       break;
+       }
+
+       if (!chan)
+               return NULL;
+
+       switch (chan->conn->type) {
+       case ACL_LINK:
+               cnt = hdev->acl_cnt;
+               break;
+       case SCO_LINK:
+       case ESCO_LINK:
+               cnt = hdev->sco_cnt;
+               break;
+       case LE_LINK:
+               cnt = hdev->le_mtu ? hdev->le_cnt : hdev->acl_cnt;
+               break;
+       default:
+               cnt = 0;
+               BT_ERR("Unknown link type");
+       }
+
+       q = cnt / num;
+       *quote = q ? q : 1;
+       BT_DBG("chan %p quote %d", chan, *quote);
+       return chan;
+}
+
+static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type)
+{
+       struct hci_conn_hash *h = &hdev->conn_hash;
+       struct hci_conn *conn;
+       int num = 0;
+
+       BT_DBG("%s", hdev->name);
+
+       list_for_each_entry(conn, &h->list, list) {
+               struct hci_chan_hash *ch;
+               struct hci_chan *chan;
+
+               if (conn->type != type)
+                       continue;
+
+               if (conn->state != BT_CONNECTED && conn->state != BT_CONFIG)
+                       continue;
+
+               num++;
+
+               ch = &conn->chan_hash;
+               list_for_each_entry(chan, &ch->list, list) {
+                       struct sk_buff *skb;
+
+                       if (chan->sent) {
+                               chan->sent = 0;
+                               continue;
+                       }
+
+                       if (skb_queue_empty(&chan->data_q))
+                               continue;
+
+                       skb = skb_peek(&chan->data_q);
+                       if (skb->priority >= HCI_PRIO_MAX - 1)
+                               continue;
+
+                       skb->priority = HCI_PRIO_MAX - 1;
+
+                       BT_DBG("chan %p skb %p promoted to %d", chan, skb,
+                                                               skb->priority);
+               }
+
+               if (hci_conn_num(hdev, type) == num)
+                       break;
+       }
+}
+
+static inline void hci_sched_acl(struct hci_dev *hdev)
+{
+       struct hci_chan *chan;
        struct sk_buff *skb;
        int quote;
+       unsigned int cnt;
 
        BT_DBG("%s", hdev->name);
 
@@ -2118,19 +2267,35 @@ static inline void hci_sched_acl(struct hci_dev *hdev)
                        hci_link_tx_to(hdev, ACL_LINK);
        }
 
-       while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, &quote))) {
-               while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
-                       BT_DBG("skb %p len %d", skb, skb->len);
+       cnt = hdev->acl_cnt;
+
+       while (hdev->acl_cnt &&
+                       (chan = hci_chan_sent(hdev, ACL_LINK, &quote))) {
+               u32 priority = (skb_peek(&chan->data_q))->priority;
+               while (quote-- && (skb = skb_peek(&chan->data_q))) {
+                       BT_DBG("chan %p skb %p len %d priority %u", chan, skb,
+                                       skb->len, skb->priority);
 
-                       hci_conn_enter_active_mode(conn, bt_cb(skb)->force_active);
+                       /* Stop if priority has changed */
+                       if (skb->priority < priority)
+                               break;
+
+                       skb = skb_dequeue(&chan->data_q);
+
+                       hci_conn_enter_active_mode(chan->conn,
+                                               bt_cb(skb)->force_active);
 
                        hci_send_frame(skb);
                        hdev->acl_last_tx = jiffies;
 
                        hdev->acl_cnt--;
-                       conn->sent++;
+                       chan->sent++;
+                       chan->conn->sent++;
                }
        }
+
+       if (cnt != hdev->acl_cnt)
+               hci_prio_recalculate(hdev, ACL_LINK);
 }
 
 /* Schedule SCO */
@@ -2182,9 +2347,9 @@ static inline void hci_sched_esco(struct hci_dev *hdev)
 
 static inline void hci_sched_le(struct hci_dev *hdev)
 {
-       struct hci_conn *conn;
+       struct hci_chan *chan;
        struct sk_buff *skb;
-       int quote, cnt;
+       int quote, cnt, tmp;
 
        BT_DBG("%s", hdev->name);
 
@@ -2200,21 +2365,35 @@ static inline void hci_sched_le(struct hci_dev *hdev)
        }
 
        cnt = hdev->le_pkts ? hdev->le_cnt : hdev->acl_cnt;
-       while (cnt && (conn = hci_low_sent(hdev, LE_LINK, &quote))) {
-               while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
-                       BT_DBG("skb %p len %d", skb, skb->len);
+       tmp = cnt;
+       while (cnt && (chan = hci_chan_sent(hdev, LE_LINK, &quote))) {
+               u32 priority = (skb_peek(&chan->data_q))->priority;
+               while (quote-- && (skb = skb_peek(&chan->data_q))) {
+                       BT_DBG("chan %p skb %p len %d priority %u", chan, skb,
+                                       skb->len, skb->priority);
+
+                       /* Stop if priority has changed */
+                       if (skb->priority < priority)
+                               break;
+
+                       skb = skb_dequeue(&chan->data_q);
 
                        hci_send_frame(skb);
                        hdev->le_last_tx = jiffies;
 
                        cnt--;
-                       conn->sent++;
+                       chan->sent++;
+                       chan->conn->sent++;
                }
        }
+
        if (hdev->le_pkts)
                hdev->le_cnt = cnt;
        else
                hdev->acl_cnt = cnt;
+
+       if (cnt != tmp)
+               hci_prio_recalculate(hdev, LE_LINK);
 }
 
 static void hci_tx_task(unsigned long arg)
@@ -2407,3 +2586,31 @@ static void hci_cmd_task(unsigned long arg)
                }
        }
 }
+
+int hci_do_inquiry(struct hci_dev *hdev, u8 length)
+{
+       /* General inquiry access code (GIAC) */
+       u8 lap[3] = { 0x33, 0x8b, 0x9e };
+       struct hci_cp_inquiry cp;
+
+       BT_DBG("%s", hdev->name);
+
+       if (test_bit(HCI_INQUIRY, &hdev->flags))
+               return -EINPROGRESS;
+
+       memset(&cp, 0, sizeof(cp));
+       memcpy(&cp.lap, lap, sizeof(cp.lap));
+       cp.length  = length;
+
+       return hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
+}
+
+int hci_cancel_inquiry(struct hci_dev *hdev)
+{
+       BT_DBG("%s", hdev->name);
+
+       if (!test_bit(HCI_INQUIRY, &hdev->flags))
+               return -EPERM;
+
+       return hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
+}
index d7d96b6..a89cf1f 100644 (file)
@@ -58,9 +58,11 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
        if (status)
                return;
 
-       if (test_and_clear_bit(HCI_INQUIRY, &hdev->flags) &&
-                       test_bit(HCI_MGMT, &hdev->flags))
-               mgmt_discovering(hdev->id, 0);
+       clear_bit(HCI_INQUIRY, &hdev->flags);
+
+       hci_dev_lock(hdev);
+       mgmt_discovering(hdev, 0);
+       hci_dev_unlock(hdev);
 
        hci_req_complete(hdev, HCI_OP_INQUIRY_CANCEL, status);
 
@@ -76,10 +78,6 @@ static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb)
        if (status)
                return;
 
-       if (test_and_clear_bit(HCI_INQUIRY, &hdev->flags) &&
-                               test_bit(HCI_MGMT, &hdev->flags))
-               mgmt_discovering(hdev->id, 0);
-
        hci_conn_check_pending(hdev);
 }
 
@@ -205,13 +203,15 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
        if (!sent)
                return;
 
+       hci_dev_lock(hdev);
+
        if (test_bit(HCI_MGMT, &hdev->flags))
-               mgmt_set_local_name_complete(hdev->id, sent, status);
+               mgmt_set_local_name_complete(hdev, sent, status);
 
-       if (status)
-               return;
+       if (status == 0)
+               memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH);
 
-       memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH);
+       hci_dev_unlock(hdev);
 }
 
 static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)
@@ -274,7 +274,8 @@ static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb)
 
 static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       __u8 status = *((__u8 *) skb->data);
+       __u8 param, status = *((__u8 *) skb->data);
+       int old_pscan, old_iscan;
        void *sent;
 
        BT_DBG("%s status 0x%x", hdev->name, status);
@@ -283,28 +284,40 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
        if (!sent)
                return;
 
-       if (!status) {
-               __u8 param = *((__u8 *) sent);
-               int old_pscan, old_iscan;
-
-               old_pscan = test_and_clear_bit(HCI_PSCAN, &hdev->flags);
-               old_iscan = test_and_clear_bit(HCI_ISCAN, &hdev->flags);
+       param = *((__u8 *) sent);
 
-               if (param & SCAN_INQUIRY) {
-                       set_bit(HCI_ISCAN, &hdev->flags);
-                       if (!old_iscan)
-                               mgmt_discoverable(hdev->id, 1);
-               } else if (old_iscan)
-                       mgmt_discoverable(hdev->id, 0);
+       hci_dev_lock(hdev);
 
-               if (param & SCAN_PAGE) {
-                       set_bit(HCI_PSCAN, &hdev->flags);
-                       if (!old_pscan)
-                               mgmt_connectable(hdev->id, 1);
-               } else if (old_pscan)
-                       mgmt_connectable(hdev->id, 0);
+       if (status != 0) {
+               mgmt_write_scan_failed(hdev, param, status);
+               hdev->discov_timeout = 0;
+               goto done;
        }
 
+       old_pscan = test_and_clear_bit(HCI_PSCAN, &hdev->flags);
+       old_iscan = test_and_clear_bit(HCI_ISCAN, &hdev->flags);
+
+       if (param & SCAN_INQUIRY) {
+               set_bit(HCI_ISCAN, &hdev->flags);
+               if (!old_iscan)
+                       mgmt_discoverable(hdev, 1);
+               if (hdev->discov_timeout > 0) {
+                       int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
+                       queue_delayed_work(hdev->workqueue, &hdev->discov_off,
+                                                                       to);
+               }
+       } else if (old_iscan)
+               mgmt_discoverable(hdev, 0);
+
+       if (param & SCAN_PAGE) {
+               set_bit(HCI_PSCAN, &hdev->flags);
+               if (!old_pscan)
+                       mgmt_connectable(hdev, 1);
+       } else if (old_pscan)
+               mgmt_connectable(hdev, 0);
+
+done:
+       hci_dev_unlock(hdev);
        hci_req_complete(hdev, HCI_OP_WRITE_SCAN_ENABLE, status);
 }
 
@@ -748,6 +761,30 @@ static void hci_cc_write_ca_timeout(struct hci_dev *hdev, struct sk_buff *skb)
        hci_req_complete(hdev, HCI_OP_WRITE_CA_TIMEOUT, status);
 }
 
+static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
+               struct sk_buff *skb)
+{
+       struct hci_rp_read_local_amp_info *rp = (void *) skb->data;
+
+       BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+       if (rp->status)
+               return;
+
+       hdev->amp_status = rp->amp_status;
+       hdev->amp_total_bw = __le32_to_cpu(rp->total_bw);
+       hdev->amp_max_bw = __le32_to_cpu(rp->max_bw);
+       hdev->amp_min_latency = __le32_to_cpu(rp->min_latency);
+       hdev->amp_max_pdu = __le32_to_cpu(rp->max_pdu);
+       hdev->amp_type = rp->amp_type;
+       hdev->amp_pal_cap = __le16_to_cpu(rp->pal_cap);
+       hdev->amp_assoc_size = __le16_to_cpu(rp->max_assoc_size);
+       hdev->amp_be_flush_to = __le32_to_cpu(rp->be_flush_to);
+       hdev->amp_max_flush_to = __le32_to_cpu(rp->max_flush_to);
+
+       hci_req_complete(hdev, HCI_OP_READ_LOCAL_AMP_INFO, rp->status);
+}
+
 static void hci_cc_delete_stored_link_key(struct hci_dev *hdev,
                                                        struct sk_buff *skb)
 {
@@ -804,19 +841,24 @@ static void hci_cc_pin_code_reply(struct hci_dev *hdev, struct sk_buff *skb)
 
        BT_DBG("%s status 0x%x", hdev->name, rp->status);
 
+       hci_dev_lock(hdev);
+
        if (test_bit(HCI_MGMT, &hdev->flags))
-               mgmt_pin_code_reply_complete(hdev->id, &rp->bdaddr, rp->status);
+               mgmt_pin_code_reply_complete(hdev, &rp->bdaddr, rp->status);
 
        if (rp->status != 0)
-               return;
+               goto unlock;
 
        cp = hci_sent_cmd_data(hdev, HCI_OP_PIN_CODE_REPLY);
        if (!cp)
-               return;
+               goto unlock;
 
        conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
        if (conn)
                conn->pin_length = cp->pin_len;
+
+unlock:
+       hci_dev_unlock(hdev);
 }
 
 static void hci_cc_pin_code_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
@@ -825,10 +867,15 @@ static void hci_cc_pin_code_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
 
        BT_DBG("%s status 0x%x", hdev->name, rp->status);
 
+       hci_dev_lock(hdev);
+
        if (test_bit(HCI_MGMT, &hdev->flags))
-               mgmt_pin_code_neg_reply_complete(hdev->id, &rp->bdaddr,
+               mgmt_pin_code_neg_reply_complete(hdev, &rp->bdaddr,
                                                                rp->status);
+
+       hci_dev_unlock(hdev);
 }
+
 static void hci_cc_le_read_buffer_size(struct hci_dev *hdev,
                                       struct sk_buff *skb)
 {
@@ -855,9 +902,13 @@ static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb)
 
        BT_DBG("%s status 0x%x", hdev->name, rp->status);
 
+       hci_dev_lock(hdev);
+
        if (test_bit(HCI_MGMT, &hdev->flags))
-               mgmt_user_confirm_reply_complete(hdev->id, &rp->bdaddr,
+               mgmt_user_confirm_reply_complete(hdev, &rp->bdaddr,
                                                                rp->status);
+
+       hci_dev_unlock(hdev);
 }
 
 static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev,
@@ -867,9 +918,13 @@ static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev,
 
        BT_DBG("%s status 0x%x", hdev->name, rp->status);
 
+       hci_dev_lock(hdev);
+
        if (test_bit(HCI_MGMT, &hdev->flags))
-               mgmt_user_confirm_neg_reply_complete(hdev->id, &rp->bdaddr,
+               mgmt_user_confirm_neg_reply_complete(hdev, &rp->bdaddr,
                                                                rp->status);
+
+       hci_dev_unlock(hdev);
 }
 
 static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
@@ -879,8 +934,10 @@ static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
 
        BT_DBG("%s status 0x%x", hdev->name, rp->status);
 
-       mgmt_read_local_oob_data_reply_complete(hdev->id, rp->hash,
+       hci_dev_lock(hdev);
+       mgmt_read_local_oob_data_reply_complete(hdev, rp->hash,
                                                rp->randomizer, rp->status);
+       hci_dev_unlock(hdev);
 }
 
 static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
@@ -955,12 +1012,18 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
        if (status) {
                hci_req_complete(hdev, HCI_OP_INQUIRY, status);
                hci_conn_check_pending(hdev);
+               hci_dev_lock(hdev);
+               if (test_bit(HCI_MGMT, &hdev->flags))
+                       mgmt_inquiry_failed(hdev, status);
+               hci_dev_unlock(hdev);
                return;
        }
 
-       if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags) &&
-                               test_bit(HCI_MGMT, &hdev->flags))
-               mgmt_discovering(hdev->id, 1);
+       set_bit(HCI_INQUIRY, &hdev->flags);
+
+       hci_dev_lock(hdev);
+       mgmt_discovering(hdev, 1);
+       hci_dev_unlock(hdev);
 }
 
 static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
@@ -1339,13 +1402,16 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff
 
        BT_DBG("%s status %d", hdev->name, status);
 
-       if (test_and_clear_bit(HCI_INQUIRY, &hdev->flags) &&
-                               test_bit(HCI_MGMT, &hdev->flags))
-               mgmt_discovering(hdev->id, 0);
-
        hci_req_complete(hdev, HCI_OP_INQUIRY, status);
 
        hci_conn_check_pending(hdev);
+
+       if (!test_and_clear_bit(HCI_INQUIRY, &hdev->flags))
+               return;
+
+       hci_dev_lock(hdev);
+       mgmt_discovering(hdev, 0);
+       hci_dev_unlock(hdev);
 }
 
 static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
@@ -1361,12 +1427,6 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
 
        hci_dev_lock(hdev);
 
-       if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags)) {
-
-               if (test_bit(HCI_MGMT, &hdev->flags))
-                       mgmt_discovering(hdev->id, 1);
-       }
-
        for (; num_rsp; num_rsp--, info++) {
                bacpy(&data.bdaddr, &info->bdaddr);
                data.pscan_rep_mode     = info->pscan_rep_mode;
@@ -1377,8 +1437,8 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
                data.rssi               = 0x00;
                data.ssp_mode           = 0x00;
                hci_inquiry_cache_update(hdev, &data);
-               mgmt_device_found(hdev->id, &info->bdaddr, info->dev_class, 0,
-                                                                       NULL);
+               mgmt_device_found(hdev, &info->bdaddr, ACL_LINK,
+                                               info->dev_class, 0, NULL);
        }
 
        hci_dev_unlock(hdev);
@@ -1412,7 +1472,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                        conn->state = BT_CONFIG;
                        hci_conn_hold(conn);
                        conn->disc_timeout = HCI_DISCONN_TIMEOUT;
-                       mgmt_connected(hdev->id, &ev->bdaddr, conn->type);
+                       mgmt_connected(hdev, &ev->bdaddr, conn->type);
                } else
                        conn->state = BT_CONNECTED;
 
@@ -1444,7 +1504,8 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
        } else {
                conn->state = BT_CLOSED;
                if (conn->type == ACL_LINK)
-                       mgmt_connect_failed(hdev->id, &ev->bdaddr, ev->status);
+                       mgmt_connect_failed(hdev, &ev->bdaddr, conn->type,
+                                                               ev->status);
        }
 
        if (conn->type == ACL_LINK)
@@ -1531,7 +1592,7 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
                struct hci_cp_reject_conn_req cp;
 
                bacpy(&cp.bdaddr, &ev->bdaddr);
-               cp.reason = 0x0f;
+               cp.reason = HCI_ERROR_REJ_BAD_ADDR;
                hci_send_cmd(hdev, HCI_OP_REJECT_CONN_REQ, sizeof(cp), &cp);
        }
 }
@@ -1544,7 +1605,9 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
        BT_DBG("%s status %d", hdev->name, ev->status);
 
        if (ev->status) {
-               mgmt_disconnect_failed(hdev->id);
+               hci_dev_lock(hdev);
+               mgmt_disconnect_failed(hdev);
+               hci_dev_unlock(hdev);
                return;
        }
 
@@ -1557,7 +1620,7 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
        conn->state = BT_CLOSED;
 
        if (conn->type == ACL_LINK || conn->type == LE_LINK)
-               mgmt_disconnected(hdev->id, &conn->dst);
+               mgmt_disconnected(hdev, &conn->dst, conn->type);
 
        hci_proto_disconn_cfm(conn, ev->reason);
        hci_conn_del(conn);
@@ -1588,7 +1651,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                        conn->sec_level = conn->pending_sec_level;
                }
        } else {
-               mgmt_auth_failed(hdev->id, &conn->dst, ev->status);
+               mgmt_auth_failed(hdev, &conn->dst, ev->status);
        }
 
        clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
@@ -1643,7 +1706,7 @@ static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb
        hci_dev_lock(hdev);
 
        if (ev->status == 0 && test_bit(HCI_MGMT, &hdev->flags))
-               mgmt_remote_name(hdev->id, &ev->bdaddr, ev->name);
+               mgmt_remote_name(hdev, &ev->bdaddr, ev->name);
 
        conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
        if (!conn)
@@ -1898,6 +1961,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
                hci_cc_write_ca_timeout(hdev, skb);
                break;
 
+       case HCI_OP_READ_LOCAL_AMP_INFO:
+               hci_cc_read_local_amp_info(hdev, skb);
+               break;
+
        case HCI_OP_DELETE_STORED_LINK_KEY:
                hci_cc_delete_stored_link_key(hdev, skb);
                break;
@@ -2029,7 +2096,7 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
        case HCI_OP_DISCONNECT:
                if (ev->status != 0)
-                       mgmt_disconnect_failed(hdev->id);
+                       mgmt_disconnect_failed(hdev);
                break;
 
        case HCI_OP_LE_CREATE_CONN:
@@ -2194,7 +2261,7 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff
                else
                        secure = 0;
 
-               mgmt_pin_code_request(hdev->id, &ev->bdaddr, secure);
+               mgmt_pin_code_request(hdev, &ev->bdaddr, secure);
        }
 
 unlock:
@@ -2363,12 +2430,6 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
 
        hci_dev_lock(hdev);
 
-       if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags)) {
-
-               if (test_bit(HCI_MGMT, &hdev->flags))
-                       mgmt_discovering(hdev->id, 1);
-       }
-
        if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) {
                struct inquiry_info_with_rssi_and_pscan_mode *info;
                info = (void *) (skb->data + 1);
@@ -2383,7 +2444,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
                        data.rssi               = info->rssi;
                        data.ssp_mode           = 0x00;
                        hci_inquiry_cache_update(hdev, &data);
-                       mgmt_device_found(hdev->id, &info->bdaddr,
+                       mgmt_device_found(hdev, &info->bdaddr, ACL_LINK,
                                                info->dev_class, info->rssi,
                                                NULL);
                }
@@ -2400,7 +2461,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
                        data.rssi               = info->rssi;
                        data.ssp_mode           = 0x00;
                        hci_inquiry_cache_update(hdev, &data);
-                       mgmt_device_found(hdev->id, &info->bdaddr,
+                       mgmt_device_found(hdev, &info->bdaddr, ACL_LINK,
                                                info->dev_class, info->rssi,
                                                NULL);
                }
@@ -2531,12 +2592,6 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
        if (!num_rsp)
                return;
 
-       if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags)) {
-
-               if (test_bit(HCI_MGMT, &hdev->flags))
-                       mgmt_discovering(hdev->id, 1);
-       }
-
        hci_dev_lock(hdev);
 
        for (; num_rsp; num_rsp--, info++) {
@@ -2549,8 +2604,8 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
                data.rssi               = info->rssi;
                data.ssp_mode           = 0x01;
                hci_inquiry_cache_update(hdev, &data);
-               mgmt_device_found(hdev->id, &info->bdaddr, info->dev_class,
-                                               info->rssi, info->data);
+               mgmt_device_found(hdev, &info->bdaddr, ACL_LINK,
+                               info->dev_class, info->rssi, info->data);
        }
 
        hci_dev_unlock(hdev);
@@ -2614,7 +2669,7 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff
                struct hci_cp_io_capability_neg_reply cp;
 
                bacpy(&cp.bdaddr, &ev->bdaddr);
-               cp.reason = 0x18; /* Pairing not allowed */
+               cp.reason = HCI_ERROR_PAIRING_NOT_ALLOWED;
 
                hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_NEG_REPLY,
                                                        sizeof(cp), &cp);
@@ -2706,7 +2761,7 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev,
        }
 
 confirm:
-       mgmt_user_confirm_request(hdev->id, &ev->bdaddr, ev->passkey,
+       mgmt_user_confirm_request(hdev, &ev->bdaddr, ev->passkey,
                                                                confirm_hint);
 
 unlock:
@@ -2732,7 +2787,7 @@ static inline void hci_simple_pair_complete_evt(struct hci_dev *hdev, struct sk_
         * event gets always produced as initiator and is also mapped to
         * the mgmt_auth_failed event */
        if (!test_bit(HCI_CONN_AUTH_PEND, &conn->pend) && ev->status != 0)
-               mgmt_auth_failed(hdev->id, &conn->dst, ev->status);
+               mgmt_auth_failed(hdev, &conn->dst, ev->status);
 
        hci_conn_put(conn);
 
@@ -2813,14 +2868,14 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff
        }
 
        if (ev->status) {
-               mgmt_connect_failed(hdev->id, &ev->bdaddr, ev->status);
+               mgmt_connect_failed(hdev, &ev->bdaddr, conn->type, ev->status);
                hci_proto_connect_cfm(conn, ev->status);
                conn->state = BT_CLOSED;
                hci_conn_del(conn);
                goto unlock;
        }
 
-       mgmt_connected(hdev->id, &ev->bdaddr, conn->type);
+       mgmt_connected(hdev, &ev->bdaddr, conn->type);
 
        conn->sec_level = BT_SECURITY_LOW;
        conn->handle = __le16_to_cpu(ev->handle);
@@ -3104,5 +3159,5 @@ void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data)
        kfree_skb(skb);
 }
 
-module_param(enable_le, bool, 0444);
+module_param(enable_le, bool, 0644);
 MODULE_PARM_DESC(enable_le, "Enable LE support");
index 661b461..c62d254 100644 (file)
@@ -436,17 +436,12 @@ static const struct file_operations inquiry_cache_fops = {
 static int blacklist_show(struct seq_file *f, void *p)
 {
        struct hci_dev *hdev = f->private;
-       struct list_head *l;
+       struct bdaddr_list *b;
 
        hci_dev_lock_bh(hdev);
 
-       list_for_each(l, &hdev->blacklist) {
-               struct bdaddr_list *b;
-
-               b = list_entry(l, struct bdaddr_list, list);
-
+       list_for_each_entry(b, &hdev->blacklist, list)
                seq_printf(f, "%s\n", batostr(&b->bdaddr));
-       }
 
        hci_dev_unlock_bh(hdev);
 
@@ -485,17 +480,12 @@ static void print_bt_uuid(struct seq_file *f, u8 *uuid)
 static int uuids_show(struct seq_file *f, void *p)
 {
        struct hci_dev *hdev = f->private;
-       struct list_head *l;
+       struct bt_uuid *uuid;
 
        hci_dev_lock_bh(hdev);
 
-       list_for_each(l, &hdev->uuids) {
-               struct bt_uuid *uuid;
-
-               uuid = list_entry(l, struct bt_uuid, list);
-
+       list_for_each_entry(uuid, &hdev->uuids, list)
                print_bt_uuid(f, uuid->uuid);
-       }
 
        hci_dev_unlock_bh(hdev);
 
@@ -543,22 +533,28 @@ static int auto_accept_delay_get(void *data, u64 *val)
 DEFINE_SIMPLE_ATTRIBUTE(auto_accept_delay_fops, auto_accept_delay_get,
                                        auto_accept_delay_set, "%llu\n");
 
-int hci_register_sysfs(struct hci_dev *hdev)
+void hci_init_sysfs(struct hci_dev *hdev)
+{
+       struct device *dev = &hdev->dev;
+
+       dev->type = &bt_host;
+       dev->class = bt_class;
+
+       dev_set_drvdata(dev, hdev);
+       device_initialize(dev);
+}
+
+int hci_add_sysfs(struct hci_dev *hdev)
 {
        struct device *dev = &hdev->dev;
        int err;
 
        BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
 
-       dev->type = &bt_host;
-       dev->class = bt_class;
        dev->parent = hdev->parent;
-
        dev_set_name(dev, "%s", hdev->name);
 
-       dev_set_drvdata(dev, hdev);
-
-       err = device_register(dev);
+       err = device_add(dev);
        if (err < 0)
                return err;
 
@@ -582,7 +578,7 @@ int hci_register_sysfs(struct hci_dev *hdev)
        return 0;
 }
 
-void hci_unregister_sysfs(struct hci_dev *hdev)
+void hci_del_sysfs(struct hci_dev *hdev)
 {
        BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
 
index 075a3e9..3c2d888 100644 (file)
@@ -81,24 +81,20 @@ static unsigned char hidp_mkeyspat[] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
 static struct hidp_session *__hidp_get_session(bdaddr_t *bdaddr)
 {
        struct hidp_session *session;
-       struct list_head *p;
 
        BT_DBG("");
 
-       list_for_each(p, &hidp_session_list) {
-               session = list_entry(p, struct hidp_session, list);
+       list_for_each_entry(session, &hidp_session_list, list) {
                if (!bacmp(bdaddr, &session->bdaddr))
                        return session;
        }
+
        return NULL;
 }
 
 static void __hidp_link_session(struct hidp_session *session)
 {
-       __module_get(THIS_MODULE);
        list_add(&session->list, &hidp_session_list);
-
-       hci_conn_hold_device(session->conn);
 }
 
 static void __hidp_unlink_session(struct hidp_session *session)
@@ -106,7 +102,6 @@ static void __hidp_unlink_session(struct hidp_session *session)
        hci_conn_put_device(session->conn);
 
        list_del(&session->list);
-       module_put(THIS_MODULE);
 }
 
 static void __hidp_copy_session(struct hidp_session *session, struct hidp_conninfo *ci)
@@ -255,6 +250,9 @@ static int __hidp_send_ctrl_message(struct hidp_session *session,
 
        BT_DBG("session %p data %p size %d", session, data, size);
 
+       if (atomic_read(&session->terminate))
+               return -EIO;
+
        skb = alloc_skb(size + 1, GFP_ATOMIC);
        if (!skb) {
                BT_ERR("Can't allocate memory for new frame");
@@ -329,6 +327,7 @@ static int hidp_get_raw_report(struct hid_device *hid,
        struct sk_buff *skb;
        size_t len;
        int numbered_reports = hid->report_enum[report_type].numbered;
+       int ret;
 
        switch (report_type) {
        case HID_FEATURE_REPORT:
@@ -352,8 +351,9 @@ static int hidp_get_raw_report(struct hid_device *hid,
        session->waiting_report_number = numbered_reports ? report_number : -1;
        set_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
        data[0] = report_number;
-       if (hidp_send_ctrl_message(hid->driver_data, report_type, data, 1))
-               goto err_eio;
+       ret = hidp_send_ctrl_message(hid->driver_data, report_type, data, 1);
+       if (ret)
+               goto err;
 
        /* Wait for the return of the report. The returned report
           gets put in session->report_return.  */
@@ -365,11 +365,13 @@ static int hidp_get_raw_report(struct hid_device *hid,
                        5*HZ);
                if (res == 0) {
                        /* timeout */
-                       goto err_eio;
+                       ret = -EIO;
+                       goto err;
                }
                if (res < 0) {
                        /* signal */
-                       goto err_restartsys;
+                       ret = -ERESTARTSYS;
+                       goto err;
                }
        }
 
@@ -390,14 +392,10 @@ static int hidp_get_raw_report(struct hid_device *hid,
 
        return len;
 
-err_restartsys:
-       clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
-       mutex_unlock(&session->report_mutex);
-       return -ERESTARTSYS;
-err_eio:
+err:
        clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
        mutex_unlock(&session->report_mutex);
-       return -EIO;
+       return ret;
 }
 
 static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count,
@@ -422,11 +420,10 @@ static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, s
 
        /* Set up our wait, and send the report request to the device. */
        set_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
-       if (hidp_send_ctrl_message(hid->driver_data, report_type,
-                       data, count)) {
-               ret = -ENOMEM;
+       ret = hidp_send_ctrl_message(hid->driver_data, report_type, data,
+                                                                       count);
+       if (ret)
                goto err;
-       }
 
        /* Wait for the ACK from the device. */
        while (test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags)) {
@@ -496,10 +493,9 @@ static void hidp_process_handshake(struct hidp_session *session,
        case HIDP_HSHK_ERR_INVALID_REPORT_ID:
        case HIDP_HSHK_ERR_UNSUPPORTED_REQUEST:
        case HIDP_HSHK_ERR_INVALID_PARAMETER:
-               if (test_bit(HIDP_WAITING_FOR_RETURN, &session->flags)) {
-                       clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
+               if (test_and_clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags))
                        wake_up_interruptible(&session->report_queue);
-               }
+
                /* FIXME: Call into SET_ GET_ handlers here */
                break;
 
@@ -520,10 +516,8 @@ static void hidp_process_handshake(struct hidp_session *session,
        }
 
        /* Wake up the waiting thread. */
-       if (test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags)) {
-               clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
+       if (test_and_clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags))
                wake_up_interruptible(&session->report_queue);
-       }
 }
 
 static void hidp_process_hid_control(struct hidp_session *session,
@@ -663,25 +657,32 @@ static int hidp_send_frame(struct socket *sock, unsigned char *data, int len)
        return kernel_sendmsg(sock, &msg, &iv, 1, len);
 }
 
-static void hidp_process_transmit(struct hidp_session *session)
+static void hidp_process_intr_transmit(struct hidp_session *session)
 {
        struct sk_buff *skb;
 
        BT_DBG("session %p", session);
 
-       while ((skb = skb_dequeue(&session->ctrl_transmit))) {
-               if (hidp_send_frame(session->ctrl_sock, skb->data, skb->len) < 0) {
-                       skb_queue_head(&session->ctrl_transmit, skb);
+       while ((skb = skb_dequeue(&session->intr_transmit))) {
+               if (hidp_send_frame(session->intr_sock, skb->data, skb->len) < 0) {
+                       skb_queue_head(&session->intr_transmit, skb);
                        break;
                }
 
                hidp_set_timer(session);
                kfree_skb(skb);
        }
+}
 
-       while ((skb = skb_dequeue(&session->intr_transmit))) {
-               if (hidp_send_frame(session->intr_sock, skb->data, skb->len) < 0) {
-                       skb_queue_head(&session->intr_transmit, skb);
+static void hidp_process_ctrl_transmit(struct hidp_session *session)
+{
+       struct sk_buff *skb;
+
+       BT_DBG("session %p", session);
+
+       while ((skb = skb_dequeue(&session->ctrl_transmit))) {
+               if (hidp_send_frame(session->ctrl_sock, skb->data, skb->len) < 0) {
+                       skb_queue_head(&session->ctrl_transmit, skb);
                        break;
                }
 
@@ -700,6 +701,7 @@ static int hidp_session(void *arg)
 
        BT_DBG("session %p", session);
 
+       __module_get(THIS_MODULE);
        set_user_nice(current, -15);
 
        init_waitqueue_entry(&ctrl_wait, current);
@@ -714,23 +716,25 @@ static int hidp_session(void *arg)
                                intr_sk->sk_state != BT_CONNECTED)
                        break;
 
-               while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) {
+               while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) {
                        skb_orphan(skb);
                        if (!skb_linearize(skb))
-                               hidp_recv_ctrl_frame(session, skb);
+                               hidp_recv_intr_frame(session, skb);
                        else
                                kfree_skb(skb);
                }
 
-               while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) {
+               hidp_process_intr_transmit(session);
+
+               while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) {
                        skb_orphan(skb);
                        if (!skb_linearize(skb))
-                               hidp_recv_intr_frame(session, skb);
+                               hidp_recv_ctrl_frame(session, skb);
                        else
                                kfree_skb(skb);
                }
 
-               hidp_process_transmit(session);
+               hidp_process_ctrl_transmit(session);
 
                schedule();
                set_current_state(TASK_INTERRUPTIBLE);
@@ -739,6 +743,10 @@ static int hidp_session(void *arg)
        remove_wait_queue(sk_sleep(intr_sk), &intr_wait);
        remove_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait);
 
+       clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
+       clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
+       wake_up_interruptible(&session->report_queue);
+
        down_write(&hidp_session_sem);
 
        hidp_del_timer(session);
@@ -772,34 +780,37 @@ static int hidp_session(void *arg)
 
        kfree(session->rd_data);
        kfree(session);
+       module_put_and_exit(0);
        return 0;
 }
 
-static struct device *hidp_get_device(struct hidp_session *session)
+static struct hci_conn *hidp_get_connection(struct hidp_session *session)
 {
        bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src;
        bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst;
-       struct device *device = NULL;
+       struct hci_conn *conn;
        struct hci_dev *hdev;
 
        hdev = hci_get_route(dst, src);
        if (!hdev)
                return NULL;
 
-       session->conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
-       if (session->conn)
-               device = &session->conn->dev;
+       hci_dev_lock_bh(hdev);
+       conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
+       if (conn)
+               hci_conn_hold_device(conn);
+       hci_dev_unlock_bh(hdev);
 
        hci_dev_put(hdev);
 
-       return device;
+       return conn;
 }
 
 static int hidp_setup_input(struct hidp_session *session,
                                struct hidp_connadd_req *req)
 {
        struct input_dev *input;
-       int err, i;
+       int i;
 
        input = input_allocate_device();
        if (!input)
@@ -842,17 +853,10 @@ static int hidp_setup_input(struct hidp_session *session,
                input->relbit[0] |= BIT_MASK(REL_WHEEL);
        }
 
-       input->dev.parent = hidp_get_device(session);
+       input->dev.parent = &session->conn->dev;
 
        input->event = hidp_input_event;
 
-       err = input_register_device(input);
-       if (err < 0) {
-               input_free_device(input);
-               session->input = NULL;
-               return err;
-       }
-
        return 0;
 }
 
@@ -949,7 +953,7 @@ static int hidp_setup_hid(struct hidp_session *session,
        strncpy(hid->phys, batostr(&bt_sk(session->ctrl_sock->sk)->src), 64);
        strncpy(hid->uniq, batostr(&bt_sk(session->ctrl_sock->sk)->dst), 64);
 
-       hid->dev.parent = hidp_get_device(session);
+       hid->dev.parent = &session->conn->dev;
        hid->ll_driver = &hidp_hid_driver;
 
        hid->hid_get_raw_report = hidp_get_raw_report;
@@ -976,18 +980,20 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
                        bacmp(&bt_sk(ctrl_sock->sk)->dst, &bt_sk(intr_sock->sk)->dst))
                return -ENOTUNIQ;
 
-       session = kzalloc(sizeof(struct hidp_session), GFP_KERNEL);
-       if (!session)
-               return -ENOMEM;
-
        BT_DBG("rd_data %p rd_size %d", req->rd_data, req->rd_size);
 
        down_write(&hidp_session_sem);
 
        s = __hidp_get_session(&bt_sk(ctrl_sock->sk)->dst);
        if (s && s->state == BT_CONNECTED) {
-               err = -EEXIST;
-               goto failed;
+               up_write(&hidp_session_sem);
+               return -EEXIST;
+       }
+
+       session = kzalloc(sizeof(struct hidp_session), GFP_KERNEL);
+       if (!session) {
+               up_write(&hidp_session_sem);
+               return -ENOMEM;
        }
 
        bacpy(&session->bdaddr, &bt_sk(ctrl_sock->sk)->dst);
@@ -1003,6 +1009,12 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
        session->intr_sock = intr_sock;
        session->state     = BT_CONNECTED;
 
+       session->conn = hidp_get_connection(session);
+       if (!session->conn) {
+               err = -ENOTCONN;
+               goto failed;
+       }
+
        setup_timer(&session->timer, hidp_idle_timeout, (unsigned long)session);
 
        skb_queue_head_init(&session->ctrl_transmit);
@@ -1015,9 +1027,11 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
        session->flags   = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID);
        session->idle_to = req->idle_to;
 
+       __hidp_link_session(session);
+
        if (req->rd_size > 0) {
                err = hidp_setup_hid(session, req);
-               if (err && err != -ENODEV)
+               if (err)
                        goto purge;
        }
 
@@ -1027,8 +1041,6 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
                        goto purge;
        }
 
-       __hidp_link_session(session);
-
        hidp_set_timer(session);
 
        if (session->hid) {
@@ -1054,7 +1066,11 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
                        !session->waiting_for_startup);
        }
 
-       err = hid_add_device(session->hid);
+       if (session->hid)
+               err = hid_add_device(session->hid);
+       else
+               err = input_register_device(session->input);
+
        if (err < 0) {
                atomic_inc(&session->terminate);
                wake_up_process(session->task);
@@ -1077,8 +1093,6 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
 unlink:
        hidp_del_timer(session);
 
-       __hidp_unlink_session(session);
-
        if (session->input) {
                input_unregister_device(session->input);
                session->input = NULL;
@@ -1093,6 +1107,8 @@ unlink:
        session->rd_data = NULL;
 
 purge:
+       __hidp_unlink_session(session);
+
        skb_queue_purge(&session->ctrl_transmit);
        skb_queue_purge(&session->intr_transmit);
 
@@ -1134,19 +1150,16 @@ int hidp_del_connection(struct hidp_conndel_req *req)
 
 int hidp_get_connlist(struct hidp_connlist_req *req)
 {
-       struct list_head *p;
+       struct hidp_session *session;
        int err = 0, n = 0;
 
        BT_DBG("");
 
        down_read(&hidp_session_sem);
 
-       list_for_each(p, &hidp_session_list) {
-               struct hidp_session *session;
+       list_for_each_entry(session, &hidp_session_list, list) {
                struct hidp_conninfo ci;
 
-               session = list_entry(p, struct hidp_session, list);
-
                __hidp_copy_session(session, &ci);
 
                if (copy_to_user(req->ci, &ci, sizeof(ci))) {
index 8cd1291..e8a6837 100644 (file)
 #include <net/bluetooth/smp.h>
 
 int disable_ertm;
+int enable_hs;
 
 static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
-static u8 l2cap_fixed_chan[8] = { 0x02, };
+static u8 l2cap_fixed_chan[8] = { L2CAP_FC_L2CAP, };
 
 static LIST_HEAD(chan_list);
 static DEFINE_RWLOCK(chan_list_lock);
@@ -219,7 +220,7 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
 
 static void l2cap_set_timer(struct l2cap_chan *chan, struct timer_list *timer, long timeout)
 {
-       BT_DBG("chan %p state %d timeout %ld", chan->sk, chan->state, timeout);
+       BT_DBG("chan %p state %d timeout %ld", chan, chan->state, timeout);
 
        if (!mod_timer(timer, jiffies + msecs_to_jiffies(timeout)))
                chan_hold(chan);
@@ -251,7 +252,7 @@ static void l2cap_chan_timeout(unsigned long arg)
 
        if (sock_owned_by_user(sk)) {
                /* sk is owned by user. Try again later */
-               __set_chan_timer(chan, HZ / 5);
+               __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
                bh_unlock_sock(sk);
                chan_put(chan);
                return;
@@ -293,6 +294,8 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk)
 
        atomic_set(&chan->refcnt, 1);
 
+       BT_DBG("sk %p chan %p", sk, chan);
+
        return chan;
 }
 
@@ -310,7 +313,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
        BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
                        chan->psm, chan->dcid);
 
-       conn->disc_reason = 0x13;
+       conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
 
        chan->conn = conn;
 
@@ -337,6 +340,13 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
                chan->omtu = L2CAP_DEFAULT_MTU;
        }
 
+       chan->local_id          = L2CAP_BESTEFFORT_ID;
+       chan->local_stype       = L2CAP_SERV_BESTEFFORT;
+       chan->local_msdu        = L2CAP_DEFAULT_MAX_SDU_SIZE;
+       chan->local_sdu_itime   = L2CAP_DEFAULT_SDU_ITIME;
+       chan->local_acc_lat     = L2CAP_DEFAULT_ACC_LAT;
+       chan->local_flush_to    = L2CAP_DEFAULT_FLUSH_TO;
+
        chan_hold(chan);
 
        list_add(&chan->list, &conn->chan_l);
@@ -556,34 +566,58 @@ static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
                flags = ACL_START;
 
        bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON;
+       skb->priority = HCI_PRIO_MAX;
+
+       hci_send_acl(conn->hchan, skb, flags);
+}
+
+static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
+{
+       struct hci_conn *hcon = chan->conn->hcon;
+       u16 flags;
+
+       BT_DBG("chan %p, skb %p len %d priority %u", chan, skb, skb->len,
+                                                       skb->priority);
+
+       if (!test_bit(FLAG_FLUSHABLE, &chan->flags) &&
+                                       lmp_no_flush_capable(hcon->hdev))
+               flags = ACL_START_NO_FLUSH;
+       else
+               flags = ACL_START;
 
-       hci_send_acl(conn->hcon, skb, flags);
+       bt_cb(skb)->force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags);
+       hci_send_acl(chan->conn->hchan, skb, flags);
 }
 
-static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control)
+static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control)
 {
        struct sk_buff *skb;
        struct l2cap_hdr *lh;
        struct l2cap_conn *conn = chan->conn;
-       int count, hlen = L2CAP_HDR_SIZE + 2;
-       u8 flags;
+       int count, hlen;
 
        if (chan->state != BT_CONNECTED)
                return;
 
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               hlen = L2CAP_EXT_HDR_SIZE;
+       else
+               hlen = L2CAP_ENH_HDR_SIZE;
+
        if (chan->fcs == L2CAP_FCS_CRC16)
-               hlen += 2;
+               hlen += L2CAP_FCS_SIZE;
 
-       BT_DBG("chan %p, control 0x%2.2x", chan, control);
+       BT_DBG("chan %p, control 0x%8.8x", chan, control);
 
        count = min_t(unsigned int, conn->mtu, hlen);
-       control |= L2CAP_CTRL_FRAME_TYPE;
+
+       control |= __set_sframe(chan);
 
        if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
-               control |= L2CAP_CTRL_FINAL;
+               control |= __set_ctrl_final(chan);
 
        if (test_and_clear_bit(CONN_SEND_PBIT, &chan->conn_state))
-               control |= L2CAP_CTRL_POLL;
+               control |= __set_ctrl_poll(chan);
 
        skb = bt_skb_alloc(count, GFP_ATOMIC);
        if (!skb)
@@ -592,32 +626,27 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control)
        lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
        lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE);
        lh->cid = cpu_to_le16(chan->dcid);
-       put_unaligned_le16(control, skb_put(skb, 2));
+
+       __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
 
        if (chan->fcs == L2CAP_FCS_CRC16) {
-               u16 fcs = crc16(0, (u8 *)lh, count - 2);
-               put_unaligned_le16(fcs, skb_put(skb, 2));
+               u16 fcs = crc16(0, (u8 *)lh, count - L2CAP_FCS_SIZE);
+               put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
        }
 
-       if (lmp_no_flush_capable(conn->hcon->hdev))
-               flags = ACL_START_NO_FLUSH;
-       else
-               flags = ACL_START;
-
-       bt_cb(skb)->force_active = chan->force_active;
-
-       hci_send_acl(chan->conn->hcon, skb, flags);
+       skb->priority = HCI_PRIO_MAX;
+       l2cap_do_send(chan, skb);
 }
 
-static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u16 control)
+static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u32 control)
 {
        if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
-               control |= L2CAP_SUPER_RCV_NOT_READY;
+               control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
                set_bit(CONN_RNR_SENT, &chan->conn_state);
        } else
-               control |= L2CAP_SUPER_RCV_READY;
+               control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
 
-       control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+       control |= __set_reqseq(chan, chan->buffer_seq);
 
        l2cap_send_sframe(chan, control);
 }
@@ -947,7 +976,7 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
        list_for_each_entry(chan, &conn->chan_l, list) {
                struct sock *sk = chan->sk;
 
-               if (chan->force_reliable)
+               if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
                        sk->sk_err = err;
        }
 
@@ -986,6 +1015,8 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
                chan->ops->close(chan->data);
        }
 
+       hci_chan_del(conn->hchan);
+
        if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
                del_timer_sync(&conn->info_timer);
 
@@ -1008,18 +1039,26 @@ static void security_timeout(unsigned long arg)
 static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
 {
        struct l2cap_conn *conn = hcon->l2cap_data;
+       struct hci_chan *hchan;
 
        if (conn || status)
                return conn;
 
+       hchan = hci_chan_create(hcon);
+       if (!hchan)
+               return NULL;
+
        conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC);
-       if (!conn)
+       if (!conn) {
+               hci_chan_del(hchan);
                return NULL;
+       }
 
        hcon->l2cap_data = conn;
        conn->hcon = hcon;
+       conn->hchan = hchan;
 
-       BT_DBG("hcon %p conn %p", hcon, conn);
+       BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
 
        if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
                conn->mtu = hcon->hdev->le_mtu;
@@ -1043,7 +1082,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
                setup_timer(&conn->info_timer, l2cap_info_timeout,
                                                (unsigned long) conn);
 
-       conn->disc_reason = 0x13;
+       conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
 
        return conn;
 }
@@ -1245,47 +1284,35 @@ static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
                __clear_retrans_timer(chan);
 }
 
-static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
-{
-       struct hci_conn *hcon = chan->conn->hcon;
-       u16 flags;
-
-       BT_DBG("chan %p, skb %p len %d", chan, skb, skb->len);
-
-       if (!chan->flushable && lmp_no_flush_capable(hcon->hdev))
-               flags = ACL_START_NO_FLUSH;
-       else
-               flags = ACL_START;
-
-       bt_cb(skb)->force_active = chan->force_active;
-       hci_send_acl(hcon, skb, flags);
-}
-
 static void l2cap_streaming_send(struct l2cap_chan *chan)
 {
        struct sk_buff *skb;
-       u16 control, fcs;
+       u32 control;
+       u16 fcs;
 
        while ((skb = skb_dequeue(&chan->tx_q))) {
-               control = get_unaligned_le16(skb->data + L2CAP_HDR_SIZE);
-               control |= chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT;
-               put_unaligned_le16(control, skb->data + L2CAP_HDR_SIZE);
+               control = __get_control(chan, skb->data + L2CAP_HDR_SIZE);
+               control |= __set_txseq(chan, chan->next_tx_seq);
+               __put_control(chan, control, skb->data + L2CAP_HDR_SIZE);
 
                if (chan->fcs == L2CAP_FCS_CRC16) {
-                       fcs = crc16(0, (u8 *)skb->data, skb->len - 2);
-                       put_unaligned_le16(fcs, skb->data + skb->len - 2);
+                       fcs = crc16(0, (u8 *)skb->data,
+                                               skb->len - L2CAP_FCS_SIZE);
+                       put_unaligned_le16(fcs,
+                                       skb->data + skb->len - L2CAP_FCS_SIZE);
                }
 
                l2cap_do_send(chan, skb);
 
-               chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
+               chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
        }
 }
 
-static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq)
+static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
 {
        struct sk_buff *skb, *tx_skb;
-       u16 control, fcs;
+       u16 fcs;
+       u32 control;
 
        skb = skb_peek(&chan->tx_q);
        if (!skb)
@@ -1308,20 +1335,23 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq)
 
        tx_skb = skb_clone(skb, GFP_ATOMIC);
        bt_cb(skb)->retries++;
-       control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
-       control &= L2CAP_CTRL_SAR;
+
+       control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
+       control &= __get_sar_mask(chan);
 
        if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
-               control |= L2CAP_CTRL_FINAL;
+               control |= __set_ctrl_final(chan);
 
-       control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
-                       | (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
+       control |= __set_reqseq(chan, chan->buffer_seq);
+       control |= __set_txseq(chan, tx_seq);
 
-       put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
+       __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
 
        if (chan->fcs == L2CAP_FCS_CRC16) {
-               fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2);
-               put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2);
+               fcs = crc16(0, (u8 *)tx_skb->data,
+                                               tx_skb->len - L2CAP_FCS_SIZE);
+               put_unaligned_le16(fcs,
+                               tx_skb->data + tx_skb->len - L2CAP_FCS_SIZE);
        }
 
        l2cap_do_send(chan, tx_skb);
@@ -1330,7 +1360,8 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq)
 static int l2cap_ertm_send(struct l2cap_chan *chan)
 {
        struct sk_buff *skb, *tx_skb;
-       u16 control, fcs;
+       u16 fcs;
+       u32 control;
        int nsent = 0;
 
        if (chan->state != BT_CONNECTED)
@@ -1348,20 +1379,22 @@ static int l2cap_ertm_send(struct l2cap_chan *chan)
 
                bt_cb(skb)->retries++;
 
-               control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
-               control &= L2CAP_CTRL_SAR;
+               control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
+               control &= __get_sar_mask(chan);
 
                if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
-                       control |= L2CAP_CTRL_FINAL;
+                       control |= __set_ctrl_final(chan);
 
-               control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
-                               | (chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
-               put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
+               control |= __set_reqseq(chan, chan->buffer_seq);
+               control |= __set_txseq(chan, chan->next_tx_seq);
 
+               __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
 
                if (chan->fcs == L2CAP_FCS_CRC16) {
-                       fcs = crc16(0, (u8 *)skb->data, tx_skb->len - 2);
-                       put_unaligned_le16(fcs, skb->data + tx_skb->len - 2);
+                       fcs = crc16(0, (u8 *)skb->data,
+                                               tx_skb->len - L2CAP_FCS_SIZE);
+                       put_unaligned_le16(fcs, skb->data +
+                                               tx_skb->len - L2CAP_FCS_SIZE);
                }
 
                l2cap_do_send(chan, tx_skb);
@@ -1369,7 +1402,8 @@ static int l2cap_ertm_send(struct l2cap_chan *chan)
                __set_retrans_timer(chan);
 
                bt_cb(skb)->tx_seq = chan->next_tx_seq;
-               chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
+
+               chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
 
                if (bt_cb(skb)->retries == 1)
                        chan->unacked_frames++;
@@ -1401,12 +1435,12 @@ static int l2cap_retransmit_frames(struct l2cap_chan *chan)
 
 static void l2cap_send_ack(struct l2cap_chan *chan)
 {
-       u16 control = 0;
+       u32 control = 0;
 
-       control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+       control |= __set_reqseq(chan, chan->buffer_seq);
 
        if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
-               control |= L2CAP_SUPER_RCV_NOT_READY;
+               control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
                set_bit(CONN_RNR_SENT, &chan->conn_state);
                l2cap_send_sframe(chan, control);
                return;
@@ -1415,20 +1449,20 @@ static void l2cap_send_ack(struct l2cap_chan *chan)
        if (l2cap_ertm_send(chan) > 0)
                return;
 
-       control |= L2CAP_SUPER_RCV_READY;
+       control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
        l2cap_send_sframe(chan, control);
 }
 
 static void l2cap_send_srejtail(struct l2cap_chan *chan)
 {
        struct srej_list *tail;
-       u16 control;
+       u32 control;
 
-       control = L2CAP_SUPER_SELECT_REJECT;
-       control |= L2CAP_CTRL_FINAL;
+       control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
+       control |= __set_ctrl_final(chan);
 
        tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
-       control |= tail->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+       control |= __set_reqseq(chan, tail->tx_seq);
 
        l2cap_send_sframe(chan, control);
 }
@@ -1456,6 +1490,8 @@ static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, in
                if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
                        return -EFAULT;
 
+               (*frag)->priority = skb->priority;
+
                sent += count;
                len  -= count;
 
@@ -1465,15 +1501,17 @@ static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, in
        return sent;
 }
 
-static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
+static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
+                                               struct msghdr *msg, size_t len,
+                                               u32 priority)
 {
        struct sock *sk = chan->sk;
        struct l2cap_conn *conn = chan->conn;
        struct sk_buff *skb;
-       int err, count, hlen = L2CAP_HDR_SIZE + 2;
+       int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE;
        struct l2cap_hdr *lh;
 
-       BT_DBG("sk %p len %d", sk, (int)len);
+       BT_DBG("sk %p len %d priority %u", sk, (int)len, priority);
 
        count = min_t(unsigned int, (conn->mtu - hlen), len);
        skb = bt_skb_send_alloc(sk, count + hlen,
@@ -1481,6 +1519,8 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct
        if (!skb)
                return ERR_PTR(err);
 
+       skb->priority = priority;
+
        /* Create L2CAP header */
        lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
        lh->cid = cpu_to_le16(chan->dcid);
@@ -1495,7 +1535,9 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct
        return skb;
 }
 
-static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
+static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
+                                               struct msghdr *msg, size_t len,
+                                               u32 priority)
 {
        struct sock *sk = chan->sk;
        struct l2cap_conn *conn = chan->conn;
@@ -1511,6 +1553,8 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct ms
        if (!skb)
                return ERR_PTR(err);
 
+       skb->priority = priority;
+
        /* Create L2CAP header */
        lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
        lh->cid = cpu_to_le16(chan->dcid);
@@ -1526,12 +1570,12 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct ms
 
 static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
                                                struct msghdr *msg, size_t len,
-                                               u16 control, u16 sdulen)
+                                               u32 control, u16 sdulen)
 {
        struct sock *sk = chan->sk;
        struct l2cap_conn *conn = chan->conn;
        struct sk_buff *skb;
-       int err, count, hlen = L2CAP_HDR_SIZE + 2;
+       int err, count, hlen;
        struct l2cap_hdr *lh;
 
        BT_DBG("sk %p len %d", sk, (int)len);
@@ -1539,11 +1583,16 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
        if (!conn)
                return ERR_PTR(-ENOTCONN);
 
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               hlen = L2CAP_EXT_HDR_SIZE;
+       else
+               hlen = L2CAP_ENH_HDR_SIZE;
+
        if (sdulen)
-               hlen += 2;
+               hlen += L2CAP_SDULEN_SIZE;
 
        if (chan->fcs == L2CAP_FCS_CRC16)
-               hlen += 2;
+               hlen += L2CAP_FCS_SIZE;
 
        count = min_t(unsigned int, (conn->mtu - hlen), len);
        skb = bt_skb_send_alloc(sk, count + hlen,
@@ -1555,9 +1604,11 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
        lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
        lh->cid = cpu_to_le16(chan->dcid);
        lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
-       put_unaligned_le16(control, skb_put(skb, 2));
+
+       __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
+
        if (sdulen)
-               put_unaligned_le16(sdulen, skb_put(skb, 2));
+               put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
 
        err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
        if (unlikely(err < 0)) {
@@ -1566,7 +1617,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
        }
 
        if (chan->fcs == L2CAP_FCS_CRC16)
-               put_unaligned_le16(0, skb_put(skb, 2));
+               put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE));
 
        bt_cb(skb)->retries = 0;
        return skb;
@@ -1576,11 +1627,11 @@ static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, si
 {
        struct sk_buff *skb;
        struct sk_buff_head sar_queue;
-       u16 control;
+       u32 control;
        size_t size = 0;
 
        skb_queue_head_init(&sar_queue);
-       control = L2CAP_SDU_START;
+       control = __set_ctrl_sar(chan, L2CAP_SAR_START);
        skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
        if (IS_ERR(skb))
                return PTR_ERR(skb);
@@ -1593,10 +1644,10 @@ static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, si
                size_t buflen;
 
                if (len > chan->remote_mps) {
-                       control = L2CAP_SDU_CONTINUE;
+                       control = __set_ctrl_sar(chan, L2CAP_SAR_CONTINUE);
                        buflen = chan->remote_mps;
                } else {
-                       control = L2CAP_SDU_END;
+                       control = __set_ctrl_sar(chan, L2CAP_SAR_END);
                        buflen = len;
                }
 
@@ -1617,15 +1668,16 @@ static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, si
        return size;
 }
 
-int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
+int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
+                                                               u32 priority)
 {
        struct sk_buff *skb;
-       u16 control;
+       u32 control;
        int err;
 
        /* Connectionless channel */
        if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
-               skb = l2cap_create_connless_pdu(chan, msg, len);
+               skb = l2cap_create_connless_pdu(chan, msg, len, priority);
                if (IS_ERR(skb))
                        return PTR_ERR(skb);
 
@@ -1640,7 +1692,7 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
                        return -EMSGSIZE;
 
                /* Create a basic PDU */
-               skb = l2cap_create_basic_pdu(chan, msg, len);
+               skb = l2cap_create_basic_pdu(chan, msg, len, priority);
                if (IS_ERR(skb))
                        return PTR_ERR(skb);
 
@@ -1652,7 +1704,7 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
        case L2CAP_MODE_STREAMING:
                /* Entire SDU fits into one PDU */
                if (len <= chan->remote_mps) {
-                       control = L2CAP_SDU_UNSEGMENTED;
+                       control = __set_ctrl_sar(chan, L2CAP_SAR_UNSEGMENTED);
                        skb = l2cap_create_iframe_pdu(chan, msg, len, control,
                                                                        0);
                        if (IS_ERR(skb))
@@ -1850,6 +1902,37 @@ static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
        *ptr += L2CAP_CONF_OPT_SIZE + len;
 }
 
+static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
+{
+       struct l2cap_conf_efs efs;
+
+       switch(chan->mode) {
+       case L2CAP_MODE_ERTM:
+               efs.id          = chan->local_id;
+               efs.stype       = chan->local_stype;
+               efs.msdu        = cpu_to_le16(chan->local_msdu);
+               efs.sdu_itime   = cpu_to_le32(chan->local_sdu_itime);
+               efs.acc_lat     = cpu_to_le32(L2CAP_DEFAULT_ACC_LAT);
+               efs.flush_to    = cpu_to_le32(L2CAP_DEFAULT_FLUSH_TO);
+               break;
+
+       case L2CAP_MODE_STREAMING:
+               efs.id          = 1;
+               efs.stype       = L2CAP_SERV_BESTEFFORT;
+               efs.msdu        = cpu_to_le16(chan->local_msdu);
+               efs.sdu_itime   = cpu_to_le32(chan->local_sdu_itime);
+               efs.acc_lat     = 0;
+               efs.flush_to    = 0;
+               break;
+
+       default:
+               return;
+       }
+
+       l2cap_add_conf_opt(ptr, L2CAP_CONF_EFS, sizeof(efs),
+                                                       (unsigned long) &efs);
+}
+
 static void l2cap_ack_timeout(unsigned long arg)
 {
        struct l2cap_chan *chan = (void *) arg;
@@ -1896,11 +1979,36 @@ static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
        }
 }
 
+static inline bool __l2cap_ews_supported(struct l2cap_chan *chan)
+{
+       return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_WINDOW;
+}
+
+static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
+{
+       return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
+}
+
+static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
+{
+       if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW &&
+                                               __l2cap_ews_supported(chan)) {
+               /* use extended control field */
+               set_bit(FLAG_EXT_CTRL, &chan->flags);
+               chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
+       } else {
+               chan->tx_win = min_t(u16, chan->tx_win,
+                                               L2CAP_DEFAULT_TX_WINDOW);
+               chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
+       }
+}
+
 static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
 {
        struct l2cap_conf_req *req = data;
        struct l2cap_conf_rfc rfc = { .mode = chan->mode };
        void *ptr = req->data;
+       u16 size;
 
        BT_DBG("chan %p", chan);
 
@@ -1913,6 +2021,9 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
                if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state))
                        break;
 
+               if (__l2cap_efs_supported(chan))
+                       set_bit(FLAG_EFS_ENABLE, &chan->flags);
+
                /* fall through */
        default:
                chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask);
@@ -1942,17 +2053,27 @@ done:
 
        case L2CAP_MODE_ERTM:
                rfc.mode            = L2CAP_MODE_ERTM;
-               rfc.txwin_size      = chan->tx_win;
                rfc.max_transmit    = chan->max_tx;
                rfc.retrans_timeout = 0;
                rfc.monitor_timeout = 0;
-               rfc.max_pdu_size    = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
-               if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10)
-                       rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
+
+               size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
+                                               L2CAP_EXT_HDR_SIZE -
+                                               L2CAP_SDULEN_SIZE -
+                                               L2CAP_FCS_SIZE);
+               rfc.max_pdu_size = cpu_to_le16(size);
+
+               l2cap_txwin_setup(chan);
+
+               rfc.txwin_size = min_t(u16, chan->tx_win,
+                                               L2CAP_DEFAULT_TX_WINDOW);
 
                l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
                                                        (unsigned long) &rfc);
 
+               if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
+                       l2cap_add_opt_efs(&ptr, chan);
+
                if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
                        break;
 
@@ -1961,6 +2082,10 @@ done:
                        chan->fcs = L2CAP_FCS_NONE;
                        l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
                }
+
+               if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+                       l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
+                                                               chan->tx_win);
                break;
 
        case L2CAP_MODE_STREAMING:
@@ -1969,13 +2094,19 @@ done:
                rfc.max_transmit    = 0;
                rfc.retrans_timeout = 0;
                rfc.monitor_timeout = 0;
-               rfc.max_pdu_size    = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
-               if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10)
-                       rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
+
+               size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
+                                               L2CAP_EXT_HDR_SIZE -
+                                               L2CAP_SDULEN_SIZE -
+                                               L2CAP_FCS_SIZE);
+               rfc.max_pdu_size = cpu_to_le16(size);
 
                l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
                                                        (unsigned long) &rfc);
 
+               if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
+                       l2cap_add_opt_efs(&ptr, chan);
+
                if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
                        break;
 
@@ -2002,8 +2133,11 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
        int type, hint, olen;
        unsigned long val;
        struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
+       struct l2cap_conf_efs efs;
+       u8 remote_efs = 0;
        u16 mtu = L2CAP_DEFAULT_MTU;
        u16 result = L2CAP_CONF_SUCCESS;
+       u16 size;
 
        BT_DBG("chan %p", chan);
 
@@ -2033,7 +2167,22 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
                case L2CAP_CONF_FCS:
                        if (val == L2CAP_FCS_NONE)
                                set_bit(CONF_NO_FCS_RECV, &chan->conf_state);
+                       break;
+
+               case L2CAP_CONF_EFS:
+                       remote_efs = 1;
+                       if (olen == sizeof(efs))
+                               memcpy(&efs, (void *) val, olen);
+                       break;
+
+               case L2CAP_CONF_EWS:
+                       if (!enable_hs)
+                               return -ECONNREFUSED;
 
+                       set_bit(FLAG_EXT_CTRL, &chan->flags);
+                       set_bit(CONF_EWS_RECV, &chan->conf_state);
+                       chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
+                       chan->remote_tx_win = val;
                        break;
 
                default:
@@ -2058,6 +2207,13 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
                        break;
                }
 
+               if (remote_efs) {
+                       if (__l2cap_efs_supported(chan))
+                               set_bit(FLAG_EFS_ENABLE, &chan->flags);
+                       else
+                               return -ECONNREFUSED;
+               }
+
                if (chan->mode != rfc.mode)
                        return -ECONNREFUSED;
 
@@ -2076,7 +2232,6 @@ done:
                                        sizeof(rfc), (unsigned long) &rfc);
        }
 
-
        if (result == L2CAP_CONF_SUCCESS) {
                /* Configure output options and let the other side know
                 * which ones we don't like. */
@@ -2089,6 +2244,26 @@ done:
                }
                l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
 
+               if (remote_efs) {
+                       if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
+                                       efs.stype != L2CAP_SERV_NOTRAFIC &&
+                                       efs.stype != chan->local_stype) {
+
+                               result = L2CAP_CONF_UNACCEPT;
+
+                               if (chan->num_conf_req >= 1)
+                                       return -ECONNREFUSED;
+
+                               l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
+                                                       sizeof(efs),
+                                                       (unsigned long) &efs);
+                       } else {
+                               /* Send PENDING Conf Rsp */
+                               result = L2CAP_CONF_PENDING;
+                               set_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
+                       }
+               }
+
                switch (rfc.mode) {
                case L2CAP_MODE_BASIC:
                        chan->fcs = L2CAP_FCS_NONE;
@@ -2096,13 +2271,20 @@ done:
                        break;
 
                case L2CAP_MODE_ERTM:
-                       chan->remote_tx_win = rfc.txwin_size;
-                       chan->remote_max_tx = rfc.max_transmit;
+                       if (!test_bit(CONF_EWS_RECV, &chan->conf_state))
+                               chan->remote_tx_win = rfc.txwin_size;
+                       else
+                               rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW;
 
-                       if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10)
-                               rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
+                       chan->remote_max_tx = rfc.max_transmit;
 
-                       chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
+                       size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
+                                               chan->conn->mtu -
+                                               L2CAP_EXT_HDR_SIZE -
+                                               L2CAP_SDULEN_SIZE -
+                                               L2CAP_FCS_SIZE);
+                       rfc.max_pdu_size = cpu_to_le16(size);
+                       chan->remote_mps = size;
 
                        rfc.retrans_timeout =
                                le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO);
@@ -2114,13 +2296,29 @@ done:
                        l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
                                        sizeof(rfc), (unsigned long) &rfc);
 
+                       if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
+                               chan->remote_id = efs.id;
+                               chan->remote_stype = efs.stype;
+                               chan->remote_msdu = le16_to_cpu(efs.msdu);
+                               chan->remote_flush_to =
+                                               le32_to_cpu(efs.flush_to);
+                               chan->remote_acc_lat =
+                                               le32_to_cpu(efs.acc_lat);
+                               chan->remote_sdu_itime =
+                                       le32_to_cpu(efs.sdu_itime);
+                               l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
+                                       sizeof(efs), (unsigned long) &efs);
+                       }
                        break;
 
                case L2CAP_MODE_STREAMING:
-                       if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10)
-                               rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
-
-                       chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
+                       size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
+                                               chan->conn->mtu -
+                                               L2CAP_EXT_HDR_SIZE -
+                                               L2CAP_SDULEN_SIZE -
+                                               L2CAP_FCS_SIZE);
+                       rfc.max_pdu_size = cpu_to_le16(size);
+                       chan->remote_mps = size;
 
                        set_bit(CONF_MODE_DONE, &chan->conf_state);
 
@@ -2153,6 +2351,7 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
        int type, olen;
        unsigned long val;
        struct l2cap_conf_rfc rfc;
+       struct l2cap_conf_efs efs;
 
        BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
 
@@ -2188,6 +2387,26 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
                        l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
                                        sizeof(rfc), (unsigned long) &rfc);
                        break;
+
+               case L2CAP_CONF_EWS:
+                       chan->tx_win = min_t(u16, val,
+                                               L2CAP_DEFAULT_EXT_WINDOW);
+                       l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
+                                                       chan->tx_win);
+                       break;
+
+               case L2CAP_CONF_EFS:
+                       if (olen == sizeof(efs))
+                               memcpy(&efs, (void *)val, olen);
+
+                       if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
+                                       efs.stype != L2CAP_SERV_NOTRAFIC &&
+                                       efs.stype != chan->local_stype)
+                               return -ECONNREFUSED;
+
+                       l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
+                                       sizeof(efs), (unsigned long) &efs);
+                       break;
                }
        }
 
@@ -2196,13 +2415,23 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
 
        chan->mode = rfc.mode;
 
-       if (*result == L2CAP_CONF_SUCCESS) {
+       if (*result == L2CAP_CONF_SUCCESS || *result == L2CAP_CONF_PENDING) {
                switch (rfc.mode) {
                case L2CAP_MODE_ERTM:
                        chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
                        chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
                        chan->mps    = le16_to_cpu(rfc.max_pdu_size);
+
+                       if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
+                               chan->local_msdu = le16_to_cpu(efs.msdu);
+                               chan->local_sdu_itime =
+                                               le32_to_cpu(efs.sdu_itime);
+                               chan->local_acc_lat = le32_to_cpu(efs.acc_lat);
+                               chan->local_flush_to =
+                                               le32_to_cpu(efs.flush_to);
+                       }
                        break;
+
                case L2CAP_MODE_STREAMING:
                        chan->mps    = le16_to_cpu(rfc.max_pdu_size);
                }
@@ -2330,7 +2559,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
        /* Check if the ACL is secure enough (if not SDP) */
        if (psm != cpu_to_le16(0x0001) &&
                                !hci_conn_check_link_mode(conn->hcon)) {
-               conn->disc_reason = 0x05;
+               conn->disc_reason = HCI_ERROR_AUTH_FAILURE;
                result = L2CAP_CR_SEC_BLOCK;
                goto response;
        }
@@ -2488,7 +2717,7 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
                if (sock_owned_by_user(sk)) {
                        l2cap_state_change(chan, BT_DISCONN);
                        __clear_chan_timer(chan);
-                       __set_chan_timer(chan, HZ / 5);
+                       __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
                        break;
                }
 
@@ -2602,6 +2831,21 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
                chan->num_conf_req++;
        }
 
+       /* Got Conf Rsp PENDING from remote side and asume we sent
+          Conf Rsp PENDING in the code above */
+       if (test_bit(CONF_REM_CONF_PEND, &chan->conf_state) &&
+                       test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
+
+               /* check compatibility */
+
+               clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
+               set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
+
+               l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
+                                       l2cap_build_conf_rsp(chan, rsp,
+                                       L2CAP_CONF_SUCCESS, 0x0000), rsp);
+       }
+
 unlock:
        bh_unlock_sock(sk);
        return 0;
@@ -2631,8 +2875,33 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        switch (result) {
        case L2CAP_CONF_SUCCESS:
                l2cap_conf_rfc_get(chan, rsp->data, len);
+               clear_bit(CONF_REM_CONF_PEND, &chan->conf_state);
                break;
 
+       case L2CAP_CONF_PENDING:
+               set_bit(CONF_REM_CONF_PEND, &chan->conf_state);
+
+               if (test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
+                       char buf[64];
+
+                       len = l2cap_parse_conf_rsp(chan, rsp->data, len,
+                                                               buf, &result);
+                       if (len < 0) {
+                               l2cap_send_disconn_req(conn, chan, ECONNRESET);
+                               goto done;
+                       }
+
+                       /* check compatibility */
+
+                       clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
+                       set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
+
+                       l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
+                                               l2cap_build_conf_rsp(chan, buf,
+                                               L2CAP_CONF_SUCCESS, 0x0000), buf);
+               }
+               goto done;
+
        case L2CAP_CONF_UNACCEPT:
                if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
                        char req[64];
@@ -2661,7 +2930,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 
        default:
                sk->sk_err = ECONNRESET;
-               __set_chan_timer(chan, HZ * 5);
+               __set_chan_timer(chan, L2CAP_DISC_REJ_TIMEOUT);
                l2cap_send_disconn_req(conn, chan, ECONNRESET);
                goto done;
        }
@@ -2718,7 +2987,7 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
        if (sock_owned_by_user(sk)) {
                l2cap_state_change(chan, BT_DISCONN);
                __clear_chan_timer(chan);
-               __set_chan_timer(chan, HZ / 5);
+               __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
                bh_unlock_sock(sk);
                return 0;
        }
@@ -2752,7 +3021,7 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
        if (sock_owned_by_user(sk)) {
                l2cap_state_change(chan,BT_DISCONN);
                __clear_chan_timer(chan);
-               __set_chan_timer(chan, HZ / 5);
+               __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
                bh_unlock_sock(sk);
                return 0;
        }
@@ -2782,15 +3051,25 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm
                if (!disable_ertm)
                        feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
                                                         | L2CAP_FEAT_FCS;
+               if (enable_hs)
+                       feat_mask |= L2CAP_FEAT_EXT_FLOW
+                                               | L2CAP_FEAT_EXT_WINDOW;
+
                put_unaligned_le32(feat_mask, rsp->data);
                l2cap_send_cmd(conn, cmd->ident,
                                        L2CAP_INFO_RSP, sizeof(buf), buf);
        } else if (type == L2CAP_IT_FIXED_CHAN) {
                u8 buf[12];
                struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
+
+               if (enable_hs)
+                       l2cap_fixed_chan[0] |= L2CAP_FC_A2MP;
+               else
+                       l2cap_fixed_chan[0] &= ~L2CAP_FC_A2MP;
+
                rsp->type   = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
                rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
-               memcpy(buf + 4, l2cap_fixed_chan, 8);
+               memcpy(rsp->data, l2cap_fixed_chan, sizeof(l2cap_fixed_chan));
                l2cap_send_cmd(conn, cmd->ident,
                                        L2CAP_INFO_RSP, sizeof(buf), buf);
        } else {
@@ -2857,6 +3136,165 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
        return 0;
 }
 
+static inline int l2cap_create_channel_req(struct l2cap_conn *conn,
+                                       struct l2cap_cmd_hdr *cmd, u16 cmd_len,
+                                       void *data)
+{
+       struct l2cap_create_chan_req *req = data;
+       struct l2cap_create_chan_rsp rsp;
+       u16 psm, scid;
+
+       if (cmd_len != sizeof(*req))
+               return -EPROTO;
+
+       if (!enable_hs)
+               return -EINVAL;
+
+       psm = le16_to_cpu(req->psm);
+       scid = le16_to_cpu(req->scid);
+
+       BT_DBG("psm %d, scid %d, amp_id %d", psm, scid, req->amp_id);
+
+       /* Placeholder: Always reject */
+       rsp.dcid = 0;
+       rsp.scid = cpu_to_le16(scid);
+       rsp.result = L2CAP_CR_NO_MEM;
+       rsp.status = L2CAP_CS_NO_INFO;
+
+       l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP,
+                      sizeof(rsp), &rsp);
+
+       return 0;
+}
+
+static inline int l2cap_create_channel_rsp(struct l2cap_conn *conn,
+                                       struct l2cap_cmd_hdr *cmd, void *data)
+{
+       BT_DBG("conn %p", conn);
+
+       return l2cap_connect_rsp(conn, cmd, data);
+}
+
+static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident,
+                                                       u16 icid, u16 result)
+{
+       struct l2cap_move_chan_rsp rsp;
+
+       BT_DBG("icid %d, result %d", icid, result);
+
+       rsp.icid = cpu_to_le16(icid);
+       rsp.result = cpu_to_le16(result);
+
+       l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_RSP, sizeof(rsp), &rsp);
+}
+
+static void l2cap_send_move_chan_cfm(struct l2cap_conn *conn,
+                               struct l2cap_chan *chan, u16 icid, u16 result)
+{
+       struct l2cap_move_chan_cfm cfm;
+       u8 ident;
+
+       BT_DBG("icid %d, result %d", icid, result);
+
+       ident = l2cap_get_ident(conn);
+       if (chan)
+               chan->ident = ident;
+
+       cfm.icid = cpu_to_le16(icid);
+       cfm.result = cpu_to_le16(result);
+
+       l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM, sizeof(cfm), &cfm);
+}
+
+static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident,
+                                                               u16 icid)
+{
+       struct l2cap_move_chan_cfm_rsp rsp;
+
+       BT_DBG("icid %d", icid);
+
+       rsp.icid = cpu_to_le16(icid);
+       l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp);
+}
+
+static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
+                       struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
+{
+       struct l2cap_move_chan_req *req = data;
+       u16 icid = 0;
+       u16 result = L2CAP_MR_NOT_ALLOWED;
+
+       if (cmd_len != sizeof(*req))
+               return -EPROTO;
+
+       icid = le16_to_cpu(req->icid);
+
+       BT_DBG("icid %d, dest_amp_id %d", icid, req->dest_amp_id);
+
+       if (!enable_hs)
+               return -EINVAL;
+
+       /* Placeholder: Always refuse */
+       l2cap_send_move_chan_rsp(conn, cmd->ident, icid, result);
+
+       return 0;
+}
+
+static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn,
+                       struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
+{
+       struct l2cap_move_chan_rsp *rsp = data;
+       u16 icid, result;
+
+       if (cmd_len != sizeof(*rsp))
+               return -EPROTO;
+
+       icid = le16_to_cpu(rsp->icid);
+       result = le16_to_cpu(rsp->result);
+
+       BT_DBG("icid %d, result %d", icid, result);
+
+       /* Placeholder: Always unconfirmed */
+       l2cap_send_move_chan_cfm(conn, NULL, icid, L2CAP_MC_UNCONFIRMED);
+
+       return 0;
+}
+
+static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn,
+                       struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
+{
+       struct l2cap_move_chan_cfm *cfm = data;
+       u16 icid, result;
+
+       if (cmd_len != sizeof(*cfm))
+               return -EPROTO;
+
+       icid = le16_to_cpu(cfm->icid);
+       result = le16_to_cpu(cfm->result);
+
+       BT_DBG("icid %d, result %d", icid, result);
+
+       l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid);
+
+       return 0;
+}
+
+static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
+                       struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
+{
+       struct l2cap_move_chan_cfm_rsp *rsp = data;
+       u16 icid;
+
+       if (cmd_len != sizeof(*rsp))
+               return -EPROTO;
+
+       icid = le16_to_cpu(rsp->icid);
+
+       BT_DBG("icid %d", icid);
+
+       return 0;
+}
+
 static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
                                                        u16 to_multiplier)
 {
@@ -2969,6 +3407,30 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
                err = l2cap_information_rsp(conn, cmd, data);
                break;
 
+       case L2CAP_CREATE_CHAN_REQ:
+               err = l2cap_create_channel_req(conn, cmd, cmd_len, data);
+               break;
+
+       case L2CAP_CREATE_CHAN_RSP:
+               err = l2cap_create_channel_rsp(conn, cmd, data);
+               break;
+
+       case L2CAP_MOVE_CHAN_REQ:
+               err = l2cap_move_channel_req(conn, cmd, cmd_len, data);
+               break;
+
+       case L2CAP_MOVE_CHAN_RSP:
+               err = l2cap_move_channel_rsp(conn, cmd, cmd_len, data);
+               break;
+
+       case L2CAP_MOVE_CHAN_CFM:
+               err = l2cap_move_channel_confirm(conn, cmd, cmd_len, data);
+               break;
+
+       case L2CAP_MOVE_CHAN_CFM_RSP:
+               err = l2cap_move_channel_confirm_rsp(conn, cmd, cmd_len, data);
+               break;
+
        default:
                BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
                err = -EINVAL;
@@ -3047,10 +3509,15 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn,
 static int l2cap_check_fcs(struct l2cap_chan *chan,  struct sk_buff *skb)
 {
        u16 our_fcs, rcv_fcs;
-       int hdr_size = L2CAP_HDR_SIZE + 2;
+       int hdr_size;
+
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               hdr_size = L2CAP_EXT_HDR_SIZE;
+       else
+               hdr_size = L2CAP_ENH_HDR_SIZE;
 
        if (chan->fcs == L2CAP_FCS_CRC16) {
-               skb_trim(skb, skb->len - 2);
+               skb_trim(skb, skb->len - L2CAP_FCS_SIZE);
                rcv_fcs = get_unaligned_le16(skb->data + skb->len);
                our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
 
@@ -3062,14 +3529,14 @@ static int l2cap_check_fcs(struct l2cap_chan *chan,  struct sk_buff *skb)
 
 static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
 {
-       u16 control = 0;
+       u32 control = 0;
 
        chan->frames_sent = 0;
 
-       control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+       control |= __set_reqseq(chan, chan->buffer_seq);
 
        if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
-               control |= L2CAP_SUPER_RCV_NOT_READY;
+               control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
                l2cap_send_sframe(chan, control);
                set_bit(CONN_RNR_SENT, &chan->conn_state);
        }
@@ -3081,12 +3548,12 @@ static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
 
        if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state) &&
                        chan->frames_sent == 0) {
-               control |= L2CAP_SUPER_RCV_READY;
+               control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
                l2cap_send_sframe(chan, control);
        }
 }
 
-static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, u8 tx_seq, u8 sar)
+static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, u16 tx_seq, u8 sar)
 {
        struct sk_buff *next_skb;
        int tx_seq_offset, next_tx_seq_offset;
@@ -3100,18 +3567,14 @@ static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb,
                return 0;
        }
 
-       tx_seq_offset = (tx_seq - chan->buffer_seq) % 64;
-       if (tx_seq_offset < 0)
-               tx_seq_offset += 64;
+       tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
 
        do {
                if (bt_cb(next_skb)->tx_seq == tx_seq)
                        return -EINVAL;
 
-               next_tx_seq_offset = (bt_cb(next_skb)->tx_seq -
-                                               chan->buffer_seq) % 64;
-               if (next_tx_seq_offset < 0)
-                       next_tx_seq_offset += 64;
+               next_tx_seq_offset = __seq_offset(chan,
+                               bt_cb(next_skb)->tx_seq, chan->buffer_seq);
 
                if (next_tx_seq_offset > tx_seq_offset) {
                        __skb_queue_before(&chan->srej_q, next_skb, skb);
@@ -3147,24 +3610,24 @@ static void append_skb_frag(struct sk_buff *skb,
        skb->truesize += new_frag->truesize;
 }
 
-static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
+static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u32 control)
 {
        int err = -EINVAL;
 
-       switch (control & L2CAP_CTRL_SAR) {
-       case L2CAP_SDU_UNSEGMENTED:
+       switch (__get_ctrl_sar(chan, control)) {
+       case L2CAP_SAR_UNSEGMENTED:
                if (chan->sdu)
                        break;
 
                err = chan->ops->recv(chan->data, skb);
                break;
 
-       case L2CAP_SDU_START:
+       case L2CAP_SAR_START:
                if (chan->sdu)
                        break;
 
                chan->sdu_len = get_unaligned_le16(skb->data);
-               skb_pull(skb, 2);
+               skb_pull(skb, L2CAP_SDULEN_SIZE);
 
                if (chan->sdu_len > chan->imtu) {
                        err = -EMSGSIZE;
@@ -3181,7 +3644,7 @@ static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u1
                err = 0;
                break;
 
-       case L2CAP_SDU_CONTINUE:
+       case L2CAP_SAR_CONTINUE:
                if (!chan->sdu)
                        break;
 
@@ -3195,7 +3658,7 @@ static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u1
                err = 0;
                break;
 
-       case L2CAP_SDU_END:
+       case L2CAP_SAR_END:
                if (!chan->sdu)
                        break;
 
@@ -3230,14 +3693,14 @@ static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u1
 
 static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
 {
-       u16 control;
+       u32 control;
 
        BT_DBG("chan %p, Enter local busy", chan);
 
        set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
 
-       control = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
-       control |= L2CAP_SUPER_RCV_NOT_READY;
+       control = __set_reqseq(chan, chan->buffer_seq);
+       control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
        l2cap_send_sframe(chan, control);
 
        set_bit(CONN_RNR_SENT, &chan->conn_state);
@@ -3247,13 +3710,14 @@ static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
 
 static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
 {
-       u16 control;
+       u32 control;
 
        if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
                goto done;
 
-       control = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
-       control |= L2CAP_SUPER_RCV_READY | L2CAP_CTRL_POLL;
+       control = __set_reqseq(chan, chan->buffer_seq);
+       control |= __set_ctrl_poll(chan);
+       control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
        l2cap_send_sframe(chan, control);
        chan->retry_count = 1;
 
@@ -3279,10 +3743,10 @@ void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
        }
 }
 
-static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq)
+static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq)
 {
        struct sk_buff *skb;
-       u16 control;
+       u32 control;
 
        while ((skb = skb_peek(&chan->srej_q)) &&
                        !test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
@@ -3292,7 +3756,7 @@ static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq)
                        break;
 
                skb = skb_dequeue(&chan->srej_q);
-               control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
+               control = __set_ctrl_sar(chan, bt_cb(skb)->sar);
                err = l2cap_reassemble_sdu(chan, skb, control);
 
                if (err < 0) {
@@ -3300,16 +3764,15 @@ static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq)
                        break;
                }
 
-               chan->buffer_seq_srej =
-                       (chan->buffer_seq_srej + 1) % 64;
-               tx_seq = (tx_seq + 1) % 64;
+               chan->buffer_seq_srej = __next_seq(chan, chan->buffer_seq_srej);
+               tx_seq = __next_seq(chan, tx_seq);
        }
 }
 
-static void l2cap_resend_srejframe(struct l2cap_chan *chan, u8 tx_seq)
+static void l2cap_resend_srejframe(struct l2cap_chan *chan, u16 tx_seq)
 {
        struct srej_list *l, *tmp;
-       u16 control;
+       u32 control;
 
        list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
                if (l->tx_seq == tx_seq) {
@@ -3317,45 +3780,48 @@ static void l2cap_resend_srejframe(struct l2cap_chan *chan, u8 tx_seq)
                        kfree(l);
                        return;
                }
-               control = L2CAP_SUPER_SELECT_REJECT;
-               control |= l->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+               control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
+               control |= __set_reqseq(chan, l->tx_seq);
                l2cap_send_sframe(chan, control);
                list_del(&l->list);
                list_add_tail(&l->list, &chan->srej_l);
        }
 }
 
-static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq)
+static void l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
 {
        struct srej_list *new;
-       u16 control;
+       u32 control;
 
        while (tx_seq != chan->expected_tx_seq) {
-               control = L2CAP_SUPER_SELECT_REJECT;
-               control |= chan->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+               control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
+               control |= __set_reqseq(chan, chan->expected_tx_seq);
                l2cap_send_sframe(chan, control);
 
                new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
                new->tx_seq = chan->expected_tx_seq;
-               chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
+
+               chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
+
                list_add_tail(&new->list, &chan->srej_l);
        }
-       chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
+
+       chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
 }
 
-static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb)
+static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_control, struct sk_buff *skb)
 {
-       u8 tx_seq = __get_txseq(rx_control);
-       u8 req_seq = __get_reqseq(rx_control);
-       u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT;
+       u16 tx_seq = __get_txseq(chan, rx_control);
+       u16 req_seq = __get_reqseq(chan, rx_control);
+       u8 sar = __get_ctrl_sar(chan, rx_control);
        int tx_seq_offset, expected_tx_seq_offset;
        int num_to_ack = (chan->tx_win/6) + 1;
        int err = 0;
 
-       BT_DBG("chan %p len %d tx_seq %d rx_control 0x%4.4x", chan, skb->len,
+       BT_DBG("chan %p len %d tx_seq %d rx_control 0x%8.8x", chan, skb->len,
                                                        tx_seq, rx_control);
 
-       if (L2CAP_CTRL_FINAL & rx_control &&
+       if (__is_ctrl_final(chan, rx_control) &&
                        test_bit(CONN_WAIT_F, &chan->conn_state)) {
                __clear_monitor_timer(chan);
                if (chan->unacked_frames > 0)
@@ -3366,9 +3832,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
        chan->expected_ack_seq = req_seq;
        l2cap_drop_acked_frames(chan);
 
-       tx_seq_offset = (tx_seq - chan->buffer_seq) % 64;
-       if (tx_seq_offset < 0)
-               tx_seq_offset += 64;
+       tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
 
        /* invalid tx_seq */
        if (tx_seq_offset >= chan->tx_win) {
@@ -3416,10 +3880,8 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
                        l2cap_send_srejframe(chan, tx_seq);
                }
        } else {
-               expected_tx_seq_offset =
-                       (chan->expected_tx_seq - chan->buffer_seq) % 64;
-               if (expected_tx_seq_offset < 0)
-                       expected_tx_seq_offset += 64;
+               expected_tx_seq_offset = __seq_offset(chan,
+                               chan->expected_tx_seq, chan->buffer_seq);
 
                /* duplicated tx_seq */
                if (tx_seq_offset < expected_tx_seq_offset)
@@ -3444,7 +3906,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
        return 0;
 
 expected:
-       chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
+       chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
 
        if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
                bt_cb(skb)->tx_seq = tx_seq;
@@ -3454,13 +3916,14 @@ expected:
        }
 
        err = l2cap_reassemble_sdu(chan, skb, rx_control);
-       chan->buffer_seq = (chan->buffer_seq + 1) % 64;
+       chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
+
        if (err < 0) {
                l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
                return err;
        }
 
-       if (rx_control & L2CAP_CTRL_FINAL) {
+       if (__is_ctrl_final(chan, rx_control)) {
                if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
                        l2cap_retransmit_frames(chan);
        }
@@ -3478,15 +3941,15 @@ drop:
        return 0;
 }
 
-static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_control)
+static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u32 rx_control)
 {
-       BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, __get_reqseq(rx_control),
-                                               rx_control);
+       BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan,
+                               __get_reqseq(chan, rx_control), rx_control);
 
-       chan->expected_ack_seq = __get_reqseq(rx_control);
+       chan->expected_ack_seq = __get_reqseq(chan, rx_control);
        l2cap_drop_acked_frames(chan);
 
-       if (rx_control & L2CAP_CTRL_POLL) {
+       if (__is_ctrl_poll(chan, rx_control)) {
                set_bit(CONN_SEND_FBIT, &chan->conn_state);
                if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
                        if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
@@ -3499,7 +3962,7 @@ static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_co
                        l2cap_send_i_or_rr_or_rnr(chan);
                }
 
-       } else if (rx_control & L2CAP_CTRL_FINAL) {
+       } else if (__is_ctrl_final(chan, rx_control)) {
                clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
 
                if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
@@ -3518,18 +3981,18 @@ static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_co
        }
 }
 
-static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u16 rx_control)
+static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u32 rx_control)
 {
-       u8 tx_seq = __get_reqseq(rx_control);
+       u16 tx_seq = __get_reqseq(chan, rx_control);
 
-       BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
+       BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
 
        clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
 
        chan->expected_ack_seq = tx_seq;
        l2cap_drop_acked_frames(chan);
 
-       if (rx_control & L2CAP_CTRL_FINAL) {
+       if (__is_ctrl_final(chan, rx_control)) {
                if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
                        l2cap_retransmit_frames(chan);
        } else {
@@ -3539,15 +4002,15 @@ static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u16 rx_c
                        set_bit(CONN_REJ_ACT, &chan->conn_state);
        }
 }
-static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_control)
+static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u32 rx_control)
 {
-       u8 tx_seq = __get_reqseq(rx_control);
+       u16 tx_seq = __get_reqseq(chan, rx_control);
 
-       BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
+       BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
 
        clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
 
-       if (rx_control & L2CAP_CTRL_POLL) {
+       if (__is_ctrl_poll(chan, rx_control)) {
                chan->expected_ack_seq = tx_seq;
                l2cap_drop_acked_frames(chan);
 
@@ -3560,7 +4023,7 @@ static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_
                        chan->srej_save_reqseq = tx_seq;
                        set_bit(CONN_SREJ_ACT, &chan->conn_state);
                }
-       } else if (rx_control & L2CAP_CTRL_FINAL) {
+       } else if (__is_ctrl_final(chan, rx_control)) {
                if (test_bit(CONN_SREJ_ACT, &chan->conn_state) &&
                                chan->srej_save_reqseq == tx_seq)
                        clear_bit(CONN_SREJ_ACT, &chan->conn_state);
@@ -3575,37 +4038,39 @@ static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_
        }
 }
 
-static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u16 rx_control)
+static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u32 rx_control)
 {
-       u8 tx_seq = __get_reqseq(rx_control);
+       u16 tx_seq = __get_reqseq(chan, rx_control);
 
-       BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
+       BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
 
        set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
        chan->expected_ack_seq = tx_seq;
        l2cap_drop_acked_frames(chan);
 
-       if (rx_control & L2CAP_CTRL_POLL)
+       if (__is_ctrl_poll(chan, rx_control))
                set_bit(CONN_SEND_FBIT, &chan->conn_state);
 
        if (!test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
                __clear_retrans_timer(chan);
-               if (rx_control & L2CAP_CTRL_POLL)
+               if (__is_ctrl_poll(chan, rx_control))
                        l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
                return;
        }
 
-       if (rx_control & L2CAP_CTRL_POLL)
+       if (__is_ctrl_poll(chan, rx_control)) {
                l2cap_send_srejtail(chan);
-       else
-               l2cap_send_sframe(chan, L2CAP_SUPER_RCV_READY);
+       } else {
+               rx_control = __set_ctrl_super(chan, L2CAP_SUPER_RR);
+               l2cap_send_sframe(chan, rx_control);
+       }
 }
 
-static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb)
+static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u32 rx_control, struct sk_buff *skb)
 {
-       BT_DBG("chan %p rx_control 0x%4.4x len %d", chan, rx_control, skb->len);
+       BT_DBG("chan %p rx_control 0x%8.8x len %d", chan, rx_control, skb->len);
 
-       if (L2CAP_CTRL_FINAL & rx_control &&
+       if (__is_ctrl_final(chan, rx_control) &&
                        test_bit(CONN_WAIT_F, &chan->conn_state)) {
                __clear_monitor_timer(chan);
                if (chan->unacked_frames > 0)
@@ -3613,20 +4078,20 @@ static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u16 rx_cont
                clear_bit(CONN_WAIT_F, &chan->conn_state);
        }
 
-       switch (rx_control & L2CAP_CTRL_SUPERVISE) {
-       case L2CAP_SUPER_RCV_READY:
+       switch (__get_ctrl_super(chan, rx_control)) {
+       case L2CAP_SUPER_RR:
                l2cap_data_channel_rrframe(chan, rx_control);
                break;
 
-       case L2CAP_SUPER_REJECT:
+       case L2CAP_SUPER_REJ:
                l2cap_data_channel_rejframe(chan, rx_control);
                break;
 
-       case L2CAP_SUPER_SELECT_REJECT:
+       case L2CAP_SUPER_SREJ:
                l2cap_data_channel_srejframe(chan, rx_control);
                break;
 
-       case L2CAP_SUPER_RCV_NOT_READY:
+       case L2CAP_SUPER_RNR:
                l2cap_data_channel_rnrframe(chan, rx_control);
                break;
        }
@@ -3638,12 +4103,12 @@ static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u16 rx_cont
 static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
 {
        struct l2cap_chan *chan = l2cap_pi(sk)->chan;
-       u16 control;
-       u8 req_seq;
+       u32 control;
+       u16 req_seq;
        int len, next_tx_seq_offset, req_seq_offset;
 
-       control = get_unaligned_le16(skb->data);
-       skb_pull(skb, 2);
+       control = __get_control(chan, skb->data);
+       skb_pull(skb, __ctrl_size(chan));
        len = skb->len;
 
        /*
@@ -3654,26 +4119,23 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
        if (l2cap_check_fcs(chan, skb))
                goto drop;
 
-       if (__is_sar_start(control) && __is_iframe(control))
-               len -= 2;
+       if (__is_sar_start(chan, control) && !__is_sframe(chan, control))
+               len -= L2CAP_SDULEN_SIZE;
 
        if (chan->fcs == L2CAP_FCS_CRC16)
-               len -= 2;
+               len -= L2CAP_FCS_SIZE;
 
        if (len > chan->mps) {
                l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
                goto drop;
        }
 
-       req_seq = __get_reqseq(control);
-       req_seq_offset = (req_seq - chan->expected_ack_seq) % 64;
-       if (req_seq_offset < 0)
-               req_seq_offset += 64;
+       req_seq = __get_reqseq(chan, control);
 
-       next_tx_seq_offset =
-               (chan->next_tx_seq - chan->expected_ack_seq) % 64;
-       if (next_tx_seq_offset < 0)
-               next_tx_seq_offset += 64;
+       req_seq_offset = __seq_offset(chan, req_seq, chan->expected_ack_seq);
+
+       next_tx_seq_offset = __seq_offset(chan, chan->next_tx_seq,
+                                               chan->expected_ack_seq);
 
        /* check for invalid req-seq */
        if (req_seq_offset > next_tx_seq_offset) {
@@ -3681,7 +4143,7 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
                goto drop;
        }
 
-       if (__is_iframe(control)) {
+       if (!__is_sframe(chan, control)) {
                if (len < 0) {
                        l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
                        goto drop;
@@ -3709,8 +4171,8 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
 {
        struct l2cap_chan *chan;
        struct sock *sk = NULL;
-       u16 control;
-       u8 tx_seq;
+       u32 control;
+       u16 tx_seq;
        int len;
 
        chan = l2cap_get_chan_by_scid(conn, cid);
@@ -3751,23 +4213,23 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
                goto done;
 
        case L2CAP_MODE_STREAMING:
-               control = get_unaligned_le16(skb->data);
-               skb_pull(skb, 2);
+               control = __get_control(chan, skb->data);
+               skb_pull(skb, __ctrl_size(chan));
                len = skb->len;
 
                if (l2cap_check_fcs(chan, skb))
                        goto drop;
 
-               if (__is_sar_start(control))
-                       len -= 2;
+               if (__is_sar_start(chan, control))
+                       len -= L2CAP_SDULEN_SIZE;
 
                if (chan->fcs == L2CAP_FCS_CRC16)
-                       len -= 2;
+                       len -= L2CAP_FCS_SIZE;
 
-               if (len > chan->mps || len < 0 || __is_sframe(control))
+               if (len > chan->mps || len < 0 || __is_sframe(chan, control))
                        goto drop;
 
-               tx_seq = __get_txseq(control);
+               tx_seq = __get_txseq(chan, control);
 
                if (chan->expected_tx_seq != tx_seq) {
                        /* Frame(s) missing - must discard partial SDU */
@@ -3779,7 +4241,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
                        /* TODO: Notify userland of missing data */
                }
 
-               chan->expected_tx_seq = (tx_seq + 1) % 64;
+               chan->expected_tx_seq = __next_seq(chan, tx_seq);
 
                if (l2cap_reassemble_sdu(chan, skb, control) == -EMSGSIZE)
                        l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
@@ -3933,12 +4395,12 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
 
                if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
                        lm1 |= HCI_LM_ACCEPT;
-                       if (c->role_switch)
+                       if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
                                lm1 |= HCI_LM_MASTER;
                        exact++;
                } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
                        lm2 |= HCI_LM_ACCEPT;
-                       if (c->role_switch)
+                       if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
                                lm2 |= HCI_LM_MASTER;
                }
        }
@@ -3973,7 +4435,7 @@ static int l2cap_disconn_ind(struct hci_conn *hcon)
        BT_DBG("hcon %p", hcon);
 
        if ((hcon->type != ACL_LINK && hcon->type != LE_LINK) || !conn)
-               return 0x13;
+               return HCI_ERROR_REMOTE_USER_TERM;
 
        return conn->disc_reason;
 }
@@ -3998,7 +4460,7 @@ static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
        if (encrypt == 0x00) {
                if (chan->sec_level == BT_SECURITY_MEDIUM) {
                        __clear_chan_timer(chan);
-                       __set_chan_timer(chan, HZ * 5);
+                       __set_chan_timer(chan, L2CAP_ENC_TIMEOUT);
                } else if (chan->sec_level == BT_SECURITY_HIGH)
                        l2cap_chan_close(chan, ECONNREFUSED);
        } else {
@@ -4066,7 +4528,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
                                        L2CAP_CONN_REQ, sizeof(req), &req);
                        } else {
                                __clear_chan_timer(chan);
-                               __set_chan_timer(chan, HZ / 10);
+                               __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
                        }
                } else if (chan->state == BT_CONNECT2) {
                        struct l2cap_conn_rsp rsp;
@@ -4086,7 +4548,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
                                }
                        } else {
                                l2cap_state_change(chan, BT_DISCONN);
-                               __set_chan_timer(chan, HZ / 10);
+                               __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
                                res = L2CAP_CR_SEC_BLOCK;
                                stat = L2CAP_CS_NO_INFO;
                        }
@@ -4306,3 +4768,6 @@ void l2cap_exit(void)
 
 module_param(disable_ertm, bool, 0644);
 MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");
+
+module_param(enable_hs, bool, 0644);
+MODULE_PARM_DESC(enable_hs, "Enable High Speed");
index 5c406d3..e2e785c 100644 (file)
@@ -334,7 +334,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us
                opts.mode     = chan->mode;
                opts.fcs      = chan->fcs;
                opts.max_tx   = chan->max_tx;
-               opts.txwin_size = (__u16)chan->tx_win;
+               opts.txwin_size = chan->tx_win;
 
                len = min_t(unsigned int, len, sizeof(opts));
                if (copy_to_user(optval, (char *) &opts, len))
@@ -359,10 +359,10 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us
                        break;
                }
 
-               if (chan->role_switch)
+               if (test_bit(FLAG_ROLE_SWITCH, &chan->flags))
                        opt |= L2CAP_LM_MASTER;
 
-               if (chan->force_reliable)
+               if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
                        opt |= L2CAP_LM_RELIABLE;
 
                if (put_user(opt, (u32 __user *) optval))
@@ -449,7 +449,8 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
                break;
 
        case BT_FLUSHABLE:
-               if (put_user(chan->flushable, (u32 __user *) optval))
+               if (put_user(test_bit(FLAG_FLUSHABLE, &chan->flags),
+                                               (u32 __user *) optval))
                        err = -EFAULT;
 
                break;
@@ -461,7 +462,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
                        break;
                }
 
-               pwr.force_active = chan->force_active;
+               pwr.force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags);
 
                len = min_t(unsigned int, len, sizeof(pwr));
                if (copy_to_user(optval, (char *) &pwr, len))
@@ -469,6 +470,16 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
 
                break;
 
+       case BT_CHANNEL_POLICY:
+               if (!enable_hs) {
+                       err = -ENOPROTOOPT;
+                       break;
+               }
+
+               if (put_user(chan->chan_policy, (u32 __user *) optval))
+                       err = -EFAULT;
+               break;
+
        default:
                err = -ENOPROTOOPT;
                break;
@@ -503,7 +514,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
                opts.mode     = chan->mode;
                opts.fcs      = chan->fcs;
                opts.max_tx   = chan->max_tx;
-               opts.txwin_size = (__u16)chan->tx_win;
+               opts.txwin_size = chan->tx_win;
 
                len = min_t(unsigned int, sizeof(opts), optlen);
                if (copy_from_user((char *) &opts, optval, len)) {
@@ -511,7 +522,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
                        break;
                }
 
-               if (opts.txwin_size > L2CAP_DEFAULT_TX_WINDOW) {
+               if (opts.txwin_size > L2CAP_DEFAULT_EXT_WINDOW) {
                        err = -EINVAL;
                        break;
                }
@@ -535,7 +546,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
                chan->omtu = opts.omtu;
                chan->fcs  = opts.fcs;
                chan->max_tx = opts.max_tx;
-               chan->tx_win = (__u8)opts.txwin_size;
+               chan->tx_win = opts.txwin_size;
                break;
 
        case L2CAP_LM:
@@ -551,8 +562,15 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
                if (opt & L2CAP_LM_SECURE)
                        chan->sec_level = BT_SECURITY_HIGH;
 
-               chan->role_switch    = (opt & L2CAP_LM_MASTER);
-               chan->force_reliable = (opt & L2CAP_LM_RELIABLE);
+               if (opt & L2CAP_LM_MASTER)
+                       set_bit(FLAG_ROLE_SWITCH, &chan->flags);
+               else
+                       clear_bit(FLAG_ROLE_SWITCH, &chan->flags);
+
+               if (opt & L2CAP_LM_RELIABLE)
+                       set_bit(FLAG_FORCE_RELIABLE, &chan->flags);
+               else
+                       clear_bit(FLAG_FORCE_RELIABLE, &chan->flags);
                break;
 
        default:
@@ -658,7 +676,10 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
                        }
                }
 
-               chan->flushable = opt;
+               if (opt)
+                       set_bit(FLAG_FLUSHABLE, &chan->flags);
+               else
+                       clear_bit(FLAG_FLUSHABLE, &chan->flags);
                break;
 
        case BT_POWER:
@@ -675,7 +696,36 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
                        err = -EFAULT;
                        break;
                }
-               chan->force_active = pwr.force_active;
+
+               if (pwr.force_active)
+                       set_bit(FLAG_FORCE_ACTIVE, &chan->flags);
+               else
+                       clear_bit(FLAG_FORCE_ACTIVE, &chan->flags);
+               break;
+
+       case BT_CHANNEL_POLICY:
+               if (!enable_hs) {
+                       err = -ENOPROTOOPT;
+                       break;
+               }
+
+               if (get_user(opt, (u32 __user *) optval)) {
+                       err = -EFAULT;
+                       break;
+               }
+
+               if (opt > BT_CHANNEL_POLICY_AMP_PREFERRED) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               if (chan->mode != L2CAP_MODE_ERTM &&
+                               chan->mode != L2CAP_MODE_STREAMING) {
+                       err = -EOPNOTSUPP;
+                       break;
+               }
+
+               chan->chan_policy = (u8) opt;
                break;
 
        default:
@@ -709,7 +759,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
                return -ENOTCONN;
        }
 
-       err = l2cap_chan_send(chan, msg, len);
+       err = l2cap_chan_send(chan, msg, len, sk->sk_priority);
 
        release_sock(sk);
        return err;
@@ -931,11 +981,9 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
                chan->fcs  = pchan->fcs;
                chan->max_tx = pchan->max_tx;
                chan->tx_win = pchan->tx_win;
+               chan->tx_win_max = pchan->tx_win_max;
                chan->sec_level = pchan->sec_level;
-               chan->role_switch = pchan->role_switch;
-               chan->force_reliable = pchan->force_reliable;
-               chan->flushable = pchan->flushable;
-               chan->force_active = pchan->force_active;
+               chan->flags = pchan->flags;
 
                security_sk_clone(parent, sk);
        } else {
@@ -964,12 +1012,10 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
                chan->max_tx = L2CAP_DEFAULT_MAX_TX;
                chan->fcs  = L2CAP_FCS_CRC16;
                chan->tx_win = L2CAP_DEFAULT_TX_WINDOW;
+               chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
                chan->sec_level = BT_SECURITY_LOW;
-               chan->role_switch = 0;
-               chan->force_reliable = 0;
-               chan->flushable = BT_FLUSHABLE_OFF;
-               chan->force_active = BT_POWER_FORCE_ACTIVE_ON;
-
+               chan->flags = 0;
+               set_bit(FLAG_FORCE_ACTIVE, &chan->flags);
        }
 
        /* Default config options */
index 2c76342..94739d3 100644 (file)
 #define MGMT_VERSION   0
 #define MGMT_REVISION  1
 
+#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
+
 struct pending_cmd {
        struct list_head list;
-       __u16 opcode;
+       u16 opcode;
        int index;
        void *param;
        struct sock *sk;
        void *user_data;
 };
 
-static LIST_HEAD(cmd_list);
-
 static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
 {
        struct sk_buff *skb;
        struct mgmt_hdr *hdr;
        struct mgmt_ev_cmd_status *ev;
+       int err;
 
        BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
 
@@ -66,10 +67,11 @@ static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
        ev->status = status;
        put_unaligned_le16(cmd, &ev->opcode);
 
-       if (sock_queue_rcv_skb(sk, skb) < 0)
+       err = sock_queue_rcv_skb(sk, skb);
+       if (err < 0)
                kfree_skb(skb);
 
-       return 0;
+       return err;
 }
 
 static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
@@ -78,6 +80,7 @@ static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
        struct sk_buff *skb;
        struct mgmt_hdr *hdr;
        struct mgmt_ev_cmd_complete *ev;
+       int err;
 
        BT_DBG("sock %p", sk);
 
@@ -97,10 +100,11 @@ static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
        if (rp)
                memcpy(ev->data, rp, rp_len);
 
-       if (sock_queue_rcv_skb(sk, skb) < 0)
+       err = sock_queue_rcv_skb(sk, skb);
+       if (err < 0)
                kfree_skb(skb);
 
-       return 0;
+       return err;;
 }
 
 static int read_version(struct sock *sk)
@@ -120,6 +124,7 @@ static int read_index_list(struct sock *sk)
 {
        struct mgmt_rp_read_index_list *rp;
        struct list_head *p;
+       struct hci_dev *d;
        size_t rp_len;
        u16 count;
        int i, err;
@@ -143,10 +148,9 @@ static int read_index_list(struct sock *sk)
        put_unaligned_le16(count, &rp->num_controllers);
 
        i = 0;
-       list_for_each(p, &hci_dev_list) {
-               struct hci_dev *d = list_entry(p, struct hci_dev, list);
-
-               hci_del_off_timer(d);
+       list_for_each_entry(d, &hci_dev_list, list) {
+               if (test_and_clear_bit(HCI_AUTO_OFF, &d->flags))
+                       cancel_delayed_work(&d->power_off);
 
                if (test_bit(HCI_SETUP, &d->flags))
                        continue;
@@ -176,7 +180,8 @@ static int read_controller_info(struct sock *sk, u16 index)
        if (!hdev)
                return cmd_status(sk, index, MGMT_OP_READ_INFO, ENODEV);
 
-       hci_del_off_timer(hdev);
+       if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
+               cancel_delayed_work_sync(&hdev->power_off);
 
        hci_dev_lock_bh(hdev);
 
@@ -221,7 +226,8 @@ static void mgmt_pending_free(struct pending_cmd *cmd)
 }
 
 static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
-                                               u16 index, void *data, u16 len)
+                                                       struct hci_dev *hdev,
+                                                       void *data, u16 len)
 {
        struct pending_cmd *cmd;
 
@@ -230,7 +236,7 @@ static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
                return NULL;
 
        cmd->opcode = opcode;
-       cmd->index = index;
+       cmd->index = hdev->id;
 
        cmd->param = kmalloc(len, GFP_ATOMIC);
        if (!cmd->param) {
@@ -244,48 +250,36 @@ static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
        cmd->sk = sk;
        sock_hold(sk);
 
-       list_add(&cmd->list, &cmd_list);
+       list_add(&cmd->list, &hdev->mgmt_pending);
 
        return cmd;
 }
 
-static void mgmt_pending_foreach(u16 opcode, int index,
+static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
                                void (*cb)(struct pending_cmd *cmd, void *data),
                                void *data)
 {
        struct list_head *p, *n;
 
-       list_for_each_safe(p, n, &cmd_list) {
+       list_for_each_safe(p, n, &hdev->mgmt_pending) {
                struct pending_cmd *cmd;
 
                cmd = list_entry(p, struct pending_cmd, list);
 
-               if (cmd->opcode != opcode)
-                       continue;
-
-               if (index >= 0 && cmd->index != index)
+               if (opcode > 0 && cmd->opcode != opcode)
                        continue;
 
                cb(cmd, data);
        }
 }
 
-static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
+static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
 {
-       struct list_head *p;
-
-       list_for_each(p, &cmd_list) {
-               struct pending_cmd *cmd;
-
-               cmd = list_entry(p, struct pending_cmd, list);
-
-               if (cmd->opcode != opcode)
-                       continue;
-
-               if (index >= 0 && cmd->index != index)
-                       continue;
+       struct pending_cmd *cmd;
 
-               return cmd;
+       list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
+               if (cmd->opcode == opcode)
+                       return cmd;
        }
 
        return NULL;
@@ -323,12 +317,12 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
                goto failed;
        }
 
-       if (mgmt_pending_find(MGMT_OP_SET_POWERED, index)) {
+       if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
                err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY);
                goto failed;
        }
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, index, data, len);
+       cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
@@ -337,7 +331,7 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
        if (cp->val)
                queue_work(hdev->workqueue, &hdev->power_on);
        else
-               queue_work(hdev->workqueue, &hdev->power_off);
+               queue_work(hdev->workqueue, &hdev->power_off.work);
 
        err = 0;
 
@@ -350,7 +344,7 @@ failed:
 static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
                                                                        u16 len)
 {
-       struct mgmt_mode *cp;
+       struct mgmt_cp_set_discoverable *cp;
        struct hci_dev *hdev;
        struct pending_cmd *cmd;
        u8 scan;
@@ -374,8 +368,8 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
                goto failed;
        }
 
-       if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
-                       mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
+       if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
+                       mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
                err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY);
                goto failed;
        }
@@ -386,7 +380,7 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
                goto failed;
        }
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, index, data, len);
+       cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
@@ -396,11 +390,16 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
 
        if (cp->val)
                scan |= SCAN_INQUIRY;
+       else
+               cancel_delayed_work(&hdev->discov_off);
 
        err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
        if (err < 0)
                mgmt_pending_remove(cmd);
 
+       if (cp->val)
+               hdev->discov_timeout = get_unaligned_le16(&cp->timeout);
+
 failed:
        hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
@@ -435,8 +434,8 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
                goto failed;
        }
 
-       if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
-                       mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
+       if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
+                       mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
                err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY);
                goto failed;
        }
@@ -446,7 +445,7 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
                goto failed;
        }
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, index, data, len);
+       cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
@@ -468,8 +467,8 @@ failed:
        return err;
 }
 
-static int mgmt_event(u16 event, u16 index, void *data, u16 data_len,
-                                                       struct sock *skip_sk)
+static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
+                                       u16 data_len, struct sock *skip_sk)
 {
        struct sk_buff *skb;
        struct mgmt_hdr *hdr;
@@ -482,7 +481,10 @@ static int mgmt_event(u16 event, u16 index, void *data, u16 data_len,
 
        hdr = (void *) skb_put(skb, sizeof(*hdr));
        hdr->opcode = cpu_to_le16(event);
-       hdr->index = cpu_to_le16(index);
+       if (hdev)
+               hdr->index = cpu_to_le16(hdev->id);
+       else
+               hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
        hdr->len = cpu_to_le16(data_len);
 
        if (data)
@@ -534,7 +536,7 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
 
        ev.val = cp->val;
 
-       err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
+       err = mgmt_event(MGMT_EV_PAIRABLE, hdev, &ev, sizeof(ev), sk);
 
 failed:
        hci_dev_unlock_bh(hdev);
@@ -587,7 +589,7 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
        u16 eir_len = 0;
        u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
        int i, truncated = 0;
-       struct list_head *p;
+       struct bt_uuid *uuid;
        size_t name_len;
 
        name_len = strlen(hdev->dev_name);
@@ -612,8 +614,7 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
        memset(uuid16_list, 0, sizeof(uuid16_list));
 
        /* Group all UUID16 types */
-       list_for_each(p, &hdev->uuids) {
-               struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
+       list_for_each_entry(uuid, &hdev->uuids, list) {
                u16 uuid16;
 
                uuid16 = get_uuid16(uuid->uuid);
@@ -689,14 +690,11 @@ static int update_eir(struct hci_dev *hdev)
 
 static u8 get_service_classes(struct hci_dev *hdev)
 {
-       struct list_head *p;
+       struct bt_uuid *uuid;
        u8 val = 0;
 
-       list_for_each(p, &hdev->uuids) {
-               struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
-
+       list_for_each_entry(uuid, &hdev->uuids, list)
                val |= uuid->svc_hint;
-       }
 
        return val;
 }
@@ -895,6 +893,9 @@ static int set_service_cache(struct sock *sk, u16 index,  unsigned char *data,
        if (err == 0)
                err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
                                                                        0);
+       else
+               cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, -err);
+
 
        hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
@@ -902,30 +903,32 @@ static int set_service_cache(struct sock *sk, u16 index,  unsigned char *data,
        return err;
 }
 
-static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
+static int load_link_keys(struct sock *sk, u16 index, unsigned char *data,
+                                                               u16 len)
 {
        struct hci_dev *hdev;
-       struct mgmt_cp_load_keys *cp;
+       struct mgmt_cp_load_link_keys *cp;
        u16 key_count, expected_len;
        int i;
 
        cp = (void *) data;
 
        if (len < sizeof(*cp))
-               return -EINVAL;
+               return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, EINVAL);
 
        key_count = get_unaligned_le16(&cp->key_count);
 
-       expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
+       expected_len = sizeof(*cp) + key_count *
+                                       sizeof(struct mgmt_link_key_info);
        if (expected_len != len) {
-               BT_ERR("load_keys: expected %u bytes, got %u bytes",
+               BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
                                                        len, expected_len);
-               return -EINVAL;
+               return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, EINVAL);
        }
 
        hdev = hci_dev_get(index);
        if (!hdev)
-               return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, ENODEV);
+               return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, ENODEV);
 
        BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
                                                                key_count);
@@ -942,7 +945,7 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
                clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
 
        for (i = 0; i < key_count; i++) {
-               struct mgmt_key_info *key = &cp->keys[i];
+               struct mgmt_link_key_info *key = &cp->keys[i];
 
                hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
                                                                key->pin_len);
@@ -954,27 +957,28 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
        return 0;
 }
 
-static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
+static int remove_keys(struct sock *sk, u16 index, unsigned char *data,
+                                                               u16 len)
 {
        struct hci_dev *hdev;
-       struct mgmt_cp_remove_key *cp;
+       struct mgmt_cp_remove_keys *cp;
        struct hci_conn *conn;
        int err;
 
        cp = (void *) data;
 
        if (len != sizeof(*cp))
-               return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, EINVAL);
+               return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, EINVAL);
 
        hdev = hci_dev_get(index);
        if (!hdev)
-               return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
+               return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, ENODEV);
 
        hci_dev_lock_bh(hdev);
 
        err = hci_remove_link_key(hdev, &cp->bdaddr);
        if (err < 0) {
-               err = cmd_status(sk, index, MGMT_OP_REMOVE_KEY, -err);
+               err = cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, -err);
                goto unlock;
        }
 
@@ -1026,7 +1030,7 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
                goto failed;
        }
 
-       if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
+       if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
                err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
                goto failed;
        }
@@ -1040,7 +1044,7 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
                goto failed;
        }
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
+       cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
@@ -1060,10 +1064,23 @@ failed:
        return err;
 }
 
+static u8 link_to_mgmt(u8 link_type)
+{
+       switch (link_type) {
+       case LE_LINK:
+               return MGMT_ADDR_LE;
+       case ACL_LINK:
+               return MGMT_ADDR_BREDR;
+       default:
+               return MGMT_ADDR_INVALID;
+       }
+}
+
 static int get_connections(struct sock *sk, u16 index)
 {
        struct mgmt_rp_get_connections *rp;
        struct hci_dev *hdev;
+       struct hci_conn *c;
        struct list_head *p;
        size_t rp_len;
        u16 count;
@@ -1082,7 +1099,7 @@ static int get_connections(struct sock *sk, u16 index)
                count++;
        }
 
-       rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
+       rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
        rp = kmalloc(rp_len, GFP_ATOMIC);
        if (!rp) {
                err = -ENOMEM;
@@ -1092,12 +1109,17 @@ static int get_connections(struct sock *sk, u16 index)
        put_unaligned_le16(count, &rp->conn_count);
 
        i = 0;
-       list_for_each(p, &hdev->conn_hash.list) {
-               struct hci_conn *c = list_entry(p, struct hci_conn, list);
-
-               bacpy(&rp->conn[i++], &c->dst);
+       list_for_each_entry(c, &hdev->conn_hash.list, list) {
+               bacpy(&rp->addr[i].bdaddr, &c->dst);
+               rp->addr[i].type = link_to_mgmt(c->type);
+               if (rp->addr[i].type == MGMT_ADDR_INVALID)
+                       continue;
+               i++;
        }
 
+       /* Recalculate length in case of filtered SCO connections, etc */
+       rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
+
        err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
 
 unlock:
@@ -1113,7 +1135,7 @@ static int send_pin_code_neg_reply(struct sock *sk, u16 index,
        struct pending_cmd *cmd;
        int err;
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index, cp,
+       cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
                                                                sizeof(*cp));
        if (!cmd)
                return -ENOMEM;
@@ -1174,7 +1196,7 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
                goto failed;
        }
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
+       cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
@@ -1265,19 +1287,12 @@ static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
 static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
 {
        struct hci_dev *hdev = conn->hdev;
-       struct list_head *p;
-
-       list_for_each(p, &cmd_list) {
-               struct pending_cmd *cmd;
-
-               cmd = list_entry(p, struct pending_cmd, list);
+       struct pending_cmd *cmd;
 
+       list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
                if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
                        continue;
 
-               if (cmd->index != hdev->id)
-                       continue;
-
                if (cmd->user_data != conn)
                        continue;
 
@@ -1310,16 +1325,19 @@ static void pairing_complete(struct pending_cmd *cmd, u8 status)
 static void pairing_complete_cb(struct hci_conn *conn, u8 status)
 {
        struct pending_cmd *cmd;
+       struct hci_dev *hdev = conn->hdev;
 
        BT_DBG("status %u", status);
 
+       hci_dev_lock_bh(hdev);
+
        cmd = find_pairing(conn);
-       if (!cmd) {
+       if (!cmd)
                BT_DBG("Unable to find a pending command");
-               return;
-       }
+       else
+               pairing_complete(cmd, status);
 
-       pairing_complete(cmd, status);
+       hci_dev_unlock_bh(hdev);
 }
 
 static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
@@ -1370,7 +1388,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
                goto unlock;
        }
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
+       cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                hci_conn_put(conn);
@@ -1432,7 +1450,7 @@ static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
                goto failed;
        }
 
-       cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
+       cmd = mgmt_pending_add(sk, mgmt_op, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
@@ -1469,7 +1487,7 @@ static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
 
        hci_dev_lock_bh(hdev);
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
+       cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
@@ -1515,12 +1533,12 @@ static int read_local_oob_data(struct sock *sk, u16 index)
                goto unlock;
        }
 
-       if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
+       if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
                err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
                goto unlock;
        }
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
+       cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
        if (!cmd) {
                err = -ENOMEM;
                goto unlock;
@@ -1607,8 +1625,6 @@ static int remove_remote_oob_data(struct sock *sk, u16 index,
 
 static int start_discovery(struct sock *sk, u16 index)
 {
-       u8 lap[3] = { 0x33, 0x8b, 0x9e };
-       struct hci_cp_inquiry cp;
        struct pending_cmd *cmd;
        struct hci_dev *hdev;
        int err;
@@ -1621,18 +1637,18 @@ static int start_discovery(struct sock *sk, u16 index)
 
        hci_dev_lock_bh(hdev);
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
+       if (!test_bit(HCI_UP, &hdev->flags)) {
+               err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENETDOWN);
+               goto failed;
+       }
+
+       cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
        }
 
-       memset(&cp, 0, sizeof(cp));
-       memcpy(&cp.lap, lap, 3);
-       cp.length  = 0x08;
-       cp.num_rsp = 0x00;
-
-       err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
+       err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
        if (err < 0)
                mgmt_pending_remove(cmd);
 
@@ -1657,13 +1673,13 @@ static int stop_discovery(struct sock *sk, u16 index)
 
        hci_dev_lock_bh(hdev);
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, NULL, 0);
+       cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
        }
 
-       err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
+       err = hci_cancel_inquiry(hdev);
        if (err < 0)
                mgmt_pending_remove(cmd);
 
@@ -1678,7 +1694,6 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data,
                                                                u16 len)
 {
        struct hci_dev *hdev;
-       struct pending_cmd *cmd;
        struct mgmt_cp_block_device *cp = (void *) data;
        int err;
 
@@ -1695,23 +1710,13 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data,
 
        hci_dev_lock_bh(hdev);
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_BLOCK_DEVICE, index, NULL, 0);
-       if (!cmd) {
-               err = -ENOMEM;
-               goto failed;
-       }
-
        err = hci_blacklist_add(hdev, &cp->bdaddr);
-
        if (err < 0)
                err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, -err);
        else
                err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
                                                        NULL, 0);
 
-       mgmt_pending_remove(cmd);
-
-failed:
        hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
 
@@ -1722,7 +1727,6 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
                                                                u16 len)
 {
        struct hci_dev *hdev;
-       struct pending_cmd *cmd;
        struct mgmt_cp_unblock_device *cp = (void *) data;
        int err;
 
@@ -1739,12 +1743,6 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
 
        hci_dev_lock_bh(hdev);
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_UNBLOCK_DEVICE, index, NULL, 0);
-       if (!cmd) {
-               err = -ENOMEM;
-               goto failed;
-       }
-
        err = hci_blacklist_del(hdev, &cp->bdaddr);
 
        if (err < 0)
@@ -1753,9 +1751,6 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
                err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
                                                                NULL, 0);
 
-       mgmt_pending_remove(cmd);
-
-failed:
        hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
 
@@ -1883,11 +1878,11 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
        case MGMT_OP_SET_SERVICE_CACHE:
                err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
                break;
-       case MGMT_OP_LOAD_KEYS:
-               err = load_keys(sk, index, buf + sizeof(*hdr), len);
+       case MGMT_OP_LOAD_LINK_KEYS:
+               err = load_link_keys(sk, index, buf + sizeof(*hdr), len);
                break;
-       case MGMT_OP_REMOVE_KEY:
-               err = remove_key(sk, index, buf + sizeof(*hdr), len);
+       case MGMT_OP_REMOVE_KEYS:
+               err = remove_keys(sk, index, buf + sizeof(*hdr), len);
                break;
        case MGMT_OP_DISCONNECT:
                err = disconnect(sk, index, buf + sizeof(*hdr), len);
@@ -1958,14 +1953,26 @@ done:
        return err;
 }
 
-int mgmt_index_added(u16 index)
+static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
 {
-       return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
+       u8 *status = data;
+
+       cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
+       mgmt_pending_remove(cmd);
 }
 
-int mgmt_index_removed(u16 index)
+int mgmt_index_added(struct hci_dev *hdev)
 {
-       return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
+       return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
+}
+
+int mgmt_index_removed(struct hci_dev *hdev)
+{
+       u8 status = ENODEV;
+
+       mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
+
+       return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
 }
 
 struct cmd_lookup {
@@ -1993,17 +2000,22 @@ static void mode_rsp(struct pending_cmd *cmd, void *data)
        mgmt_pending_free(cmd);
 }
 
-int mgmt_powered(u16 index, u8 powered)
+int mgmt_powered(struct hci_dev *hdev, u8 powered)
 {
        struct mgmt_mode ev;
        struct cmd_lookup match = { powered, NULL };
        int ret;
 
-       mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
+       mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, mode_rsp, &match);
+
+       if (!powered) {
+               u8 status = ENETDOWN;
+               mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
+       }
 
        ev.val = powered;
 
-       ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
+       ret = mgmt_event(MGMT_EV_POWERED, hdev, &ev, sizeof(ev), match.sk);
 
        if (match.sk)
                sock_put(match.sk);
@@ -2011,17 +2023,17 @@ int mgmt_powered(u16 index, u8 powered)
        return ret;
 }
 
-int mgmt_discoverable(u16 index, u8 discoverable)
+int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
 {
        struct mgmt_mode ev;
        struct cmd_lookup match = { discoverable, NULL };
        int ret;
 
-       mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
+       mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, mode_rsp, &match);
 
        ev.val = discoverable;
 
-       ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
+       ret = mgmt_event(MGMT_EV_DISCOVERABLE, hdev, &ev, sizeof(ev),
                                                                match.sk);
 
        if (match.sk)
@@ -2030,17 +2042,17 @@ int mgmt_discoverable(u16 index, u8 discoverable)
        return ret;
 }
 
-int mgmt_connectable(u16 index, u8 connectable)
+int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
 {
        struct mgmt_mode ev;
        struct cmd_lookup match = { connectable, NULL };
        int ret;
 
-       mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
+       mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, mode_rsp, &match);
 
        ev.val = connectable;
 
-       ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
+       ret = mgmt_event(MGMT_EV_CONNECTABLE, hdev, &ev, sizeof(ev), match.sk);
 
        if (match.sk)
                sock_put(match.sk);
@@ -2048,9 +2060,23 @@ int mgmt_connectable(u16 index, u8 connectable)
        return ret;
 }
 
-int mgmt_new_key(u16 index, struct link_key *key, u8 persistent)
+int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
+{
+       if (scan & SCAN_PAGE)
+               mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
+                                               cmd_status_rsp, &status);
+
+       if (scan & SCAN_INQUIRY)
+               mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
+                                               cmd_status_rsp, &status);
+
+       return 0;
+}
+
+int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
+                                                               u8 persistent)
 {
-       struct mgmt_ev_new_key ev;
+       struct mgmt_ev_new_link_key ev;
 
        memset(&ev, 0, sizeof(ev));
 
@@ -2060,17 +2086,17 @@ int mgmt_new_key(u16 index, struct link_key *key, u8 persistent)
        memcpy(ev.key.val, key->val, 16);
        ev.key.pin_len = key->pin_len;
 
-       return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL);
+       return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
 }
 
-int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 link_type)
+int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type)
 {
-       struct mgmt_ev_connected ev;
+       struct mgmt_addr_info ev;
 
        bacpy(&ev.bdaddr, bdaddr);
-       ev.link_type = link_type;
+       ev.type = link_to_mgmt(link_type);
 
-       return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
+       return mgmt_event(MGMT_EV_CONNECTED, hdev, &ev, sizeof(ev), NULL);
 }
 
 static void disconnect_rsp(struct pending_cmd *cmd, void *data)
@@ -2089,17 +2115,18 @@ static void disconnect_rsp(struct pending_cmd *cmd, void *data)
        mgmt_pending_remove(cmd);
 }
 
-int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
+int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
 {
-       struct mgmt_ev_disconnected ev;
+       struct mgmt_addr_info ev;
        struct sock *sk = NULL;
        int err;
 
-       mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
+       mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
 
        bacpy(&ev.bdaddr, bdaddr);
+       ev.type = link_to_mgmt(type);
 
-       err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
+       err = mgmt_event(MGMT_EV_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
 
        if (sk)
                sock_put(sk);
@@ -2107,57 +2134,60 @@ int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
        return err;
 }
 
-int mgmt_disconnect_failed(u16 index)
+int mgmt_disconnect_failed(struct hci_dev *hdev)
 {
        struct pending_cmd *cmd;
        int err;
 
-       cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
+       cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
        if (!cmd)
                return -ENOENT;
 
-       err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
+       err = cmd_status(cmd->sk, hdev->id, MGMT_OP_DISCONNECT, EIO);
 
        mgmt_pending_remove(cmd);
 
        return err;
 }
 
-int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
+int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type,
+                                                               u8 status)
 {
        struct mgmt_ev_connect_failed ev;
 
-       bacpy(&ev.bdaddr, bdaddr);
+       bacpy(&ev.addr.bdaddr, bdaddr);
+       ev.addr.type = link_to_mgmt(type);
        ev.status = status;
 
-       return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
+       return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
 }
 
-int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure)
+int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
 {
        struct mgmt_ev_pin_code_request ev;
 
        bacpy(&ev.bdaddr, bdaddr);
        ev.secure = secure;
 
-       return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
+       return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
                                                                        NULL);
 }
 
-int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
+int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                                               u8 status)
 {
        struct pending_cmd *cmd;
        struct mgmt_rp_pin_code_reply rp;
        int err;
 
-       cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
+       cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
        if (!cmd)
                return -ENOENT;
 
        bacpy(&rp.bdaddr, bdaddr);
        rp.status = status;
 
-       err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
+       err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
                                                                sizeof(rp));
 
        mgmt_pending_remove(cmd);
@@ -2165,20 +2195,21 @@ int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
        return err;
 }
 
-int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
+int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                                               u8 status)
 {
        struct pending_cmd *cmd;
        struct mgmt_rp_pin_code_reply rp;
        int err;
 
-       cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
+       cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
        if (!cmd)
                return -ENOENT;
 
        bacpy(&rp.bdaddr, bdaddr);
        rp.status = status;
 
-       err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
+       err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
                                                                sizeof(rp));
 
        mgmt_pending_remove(cmd);
@@ -2186,97 +2217,93 @@ int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
        return err;
 }
 
-int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value,
-                                                       u8 confirm_hint)
+int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                               __le32 value, u8 confirm_hint)
 {
        struct mgmt_ev_user_confirm_request ev;
 
-       BT_DBG("hci%u", index);
+       BT_DBG("%s", hdev->name);
 
        bacpy(&ev.bdaddr, bdaddr);
        ev.confirm_hint = confirm_hint;
        put_unaligned_le32(value, &ev.value);
 
-       return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
+       return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
                                                                        NULL);
 }
 
-static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
-                                                               u8 opcode)
+static int confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                                       u8 status, u8 opcode)
 {
        struct pending_cmd *cmd;
        struct mgmt_rp_user_confirm_reply rp;
        int err;
 
-       cmd = mgmt_pending_find(opcode, index);
+       cmd = mgmt_pending_find(opcode, hdev);
        if (!cmd)
                return -ENOENT;
 
        bacpy(&rp.bdaddr, bdaddr);
        rp.status = status;
-       err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
+       err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
 
        mgmt_pending_remove(cmd);
 
        return err;
 }
 
-int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
+int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                                               u8 status)
 {
-       return confirm_reply_complete(index, bdaddr, status,
+       return confirm_reply_complete(hdev, bdaddr, status,
                                                MGMT_OP_USER_CONFIRM_REPLY);
 }
 
-int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
+int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
+                                               bdaddr_t *bdaddr, u8 status)
 {
-       return confirm_reply_complete(index, bdaddr, status,
+       return confirm_reply_complete(hdev, bdaddr, status,
                                        MGMT_OP_USER_CONFIRM_NEG_REPLY);
 }
 
-int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
+int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
 {
        struct mgmt_ev_auth_failed ev;
 
        bacpy(&ev.bdaddr, bdaddr);
        ev.status = status;
 
-       return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
+       return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
 }
 
-int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
+int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
 {
        struct pending_cmd *cmd;
-       struct hci_dev *hdev;
        struct mgmt_cp_set_local_name ev;
        int err;
 
        memset(&ev, 0, sizeof(ev));
        memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
 
-       cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
+       cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
        if (!cmd)
                goto send_event;
 
        if (status) {
-               err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
+               err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
+                                                                       EIO);
                goto failed;
        }
 
-       hdev = hci_dev_get(index);
-       if (hdev) {
-               hci_dev_lock_bh(hdev);
-               update_eir(hdev);
-               hci_dev_unlock_bh(hdev);
-               hci_dev_put(hdev);
-       }
+       update_eir(hdev);
 
-       err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
+       err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
                                                                sizeof(ev));
        if (err < 0)
                goto failed;
 
 send_event:
-       err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
+       err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
                                                        cmd ? cmd->sk : NULL);
 
 failed:
@@ -2285,29 +2312,30 @@ failed:
        return err;
 }
 
-int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
-                                                               u8 status)
+int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
+                                               u8 *randomizer, u8 status)
 {
        struct pending_cmd *cmd;
        int err;
 
-       BT_DBG("hci%u status %u", index, status);
+       BT_DBG("%s status %u", hdev->name, status);
 
-       cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
+       cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
        if (!cmd)
                return -ENOENT;
 
        if (status) {
-               err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
-                                                                       EIO);
+               err = cmd_status(cmd->sk, hdev->id,
+                                       MGMT_OP_READ_LOCAL_OOB_DATA, EIO);
        } else {
                struct mgmt_rp_read_local_oob_data rp;
 
                memcpy(rp.hash, hash, sizeof(rp.hash));
                memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
 
-               err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
-                                                       &rp, sizeof(rp));
+               err = cmd_complete(cmd->sk, hdev->id,
+                                               MGMT_OP_READ_LOCAL_OOB_DATA,
+                                               &rp, sizeof(rp));
        }
 
        mgmt_pending_remove(cmd);
@@ -2315,14 +2343,15 @@ int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
        return err;
 }
 
-int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
-                                                               u8 *eir)
+int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type,
+                                       u8 *dev_class, s8 rssi, u8 *eir)
 {
        struct mgmt_ev_device_found ev;
 
        memset(&ev, 0, sizeof(ev));
 
-       bacpy(&ev.bdaddr, bdaddr);
+       bacpy(&ev.addr.bdaddr, bdaddr);
+       ev.addr.type = link_to_mgmt(type);
        ev.rssi = rssi;
 
        if (eir)
@@ -2331,10 +2360,10 @@ int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
        if (dev_class)
                memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
 
-       return mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
+       return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, &ev, sizeof(ev), NULL);
 }
 
-int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name)
+int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name)
 {
        struct mgmt_ev_remote_name ev;
 
@@ -2343,37 +2372,64 @@ int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name)
        bacpy(&ev.bdaddr, bdaddr);
        memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
 
-       return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
+       return mgmt_event(MGMT_EV_REMOTE_NAME, hdev, &ev, sizeof(ev), NULL);
 }
 
-int mgmt_discovering(u16 index, u8 discovering)
+int mgmt_inquiry_failed(struct hci_dev *hdev, u8 status)
 {
-       return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering,
+       struct pending_cmd *cmd;
+       int err;
+
+       cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
+       if (!cmd)
+               return -ENOENT;
+
+       err = cmd_status(cmd->sk, hdev->id, cmd->opcode, status);
+       mgmt_pending_remove(cmd);
+
+       return err;
+}
+
+int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
+{
+       struct pending_cmd *cmd;
+
+       if (discovering)
+               cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
+       else
+               cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
+
+       if (cmd != NULL) {
+               cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0);
+               mgmt_pending_remove(cmd);
+       }
+
+       return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
                                                sizeof(discovering), NULL);
 }
 
-int mgmt_device_blocked(u16 index, bdaddr_t *bdaddr)
+int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
 {
        struct pending_cmd *cmd;
        struct mgmt_ev_device_blocked ev;
 
-       cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, index);
+       cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
 
        bacpy(&ev.bdaddr, bdaddr);
 
-       return mgmt_event(MGMT_EV_DEVICE_BLOCKED, index, &ev, sizeof(ev),
-                                               cmd ? cmd->sk : NULL);
+       return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
+                                                       cmd ? cmd->sk : NULL);
 }
 
-int mgmt_device_unblocked(u16 index, bdaddr_t *bdaddr)
+int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
 {
        struct pending_cmd *cmd;
        struct mgmt_ev_device_unblocked ev;
 
-       cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, index);
+       cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
 
        bacpy(&ev.bdaddr, bdaddr);
 
-       return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, index, &ev, sizeof(ev),
-                                               cmd ? cmd->sk : NULL);
+       return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
+                                                       cmd ? cmd->sk : NULL);
 }
index 4e32e18..8743f36 100644 (file)
@@ -65,7 +65,8 @@ static DEFINE_MUTEX(rfcomm_mutex);
 
 static LIST_HEAD(session_list);
 
-static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len);
+static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len,
+                                                       u32 priority);
 static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci);
 static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci);
 static int rfcomm_queue_disc(struct rfcomm_dlc *d);
@@ -377,13 +378,11 @@ static void rfcomm_dlc_unlink(struct rfcomm_dlc *d)
 static struct rfcomm_dlc *rfcomm_dlc_get(struct rfcomm_session *s, u8 dlci)
 {
        struct rfcomm_dlc *d;
-       struct list_head *p;
 
-       list_for_each(p, &s->dlcs) {
-               d = list_entry(p, struct rfcomm_dlc, list);
+       list_for_each_entry(d, &s->dlcs, list)
                if (d->dlci == dlci)
                        return d;
-       }
+
        return NULL;
 }
 
@@ -749,19 +748,34 @@ void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *d
 }
 
 /* ---- RFCOMM frame sending ---- */
-static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len)
+static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len,
+                                                       u32 priority)
 {
        struct socket *sock = s->sock;
+       struct sock *sk = sock->sk;
        struct kvec iv = { data, len };
        struct msghdr msg;
 
-       BT_DBG("session %p len %d", s, len);
+       BT_DBG("session %p len %d priority %u", s, len, priority);
+
+       if (sk->sk_priority != priority) {
+               lock_sock(sk);
+               sk->sk_priority = priority;
+               release_sock(sk);
+       }
 
        memset(&msg, 0, sizeof(msg));
 
        return kernel_sendmsg(sock, &msg, &iv, 1, len);
 }
 
+static int rfcomm_send_cmd(struct rfcomm_session *s, struct rfcomm_cmd *cmd)
+{
+       BT_DBG("%p cmd %u", s, cmd->ctrl);
+
+       return rfcomm_send_frame(s, (void *) cmd, sizeof(*cmd), HCI_PRIO_MAX);
+}
+
 static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci)
 {
        struct rfcomm_cmd cmd;
@@ -773,7 +787,7 @@ static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci)
        cmd.len  = __len8(0);
        cmd.fcs  = __fcs2((u8 *) &cmd);
 
-       return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
+       return rfcomm_send_cmd(s, &cmd);
 }
 
 static int rfcomm_send_ua(struct rfcomm_session *s, u8 dlci)
@@ -787,7 +801,7 @@ static int rfcomm_send_ua(struct rfcomm_session *s, u8 dlci)
        cmd.len  = __len8(0);
        cmd.fcs  = __fcs2((u8 *) &cmd);
 
-       return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
+       return rfcomm_send_cmd(s, &cmd);
 }
 
 static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci)
@@ -801,7 +815,7 @@ static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci)
        cmd.len  = __len8(0);
        cmd.fcs  = __fcs2((u8 *) &cmd);
 
-       return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
+       return rfcomm_send_cmd(s, &cmd);
 }
 
 static int rfcomm_queue_disc(struct rfcomm_dlc *d)
@@ -815,6 +829,8 @@ static int rfcomm_queue_disc(struct rfcomm_dlc *d)
        if (!skb)
                return -ENOMEM;
 
+       skb->priority = HCI_PRIO_MAX;
+
        cmd = (void *) __skb_put(skb, sizeof(*cmd));
        cmd->addr = d->addr;
        cmd->ctrl = __ctrl(RFCOMM_DISC, 1);
@@ -837,7 +853,7 @@ static int rfcomm_send_dm(struct rfcomm_session *s, u8 dlci)
        cmd.len  = __len8(0);
        cmd.fcs  = __fcs2((u8 *) &cmd);
 
-       return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
+       return rfcomm_send_cmd(s, &cmd);
 }
 
 static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type)
@@ -862,7 +878,7 @@ static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type)
 
        *ptr = __fcs(buf); ptr++;
 
-       return rfcomm_send_frame(s, buf, ptr - buf);
+       return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
 }
 
 static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d)
@@ -904,7 +920,7 @@ static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d
 
        *ptr = __fcs(buf); ptr++;
 
-       return rfcomm_send_frame(s, buf, ptr - buf);
+       return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
 }
 
 int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci,
@@ -942,7 +958,7 @@ int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci,
 
        *ptr = __fcs(buf); ptr++;
 
-       return rfcomm_send_frame(s, buf, ptr - buf);
+       return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
 }
 
 static int rfcomm_send_rls(struct rfcomm_session *s, int cr, u8 dlci, u8 status)
@@ -969,7 +985,7 @@ static int rfcomm_send_rls(struct rfcomm_session *s, int cr, u8 dlci, u8 status)
 
        *ptr = __fcs(buf); ptr++;
 
-       return rfcomm_send_frame(s, buf, ptr - buf);
+       return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
 }
 
 static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig)
@@ -996,7 +1012,7 @@ static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig
 
        *ptr = __fcs(buf); ptr++;
 
-       return rfcomm_send_frame(s, buf, ptr - buf);
+       return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
 }
 
 static int rfcomm_send_fcoff(struct rfcomm_session *s, int cr)
@@ -1018,7 +1034,7 @@ static int rfcomm_send_fcoff(struct rfcomm_session *s, int cr)
 
        *ptr = __fcs(buf); ptr++;
 
-       return rfcomm_send_frame(s, buf, ptr - buf);
+       return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
 }
 
 static int rfcomm_send_fcon(struct rfcomm_session *s, int cr)
@@ -1040,7 +1056,7 @@ static int rfcomm_send_fcon(struct rfcomm_session *s, int cr)
 
        *ptr = __fcs(buf); ptr++;
 
-       return rfcomm_send_frame(s, buf, ptr - buf);
+       return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
 }
 
 static int rfcomm_send_test(struct rfcomm_session *s, int cr, u8 *pattern, int len)
@@ -1091,7 +1107,7 @@ static int rfcomm_send_credits(struct rfcomm_session *s, u8 addr, u8 credits)
 
        *ptr = __fcs(buf); ptr++;
 
-       return rfcomm_send_frame(s, buf, ptr - buf);
+       return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
 }
 
 static void rfcomm_make_uih(struct sk_buff *skb, u8 addr)
@@ -1769,7 +1785,8 @@ static inline int rfcomm_process_tx(struct rfcomm_dlc *d)
                return skb_queue_len(&d->tx_queue);
 
        while (d->tx_credits && (skb = skb_dequeue(&d->tx_queue))) {
-               err = rfcomm_send_frame(d->session, skb->data, skb->len);
+               err = rfcomm_send_frame(d->session, skb->data, skb->len,
+                                                       skb->priority);
                if (err < 0) {
                        skb_queue_head(&d->tx_queue, skb);
                        break;
@@ -2120,15 +2137,13 @@ static struct hci_cb rfcomm_cb = {
 static int rfcomm_dlc_debugfs_show(struct seq_file *f, void *x)
 {
        struct rfcomm_session *s;
-       struct list_head *pp, *p;
 
        rfcomm_lock();
 
-       list_for_each(p, &session_list) {
-               s = list_entry(p, struct rfcomm_session, list);
-               list_for_each(pp, &s->dlcs) {
+       list_for_each_entry(s, &session_list, list) {
+               struct rfcomm_dlc *d;
+               list_for_each_entry(d, &s->dlcs, list) {
                        struct sock *sk = s->sock->sk;
-                       struct rfcomm_dlc *d = list_entry(pp, struct rfcomm_dlc, list);
 
                        seq_printf(f, "%s %s %ld %d %d %d %d\n",
                                                batostr(&bt_sk(sk)->src),
index 5417f61..aea2bdd 100644 (file)
@@ -600,6 +600,8 @@ static int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
                        break;
                }
 
+               skb->priority = sk->sk_priority;
+
                err = rfcomm_dlc_send(d, skb);
                if (err < 0) {
                        kfree_skb(skb);
index c258796..fa8f4de 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/capability.h>
 #include <linux/slab.h>
 #include <linux/skbuff.h>
+#include <linux/workqueue.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
@@ -65,7 +66,7 @@ struct rfcomm_dev {
        struct rfcomm_dlc       *dlc;
        struct tty_struct       *tty;
        wait_queue_head_t       wait;
-       struct tasklet_struct   wakeup_task;
+       struct work_struct      wakeup_task;
 
        struct device           *tty_dev;
 
@@ -81,7 +82,7 @@ static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb);
 static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err);
 static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig);
 
-static void rfcomm_tty_wakeup(unsigned long arg);
+static void rfcomm_tty_wakeup(struct work_struct *work);
 
 /* ---- Device functions ---- */
 static void rfcomm_dev_destruct(struct rfcomm_dev *dev)
@@ -133,13 +134,10 @@ static inline void rfcomm_dev_put(struct rfcomm_dev *dev)
 static struct rfcomm_dev *__rfcomm_dev_get(int id)
 {
        struct rfcomm_dev *dev;
-       struct list_head  *p;
 
-       list_for_each(p, &rfcomm_dev_list) {
-               dev = list_entry(p, struct rfcomm_dev, list);
+       list_for_each_entry(dev, &rfcomm_dev_list, list)
                if (dev->id == id)
                        return dev;
-       }
 
        return NULL;
 }
@@ -197,7 +195,7 @@ static DEVICE_ATTR(channel, S_IRUGO, show_channel, NULL);
 
 static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
 {
-       struct rfcomm_dev *dev;
+       struct rfcomm_dev *dev, *entry;
        struct list_head *head = &rfcomm_dev_list, *p;
        int err = 0;
 
@@ -212,8 +210,8 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
        if (req->dev_id < 0) {
                dev->id = 0;
 
-               list_for_each(p, &rfcomm_dev_list) {
-                       if (list_entry(p, struct rfcomm_dev, list)->id != dev->id)
+               list_for_each_entry(entry, &rfcomm_dev_list, list) {
+                       if (entry->id != dev->id)
                                break;
 
                        dev->id++;
@@ -222,9 +220,7 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
        } else {
                dev->id = req->dev_id;
 
-               list_for_each(p, &rfcomm_dev_list) {
-                       struct rfcomm_dev *entry = list_entry(p, struct rfcomm_dev, list);
-
+               list_for_each_entry(entry, &rfcomm_dev_list, list) {
                        if (entry->id == dev->id) {
                                err = -EADDRINUSE;
                                goto out;
@@ -257,7 +253,7 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
        atomic_set(&dev->opened, 0);
 
        init_waitqueue_head(&dev->wait);
-       tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev);
+       INIT_WORK(&dev->wakeup_task, rfcomm_tty_wakeup);
 
        skb_queue_head_init(&dev->pending);
 
@@ -351,7 +347,7 @@ static void rfcomm_wfree(struct sk_buff *skb)
        struct rfcomm_dev *dev = (void *) skb->sk;
        atomic_sub(skb->truesize, &dev->wmem_alloc);
        if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags))
-               tasklet_schedule(&dev->wakeup_task);
+               queue_work(system_nrt_wq, &dev->wakeup_task);
        rfcomm_dev_put(dev);
 }
 
@@ -455,9 +451,9 @@ static int rfcomm_release_dev(void __user *arg)
 
 static int rfcomm_get_dev_list(void __user *arg)
 {
+       struct rfcomm_dev *dev;
        struct rfcomm_dev_list_req *dl;
        struct rfcomm_dev_info *di;
-       struct list_head *p;
        int n = 0, size, err;
        u16 dev_num;
 
@@ -479,8 +475,7 @@ static int rfcomm_get_dev_list(void __user *arg)
 
        read_lock_bh(&rfcomm_dev_lock);
 
-       list_for_each(p, &rfcomm_dev_list) {
-               struct rfcomm_dev *dev = list_entry(p, struct rfcomm_dev, list);
+       list_for_each_entry(dev, &rfcomm_dev_list, list) {
                if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags))
                        continue;
                (di + n)->id      = dev->id;
@@ -635,9 +630,10 @@ static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig)
 }
 
 /* ---- TTY functions ---- */
-static void rfcomm_tty_wakeup(unsigned long arg)
+static void rfcomm_tty_wakeup(struct work_struct *work)
 {
-       struct rfcomm_dev *dev = (void *) arg;
+       struct rfcomm_dev *dev = container_of(work, struct rfcomm_dev,
+                                                               wakeup_task);
        struct tty_struct *tty = dev->tty;
        if (!tty)
                return;
@@ -762,7 +758,7 @@ static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
                rfcomm_dlc_close(dev->dlc, 0);
 
                clear_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
-               tasklet_kill(&dev->wakeup_task);
+               cancel_work_sync(&dev->wakeup_task);
 
                rfcomm_dlc_lock(dev->dlc);
                tty->driver_data = NULL;
@@ -1155,9 +1151,11 @@ static const struct tty_operations rfcomm_ops = {
 
 int __init rfcomm_init_ttys(void)
 {
+       int error;
+
        rfcomm_tty_driver = alloc_tty_driver(RFCOMM_TTY_PORTS);
        if (!rfcomm_tty_driver)
-               return -1;
+               return -ENOMEM;
 
        rfcomm_tty_driver->owner        = THIS_MODULE;
        rfcomm_tty_driver->driver_name  = "rfcomm";
@@ -1172,10 +1170,11 @@ int __init rfcomm_init_ttys(void)
        rfcomm_tty_driver->init_termios.c_lflag &= ~ICANON;
        tty_set_operations(rfcomm_tty_driver, &rfcomm_ops);
 
-       if (tty_register_driver(rfcomm_tty_driver)) {
+       error = tty_register_driver(rfcomm_tty_driver);
+       if (error) {
                BT_ERR("Can't register RFCOMM TTY driver");
                put_tty_driver(rfcomm_tty_driver);
-               return -1;
+               return error;
        }
 
        BT_INFO("RFCOMM TTY layer initialized");
index 759b635..94e94ca 100644 (file)
@@ -181,7 +181,8 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
        if (!skb)
                return;
 
-       hci_send_acl(conn->hcon, skb, 0);
+       skb->priority = HCI_PRIO_MAX;
+       hci_send_acl(conn->hchan, skb, 0);
 
        mod_timer(&conn->security_timer, jiffies +
                                        msecs_to_jiffies(SMP_TIMEOUT));
index feb77ea..a3754ac 100644 (file)
@@ -186,7 +186,8 @@ static void br_getinfo(struct net_device *dev, struct ethtool_drvinfo *info)
        strcpy(info->bus_info, "N/A");
 }
 
-static u32 br_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t br_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        struct net_bridge *br = netdev_priv(dev);
 
@@ -341,10 +342,10 @@ void br_dev_setup(struct net_device *dev)
        dev->priv_flags = IFF_EBRIDGE;
 
        dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
-                       NETIF_F_GSO_MASK | NETIF_F_NO_CSUM | NETIF_F_LLTX |
+                       NETIF_F_GSO_MASK | NETIF_F_HW_CSUM | NETIF_F_LLTX |
                        NETIF_F_NETNS_LOCAL | NETIF_F_HW_VLAN_TX;
        dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
-                          NETIF_F_GSO_MASK | NETIF_F_NO_CSUM |
+                          NETIF_F_GSO_MASK | NETIF_F_HW_CSUM |
                           NETIF_F_HW_VLAN_TX;
 
        br->dev = dev;
index c8e7861..973813e 100644 (file)
@@ -556,7 +556,7 @@ skip:
        return skb->len;
 }
 
-/* Create new static fdb entry */
+/* Update (create or replace) forwarding database entry */
 static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr,
                         __u16 state, __u16 flags)
 {
@@ -575,16 +575,21 @@ static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr,
        } else {
                if (flags & NLM_F_EXCL)
                        return -EEXIST;
+       }
+
+       if (fdb_to_nud(fdb) != state) {
+               if (state & NUD_PERMANENT)
+                       fdb->is_local = fdb->is_static = 1;
+               else if (state & NUD_NOARP) {
+                       fdb->is_local = 0;
+                       fdb->is_static = 1;
+               } else
+                       fdb->is_local = fdb->is_static = 0;
 
-               if (flags & NLM_F_REPLACE)
-                       fdb->updated = fdb->used = jiffies;
-               fdb->is_local = fdb->is_static = 0;
+               fdb->updated = fdb->used = jiffies;
+               fdb_notify(fdb, RTM_NEWNEIGH);
        }
 
-       if (state & NUD_PERMANENT)
-               fdb->is_local = fdb->is_static = 1;
-       else if (state & NUD_NOARP)
-               fdb->is_static = 1;
        return 0;
 }
 
@@ -627,6 +632,11 @@ int br_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
                return -EINVAL;
        }
 
+       if (!(ndm->ndm_state & (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE))) {
+               pr_info("bridge: RTM_NEWNEIGH with invalid state %#x\n", ndm->ndm_state);
+               return -EINVAL;
+       }
+
        p = br_port_get_rtnl(dev);
        if (p == NULL) {
                pr_info("bridge: RTM_NEWNEIGH %s not a bridge port\n",
@@ -634,9 +644,15 @@ int br_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
                return -EINVAL;
        }
 
-       spin_lock_bh(&p->br->hash_lock);
-       err = fdb_add_entry(p, addr, ndm->ndm_state, nlh->nlmsg_flags);
-       spin_unlock_bh(&p->br->hash_lock);
+       if (ndm->ndm_flags & NTF_USE) {
+               rcu_read_lock();
+               br_fdb_update(p->br, p, addr);
+               rcu_read_unlock();
+       } else {
+               spin_lock_bh(&p->br->hash_lock);
+               err = fdb_add_entry(p, addr, ndm->ndm_state, nlh->nlmsg_flags);
+               spin_unlock_bh(&p->br->hash_lock);
+       }
 
        return err;
 }
index f603e5b..0a942fb 100644 (file)
@@ -296,10 +296,11 @@ int br_min_mtu(const struct net_bridge *br)
 /*
  * Recomputes features using slave's features
  */
-u32 br_features_recompute(struct net_bridge *br, u32 features)
+netdev_features_t br_features_recompute(struct net_bridge *br,
+       netdev_features_t features)
 {
        struct net_bridge_port *p;
-       u32 mask;
+       netdev_features_t mask;
 
        if (list_empty(&br->port_list))
                return features;
index 995cbe0..7743e0d 100644 (file)
@@ -127,7 +127,7 @@ static struct net_bridge_mdb_entry *br_mdb_ip6_get(
 {
        struct br_ip br_dst;
 
-       ipv6_addr_copy(&br_dst.u.ip6, dst);
+       br_dst.u.ip6 = *dst;
        br_dst.proto = htons(ETH_P_IPV6);
 
        return br_mdb_ip_get(mdb, &br_dst);
@@ -154,7 +154,7 @@ struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br,
                break;
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
        case htons(ETH_P_IPV6):
-               ipv6_addr_copy(&ip.u.ip6, &ipv6_hdr(skb)->daddr);
+               ip.u.ip6 = ipv6_hdr(skb)->daddr;
                break;
 #endif
        default:
@@ -474,7 +474,7 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br,
        mldq->mld_cksum = 0;
        mldq->mld_maxdelay = htons((u16)jiffies_to_msecs(interval));
        mldq->mld_reserved = 0;
-       ipv6_addr_copy(&mldq->mld_mca, group);
+       mldq->mld_mca = *group;
 
        /* checksum */
        mldq->mld_cksum = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
@@ -783,7 +783,7 @@ static int br_ip6_multicast_add_group(struct net_bridge *br,
        if (!ipv6_is_transient_multicast(group))
                return 0;
 
-       ipv6_addr_copy(&br_group.u.ip6, group);
+       br_group.u.ip6 = *group;
        br_group.proto = htons(ETH_P_IPV6);
 
        return br_multicast_add_group(br, port, &br_group);
@@ -1344,7 +1344,7 @@ static void br_ip6_multicast_leave_group(struct net_bridge *br,
        if (!ipv6_is_transient_multicast(group))
                return;
 
-       ipv6_addr_copy(&br_group.u.ip6, group);
+       br_group.u.ip6 = *group;
        br_group.proto = htons(ETH_P_IPV6);
 
        br_multicast_leave_group(br, port, &br_group);
@@ -1501,6 +1501,8 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
 
        __skb_pull(skb2, offset);
        skb_reset_transport_header(skb2);
+       skb_postpull_rcsum(skb2, skb_network_header(skb2),
+                          skb_network_header_len(skb2));
 
        icmp6_type = icmp6_hdr(skb2)->icmp6_type;
 
@@ -1770,7 +1772,7 @@ int br_multicast_toggle(struct net_bridge *br, unsigned long val)
        int err = 0;
        struct net_bridge_mdb_htable *mdb;
 
-       spin_lock(&br->multicast_lock);
+       spin_lock_bh(&br->multicast_lock);
        if (br->multicast_disabled == !val)
                goto unlock;
 
@@ -1806,7 +1808,7 @@ rollback:
        }
 
 unlock:
-       spin_unlock(&br->multicast_lock);
+       spin_unlock_bh(&br->multicast_lock);
 
        return err;
 }
index d7d6fb0..4027029 100644 (file)
@@ -387,7 +387,8 @@ extern int br_add_if(struct net_bridge *br,
 extern int br_del_if(struct net_bridge *br,
              struct net_device *dev);
 extern int br_min_mtu(const struct net_bridge *br);
-extern u32 br_features_recompute(struct net_bridge *br, u32 features);
+extern netdev_features_t br_features_recompute(struct net_bridge *br,
+       netdev_features_t features);
 
 /* br_input.c */
 extern int br_handle_frame_finish(struct sk_buff *skb);
index 0d357b1..3606d40 100644 (file)
@@ -19,3 +19,4 @@ obj-$(CONFIG_FIB_RULES) += fib_rules.o
 obj-$(CONFIG_TRACEPOINTS) += net-traces.o
 obj-$(CONFIG_NET_DROP_MONITOR) += drop_monitor.o
 obj-$(CONFIG_NETWORK_PHY_TIMESTAMPING) += timestamping.o
+obj-$(CONFIG_NETPRIO_CGROUP) += netprio_cgroup.o
index 6ba50a1..8afb244 100644 (file)
 #include <linux/if_pppox.h>
 #include <linux/ppp_defs.h>
 #include <linux/net_tstamp.h>
+#include <linux/jump_label.h>
 
 #include "net-sysfs.h"
 
@@ -1320,8 +1321,6 @@ EXPORT_SYMBOL(dev_close);
  */
 void dev_disable_lro(struct net_device *dev)
 {
-       u32 flags;
-
        /*
         * If we're trying to disable lro on a vlan device
         * use the underlying physical device instead
@@ -1329,15 +1328,9 @@ void dev_disable_lro(struct net_device *dev)
        if (is_vlan_dev(dev))
                dev = vlan_dev_real_dev(dev);
 
-       if (dev->ethtool_ops && dev->ethtool_ops->get_flags)
-               flags = dev->ethtool_ops->get_flags(dev);
-       else
-               flags = ethtool_op_get_flags(dev);
+       dev->wanted_features &= ~NETIF_F_LRO;
+       netdev_update_features(dev);
 
-       if (!(flags & ETH_FLAG_LRO))
-               return;
-
-       __ethtool_set_flags(dev, flags & ~ETH_FLAG_LRO);
        if (unlikely(dev->features & NETIF_F_LRO))
                netdev_WARN(dev, "failed to disable LRO!\n");
 }
@@ -1449,34 +1442,32 @@ int call_netdevice_notifiers(unsigned long val, struct net_device *dev)
 }
 EXPORT_SYMBOL(call_netdevice_notifiers);
 
-/* When > 0 there are consumers of rx skb time stamps */
-static atomic_t netstamp_needed = ATOMIC_INIT(0);
+static struct jump_label_key netstamp_needed __read_mostly;
 
 void net_enable_timestamp(void)
 {
-       atomic_inc(&netstamp_needed);
+       jump_label_inc(&netstamp_needed);
 }
 EXPORT_SYMBOL(net_enable_timestamp);
 
 void net_disable_timestamp(void)
 {
-       atomic_dec(&netstamp_needed);
+       jump_label_dec(&netstamp_needed);
 }
 EXPORT_SYMBOL(net_disable_timestamp);
 
 static inline void net_timestamp_set(struct sk_buff *skb)
 {
-       if (atomic_read(&netstamp_needed))
+       skb->tstamp.tv64 = 0;
+       if (static_branch(&netstamp_needed))
                __net_timestamp(skb);
-       else
-               skb->tstamp.tv64 = 0;
 }
 
-static inline void net_timestamp_check(struct sk_buff *skb)
-{
-       if (!skb->tstamp.tv64 && atomic_read(&netstamp_needed))
-               __net_timestamp(skb);
-}
+#define net_timestamp_check(COND, SKB)                 \
+       if (static_branch(&netstamp_needed)) {          \
+               if ((COND) && !(SKB)->tstamp.tv64)      \
+                       __net_timestamp(SKB);           \
+       }                                               \
 
 static int net_hwtstamp_validate(struct ifreq *ifr)
 {
@@ -1923,7 +1914,8 @@ EXPORT_SYMBOL(skb_checksum_help);
  *     It may return NULL if the skb requires no segmentation.  This is
  *     only possible when GSO is used for verifying header integrity.
  */
-struct sk_buff *skb_gso_segment(struct sk_buff *skb, u32 features)
+struct sk_buff *skb_gso_segment(struct sk_buff *skb,
+       netdev_features_t features)
 {
        struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
        struct packet_type *ptype;
@@ -1953,9 +1945,9 @@ struct sk_buff *skb_gso_segment(struct sk_buff *skb, u32 features)
                if (dev && dev->ethtool_ops && dev->ethtool_ops->get_drvinfo)
                        dev->ethtool_ops->get_drvinfo(dev, &info);
 
-               WARN(1, "%s: caps=(0x%lx, 0x%lx) len=%d data_len=%d ip_summed=%d\n",
-                    info.driver, dev ? dev->features : 0L,
-                    skb->sk ? skb->sk->sk_route_caps : 0L,
+               WARN(1, "%s: caps=(%pNF, %pNF) len=%d data_len=%d ip_summed=%d\n",
+                    info.driver, dev ? &dev->features : NULL,
+                    skb->sk ? &skb->sk->sk_route_caps : NULL,
                     skb->len, skb->data_len, skb->ip_summed);
 
                if (skb_header_cloned(skb) &&
@@ -2064,7 +2056,7 @@ static void dev_gso_skb_destructor(struct sk_buff *skb)
  *     This function segments the given skb and stores the list of segments
  *     in skb->next.
  */
-static int dev_gso_segment(struct sk_buff *skb, int features)
+static int dev_gso_segment(struct sk_buff *skb, netdev_features_t features)
 {
        struct sk_buff *segs;
 
@@ -2103,7 +2095,7 @@ static inline void skb_orphan_try(struct sk_buff *skb)
        }
 }
 
-static bool can_checksum_protocol(unsigned long features, __be16 protocol)
+static bool can_checksum_protocol(netdev_features_t features, __be16 protocol)
 {
        return ((features & NETIF_F_GEN_CSUM) ||
                ((features & NETIF_F_V4_CSUM) &&
@@ -2114,7 +2106,8 @@ static bool can_checksum_protocol(unsigned long features, __be16 protocol)
                 protocol == htons(ETH_P_FCOE)));
 }
 
-static u32 harmonize_features(struct sk_buff *skb, __be16 protocol, u32 features)
+static netdev_features_t harmonize_features(struct sk_buff *skb,
+       __be16 protocol, netdev_features_t features)
 {
        if (!can_checksum_protocol(features, protocol)) {
                features &= ~NETIF_F_ALL_CSUM;
@@ -2126,10 +2119,10 @@ static u32 harmonize_features(struct sk_buff *skb, __be16 protocol, u32 features
        return features;
 }
 
-u32 netif_skb_features(struct sk_buff *skb)
+netdev_features_t netif_skb_features(struct sk_buff *skb)
 {
        __be16 protocol = skb->protocol;
-       u32 features = skb->dev->features;
+       netdev_features_t features = skb->dev->features;
 
        if (protocol == htons(ETH_P_8021Q)) {
                struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
@@ -2175,7 +2168,7 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
        unsigned int skb_len;
 
        if (likely(!skb->next)) {
-               u32 features;
+               netdev_features_t features;
 
                /*
                 * If device doesn't need skb->dst, release it right now while
@@ -2456,6 +2449,18 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q,
        return rc;
 }
 
+#if IS_ENABLED(CONFIG_NETPRIO_CGROUP)
+static void skb_update_prio(struct sk_buff *skb)
+{
+       struct netprio_map *map = rcu_dereference(skb->dev->priomap);
+
+       if ((!skb->priority) && (skb->sk) && map)
+               skb->priority = map->priomap[skb->sk->sk_cgrp_prioidx];
+}
+#else
+#define skb_update_prio(skb)
+#endif
+
 static DEFINE_PER_CPU(int, xmit_recursion);
 #define RECURSION_LIMIT 10
 
@@ -2496,6 +2501,8 @@ int dev_queue_xmit(struct sk_buff *skb)
         */
        rcu_read_lock_bh();
 
+       skb_update_prio(skb);
+
        txq = dev_pick_tx(dev, skb);
        q = rcu_dereference_bh(txq->qdisc);
 
@@ -2718,6 +2725,8 @@ EXPORT_SYMBOL(__skb_get_rxhash);
 struct rps_sock_flow_table __rcu *rps_sock_flow_table __read_mostly;
 EXPORT_SYMBOL(rps_sock_flow_table);
 
+struct jump_label_key rps_needed __read_mostly;
+
 static struct rps_dev_flow *
 set_rps_cpu(struct net_device *dev, struct sk_buff *skb,
            struct rps_dev_flow *rflow, u16 next_cpu)
@@ -2997,12 +3006,11 @@ int netif_rx(struct sk_buff *skb)
        if (netpoll_rx(skb))
                return NET_RX_DROP;
 
-       if (netdev_tstamp_prequeue)
-               net_timestamp_check(skb);
+       net_timestamp_check(netdev_tstamp_prequeue, skb);
 
        trace_netif_rx(skb);
 #ifdef CONFIG_RPS
-       {
+       if (static_branch(&rps_needed)) {
                struct rps_dev_flow voidflow, *rflow = &voidflow;
                int cpu;
 
@@ -3017,14 +3025,13 @@ int netif_rx(struct sk_buff *skb)
 
                rcu_read_unlock();
                preempt_enable();
-       }
-#else
+       } else
+#endif
        {
                unsigned int qtail;
                ret = enqueue_to_backlog(skb, get_cpu(), &qtail);
                put_cpu();
        }
-#endif
        return ret;
 }
 EXPORT_SYMBOL(netif_rx);
@@ -3230,8 +3237,7 @@ static int __netif_receive_skb(struct sk_buff *skb)
        int ret = NET_RX_DROP;
        __be16 type;
 
-       if (!netdev_tstamp_prequeue)
-               net_timestamp_check(skb);
+       net_timestamp_check(!netdev_tstamp_prequeue, skb);
 
        trace_netif_receive_skb(skb);
 
@@ -3362,14 +3368,13 @@ out:
  */
 int netif_receive_skb(struct sk_buff *skb)
 {
-       if (netdev_tstamp_prequeue)
-               net_timestamp_check(skb);
+       net_timestamp_check(netdev_tstamp_prequeue, skb);
 
        if (skb_defer_rx_timestamp(skb))
                return NET_RX_SUCCESS;
 
 #ifdef CONFIG_RPS
-       {
+       if (static_branch(&rps_needed)) {
                struct rps_dev_flow voidflow, *rflow = &voidflow;
                int cpu, ret;
 
@@ -3380,16 +3385,12 @@ int netif_receive_skb(struct sk_buff *skb)
                if (cpu >= 0) {
                        ret = enqueue_to_backlog(skb, cpu, &rflow->last_qtail);
                        rcu_read_unlock();
-               } else {
-                       rcu_read_unlock();
-                       ret = __netif_receive_skb(skb);
+                       return ret;
                }
-
-               return ret;
+               rcu_read_unlock();
        }
-#else
-       return __netif_receive_skb(skb);
 #endif
+       return __netif_receive_skb(skb);
 }
 EXPORT_SYMBOL(netif_receive_skb);
 
@@ -5362,7 +5363,8 @@ static void rollback_registered(struct net_device *dev)
        list_del(&single);
 }
 
-static u32 netdev_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t netdev_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        /* Fix illegal checksum combinations */
        if ((features & NETIF_F_HW_CSUM) &&
@@ -5371,12 +5373,6 @@ static u32 netdev_fix_features(struct net_device *dev, u32 features)
                features &= ~(NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM);
        }
 
-       if ((features & NETIF_F_NO_CSUM) &&
-           (features & (NETIF_F_HW_CSUM|NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM))) {
-               netdev_warn(dev, "mixed no checksumming and other settings.\n");
-               features &= ~(NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM|NETIF_F_HW_CSUM);
-       }
-
        /* Fix illegal SG+CSUM combinations. */
        if ((features & NETIF_F_SG) &&
            !(features & NETIF_F_ALL_CSUM)) {
@@ -5424,7 +5420,7 @@ static u32 netdev_fix_features(struct net_device *dev, u32 features)
 
 int __netdev_update_features(struct net_device *dev)
 {
-       u32 features;
+       netdev_features_t features;
        int err = 0;
 
        ASSERT_RTNL();
@@ -5440,16 +5436,16 @@ int __netdev_update_features(struct net_device *dev)
        if (dev->features == features)
                return 0;
 
-       netdev_dbg(dev, "Features changed: 0x%08x -> 0x%08x\n",
-               dev->features, features);
+       netdev_dbg(dev, "Features changed: %pNF -> %pNF\n",
+               &dev->features, &features);
 
        if (dev->netdev_ops->ndo_set_features)
                err = dev->netdev_ops->ndo_set_features(dev, features);
 
        if (unlikely(err < 0)) {
                netdev_err(dev,
-                       "set_features() failed (%d); wanted 0x%08x, left 0x%08x\n",
-                       err, features, dev->features);
+                       "set_features() failed (%d); wanted %pNF, left %pNF\n",
+                       err, &features, &dev->features);
                return -1;
        }
 
@@ -5633,11 +5629,12 @@ int register_netdevice(struct net_device *dev)
        dev->wanted_features = dev->features & dev->hw_features;
 
        /* Turn on no cache copy if HW is doing checksum */
-       dev->hw_features |= NETIF_F_NOCACHE_COPY;
-       if ((dev->features & NETIF_F_ALL_CSUM) &&
-           !(dev->features & NETIF_F_NO_CSUM)) {
-               dev->wanted_features |= NETIF_F_NOCACHE_COPY;
-               dev->features |= NETIF_F_NOCACHE_COPY;
+       if (!(dev->flags & IFF_LOOPBACK)) {
+               dev->hw_features |= NETIF_F_NOCACHE_COPY;
+               if (dev->features & NETIF_F_ALL_CSUM) {
+                       dev->wanted_features |= NETIF_F_NOCACHE_COPY;
+                       dev->features |= NETIF_F_NOCACHE_COPY;
+               }
        }
 
        /* Make NETIF_F_HIGHDMA inheritable to VLAN devices.
@@ -6373,7 +6370,8 @@ static int dev_cpu_callback(struct notifier_block *nfb,
  *     @one to the master device with current feature set @all.  Will not
  *     enable anything that is off in @mask. Returns the new feature set.
  */
-u32 netdev_increment_features(u32 all, u32 one, u32 mask)
+netdev_features_t netdev_increment_features(netdev_features_t all,
+       netdev_features_t one, netdev_features_t mask)
 {
        if (mask & NETIF_F_GEN_CSUM)
                mask |= NETIF_F_ALL_CSUM;
@@ -6382,10 +6380,6 @@ u32 netdev_increment_features(u32 all, u32 one, u32 mask)
        all |= one & (NETIF_F_ONE_FOR_ALL|NETIF_F_ALL_CSUM) & mask;
        all &= one | ~NETIF_F_ALL_FOR_ALL;
 
-       /* If device needs checksumming, downgrade to it. */
-       if (all & (NETIF_F_ALL_CSUM & ~NETIF_F_NO_CSUM))
-               all &= ~NETIF_F_NO_CSUM;
-
        /* If one device supports hw checksumming, set for all. */
        if (all & NETIF_F_GEN_CSUM)
                all &= ~(NETIF_F_ALL_CSUM & ~NETIF_F_GEN_CSUM);
index f444817..31b0b7f 100644 (file)
@@ -36,235 +36,44 @@ u32 ethtool_op_get_link(struct net_device *dev)
 }
 EXPORT_SYMBOL(ethtool_op_get_link);
 
-u32 ethtool_op_get_tx_csum(struct net_device *dev)
-{
-       return (dev->features & NETIF_F_ALL_CSUM) != 0;
-}
-EXPORT_SYMBOL(ethtool_op_get_tx_csum);
-
-int ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
-{
-       if (data)
-               dev->features |= NETIF_F_IP_CSUM;
-       else
-               dev->features &= ~NETIF_F_IP_CSUM;
-
-       return 0;
-}
-EXPORT_SYMBOL(ethtool_op_set_tx_csum);
-
-int ethtool_op_set_tx_hw_csum(struct net_device *dev, u32 data)
-{
-       if (data)
-               dev->features |= NETIF_F_HW_CSUM;
-       else
-               dev->features &= ~NETIF_F_HW_CSUM;
-
-       return 0;
-}
-EXPORT_SYMBOL(ethtool_op_set_tx_hw_csum);
-
-int ethtool_op_set_tx_ipv6_csum(struct net_device *dev, u32 data)
-{
-       if (data)
-               dev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
-       else
-               dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
-
-       return 0;
-}
-EXPORT_SYMBOL(ethtool_op_set_tx_ipv6_csum);
-
-u32 ethtool_op_get_sg(struct net_device *dev)
-{
-       return (dev->features & NETIF_F_SG) != 0;
-}
-EXPORT_SYMBOL(ethtool_op_get_sg);
-
-int ethtool_op_set_sg(struct net_device *dev, u32 data)
-{
-       if (data)
-               dev->features |= NETIF_F_SG;
-       else
-               dev->features &= ~NETIF_F_SG;
-
-       return 0;
-}
-EXPORT_SYMBOL(ethtool_op_set_sg);
-
-u32 ethtool_op_get_tso(struct net_device *dev)
-{
-       return (dev->features & NETIF_F_TSO) != 0;
-}
-EXPORT_SYMBOL(ethtool_op_get_tso);
-
-int ethtool_op_set_tso(struct net_device *dev, u32 data)
-{
-       if (data)
-               dev->features |= NETIF_F_TSO;
-       else
-               dev->features &= ~NETIF_F_TSO;
-
-       return 0;
-}
-EXPORT_SYMBOL(ethtool_op_set_tso);
-
-u32 ethtool_op_get_ufo(struct net_device *dev)
-{
-       return (dev->features & NETIF_F_UFO) != 0;
-}
-EXPORT_SYMBOL(ethtool_op_get_ufo);
-
-int ethtool_op_set_ufo(struct net_device *dev, u32 data)
-{
-       if (data)
-               dev->features |= NETIF_F_UFO;
-       else
-               dev->features &= ~NETIF_F_UFO;
-       return 0;
-}
-EXPORT_SYMBOL(ethtool_op_set_ufo);
-
-/* the following list of flags are the same as their associated
- * NETIF_F_xxx values in include/linux/netdevice.h
- */
-static const u32 flags_dup_features =
-       (ETH_FLAG_LRO | ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN | ETH_FLAG_NTUPLE |
-        ETH_FLAG_RXHASH);
-
-u32 ethtool_op_get_flags(struct net_device *dev)
-{
-       /* in the future, this function will probably contain additional
-        * handling for flags which are not so easily handled
-        * by a simple masking operation
-        */
-
-       return dev->features & flags_dup_features;
-}
-EXPORT_SYMBOL(ethtool_op_get_flags);
-
-/* Check if device can enable (or disable) particular feature coded in "data"
- * argument. Flags "supported" describe features that can be toggled by device.
- * If feature can not be toggled, it state (enabled or disabled) must match
- * hardcoded device features state, otherwise flags are marked as invalid.
- */
-bool ethtool_invalid_flags(struct net_device *dev, u32 data, u32 supported)
-{
-       u32 features = dev->features & flags_dup_features;
-       /* "data" can contain only flags_dup_features bits,
-        * see __ethtool_set_flags */
-
-       return (features & ~supported) != (data & ~supported);
-}
-EXPORT_SYMBOL(ethtool_invalid_flags);
-
-int ethtool_op_set_flags(struct net_device *dev, u32 data, u32 supported)
-{
-       if (ethtool_invalid_flags(dev, data, supported))
-               return -EINVAL;
-
-       dev->features = ((dev->features & ~flags_dup_features) |
-                        (data & flags_dup_features));
-       return 0;
-}
-EXPORT_SYMBOL(ethtool_op_set_flags);
-
 /* Handlers for each ethtool command */
 
-#define ETHTOOL_DEV_FEATURE_WORDS      1
-
-static void ethtool_get_features_compat(struct net_device *dev,
-       struct ethtool_get_features_block *features)
-{
-       if (!dev->ethtool_ops)
-               return;
-
-       /* getting RX checksum */
-       if (dev->ethtool_ops->get_rx_csum)
-               if (dev->ethtool_ops->get_rx_csum(dev))
-                       features[0].active |= NETIF_F_RXCSUM;
-
-       /* mark legacy-changeable features */
-       if (dev->ethtool_ops->set_sg)
-               features[0].available |= NETIF_F_SG;
-       if (dev->ethtool_ops->set_tx_csum)
-               features[0].available |= NETIF_F_ALL_CSUM;
-       if (dev->ethtool_ops->set_tso)
-               features[0].available |= NETIF_F_ALL_TSO;
-       if (dev->ethtool_ops->set_rx_csum)
-               features[0].available |= NETIF_F_RXCSUM;
-       if (dev->ethtool_ops->set_flags)
-               features[0].available |= flags_dup_features;
-}
-
-static int ethtool_set_feature_compat(struct net_device *dev,
-       int (*legacy_set)(struct net_device *, u32),
-       struct ethtool_set_features_block *features, u32 mask)
-{
-       u32 do_set;
-
-       if (!legacy_set)
-               return 0;
-
-       if (!(features[0].valid & mask))
-               return 0;
-
-       features[0].valid &= ~mask;
-
-       do_set = !!(features[0].requested & mask);
-
-       if (legacy_set(dev, do_set) < 0)
-               netdev_info(dev,
-                       "Legacy feature change (%s) failed for 0x%08x\n",
-                       do_set ? "set" : "clear", mask);
-
-       return 1;
-}
-
-static int ethtool_set_flags_compat(struct net_device *dev,
-       int (*legacy_set)(struct net_device *, u32),
-       struct ethtool_set_features_block *features, u32 mask)
-{
-       u32 value;
-
-       if (!legacy_set)
-               return 0;
-
-       if (!(features[0].valid & mask))
-               return 0;
-
-       value = dev->features & ~features[0].valid;
-       value |= features[0].requested;
-
-       features[0].valid &= ~mask;
-
-       if (legacy_set(dev, value & mask) < 0)
-               netdev_info(dev, "Legacy flags change failed\n");
-
-       return 1;
-}
-
-static int ethtool_set_features_compat(struct net_device *dev,
-       struct ethtool_set_features_block *features)
-{
-       int compat;
-
-       if (!dev->ethtool_ops)
-               return 0;
-
-       compat  = ethtool_set_feature_compat(dev, dev->ethtool_ops->set_sg,
-               features, NETIF_F_SG);
-       compat |= ethtool_set_feature_compat(dev, dev->ethtool_ops->set_tx_csum,
-               features, NETIF_F_ALL_CSUM);
-       compat |= ethtool_set_feature_compat(dev, dev->ethtool_ops->set_tso,
-               features, NETIF_F_ALL_TSO);
-       compat |= ethtool_set_feature_compat(dev, dev->ethtool_ops->set_rx_csum,
-               features, NETIF_F_RXCSUM);
-       compat |= ethtool_set_flags_compat(dev, dev->ethtool_ops->set_flags,
-               features, flags_dup_features);
-
-       return compat;
-}
+#define ETHTOOL_DEV_FEATURE_WORDS      ((NETDEV_FEATURE_COUNT + 31) / 32)
+
+static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] = {
+       [NETIF_F_SG_BIT] =               "tx-scatter-gather",
+       [NETIF_F_IP_CSUM_BIT] =          "tx-checksum-ipv4",
+       [NETIF_F_HW_CSUM_BIT] =          "tx-checksum-ip-generic",
+       [NETIF_F_IPV6_CSUM_BIT] =        "tx-checksum-ipv6",
+       [NETIF_F_HIGHDMA_BIT] =          "highdma",
+       [NETIF_F_FRAGLIST_BIT] =         "tx-scatter-gather-fraglist",
+       [NETIF_F_HW_VLAN_TX_BIT] =       "tx-vlan-hw-insert",
+
+       [NETIF_F_HW_VLAN_RX_BIT] =       "rx-vlan-hw-parse",
+       [NETIF_F_HW_VLAN_FILTER_BIT] =   "rx-vlan-filter",
+       [NETIF_F_VLAN_CHALLENGED_BIT] =  "vlan-challenged",
+       [NETIF_F_GSO_BIT] =              "tx-generic-segmentation",
+       [NETIF_F_LLTX_BIT] =             "tx-lockless",
+       [NETIF_F_NETNS_LOCAL_BIT] =      "netns-local",
+       [NETIF_F_GRO_BIT] =              "rx-gro",
+       [NETIF_F_LRO_BIT] =              "rx-lro",
+
+       [NETIF_F_TSO_BIT] =              "tx-tcp-segmentation",
+       [NETIF_F_UFO_BIT] =              "tx-udp-fragmentation",
+       [NETIF_F_GSO_ROBUST_BIT] =       "tx-gso-robust",
+       [NETIF_F_TSO_ECN_BIT] =          "tx-tcp-ecn-segmentation",
+       [NETIF_F_TSO6_BIT] =             "tx-tcp6-segmentation",
+       [NETIF_F_FSO_BIT] =              "tx-fcoe-segmentation",
+
+       [NETIF_F_FCOE_CRC_BIT] =         "tx-checksum-fcoe-crc",
+       [NETIF_F_SCTP_CSUM_BIT] =        "tx-checksum-sctp",
+       [NETIF_F_FCOE_MTU_BIT] =         "fcoe-mtu",
+       [NETIF_F_NTUPLE_BIT] =           "rx-ntuple-filter",
+       [NETIF_F_RXHASH_BIT] =           "rx-hashing",
+       [NETIF_F_RXCSUM_BIT] =           "rx-checksum",
+       [NETIF_F_NOCACHE_COPY_BIT] =     "tx-nocache-copy",
+       [NETIF_F_LOOPBACK_BIT] =         "loopback",
+};
 
 static int ethtool_get_features(struct net_device *dev, void __user *useraddr)
 {
@@ -272,18 +81,21 @@ static int ethtool_get_features(struct net_device *dev, void __user *useraddr)
                .cmd = ETHTOOL_GFEATURES,
                .size = ETHTOOL_DEV_FEATURE_WORDS,
        };
-       struct ethtool_get_features_block features[ETHTOOL_DEV_FEATURE_WORDS] = {
-               {
-                       .available = dev->hw_features,
-                       .requested = dev->wanted_features,
-                       .active = dev->features,
-                       .never_changed = NETIF_F_NEVER_CHANGE,
-               },
-       };
+       struct ethtool_get_features_block features[ETHTOOL_DEV_FEATURE_WORDS];
        u32 __user *sizeaddr;
        u32 copy_size;
+       int i;
 
-       ethtool_get_features_compat(dev, features);
+       /* in case feature bits run out again */
+       BUILD_BUG_ON(ETHTOOL_DEV_FEATURE_WORDS * sizeof(u32) > sizeof(netdev_features_t));
+
+       for (i = 0; i < ETHTOOL_DEV_FEATURE_WORDS; ++i) {
+               features[i].available = (u32)(dev->hw_features >> (32 * i));
+               features[i].requested = (u32)(dev->wanted_features >> (32 * i));
+               features[i].active = (u32)(dev->features >> (32 * i));
+               features[i].never_changed =
+                       (u32)(NETIF_F_NEVER_CHANGE >> (32 * i));
+       }
 
        sizeaddr = useraddr + offsetof(struct ethtool_gfeatures, size);
        if (get_user(copy_size, sizeaddr))
@@ -305,7 +117,8 @@ static int ethtool_set_features(struct net_device *dev, void __user *useraddr)
 {
        struct ethtool_sfeatures cmd;
        struct ethtool_set_features_block features[ETHTOOL_DEV_FEATURE_WORDS];
-       int ret = 0;
+       netdev_features_t wanted = 0, valid = 0;
+       int i, ret = 0;
 
        if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
                return -EFAULT;
@@ -317,65 +130,29 @@ static int ethtool_set_features(struct net_device *dev, void __user *useraddr)
        if (copy_from_user(features, useraddr, sizeof(features)))
                return -EFAULT;
 
-       if (features[0].valid & ~NETIF_F_ETHTOOL_BITS)
-               return -EINVAL;
+       for (i = 0; i < ETHTOOL_DEV_FEATURE_WORDS; ++i) {
+               valid |= (netdev_features_t)features[i].valid << (32 * i);
+               wanted |= (netdev_features_t)features[i].requested << (32 * i);
+       }
 
-       if (ethtool_set_features_compat(dev, features))
-               ret |= ETHTOOL_F_COMPAT;
+       if (valid & ~NETIF_F_ETHTOOL_BITS)
+               return -EINVAL;
 
-       if (features[0].valid & ~dev->hw_features) {
-               features[0].valid &= dev->hw_features;
+       if (valid & ~dev->hw_features) {
+               valid &= dev->hw_features;
                ret |= ETHTOOL_F_UNSUPPORTED;
        }
 
-       dev->wanted_features &= ~features[0].valid;
-       dev->wanted_features |= features[0].valid & features[0].requested;
+       dev->wanted_features &= ~valid;
+       dev->wanted_features |= wanted & valid;
        __netdev_update_features(dev);
 
-       if ((dev->wanted_features ^ dev->features) & features[0].valid)
+       if ((dev->wanted_features ^ dev->features) & valid)
                ret |= ETHTOOL_F_WISH;
 
        return ret;
 }
 
-static const char netdev_features_strings[ETHTOOL_DEV_FEATURE_WORDS * 32][ETH_GSTRING_LEN] = {
-       /* NETIF_F_SG */              "tx-scatter-gather",
-       /* NETIF_F_IP_CSUM */         "tx-checksum-ipv4",
-       /* NETIF_F_NO_CSUM */         "tx-checksum-unneeded",
-       /* NETIF_F_HW_CSUM */         "tx-checksum-ip-generic",
-       /* NETIF_F_IPV6_CSUM */       "tx-checksum-ipv6",
-       /* NETIF_F_HIGHDMA */         "highdma",
-       /* NETIF_F_FRAGLIST */        "tx-scatter-gather-fraglist",
-       /* NETIF_F_HW_VLAN_TX */      "tx-vlan-hw-insert",
-
-       /* NETIF_F_HW_VLAN_RX */      "rx-vlan-hw-parse",
-       /* NETIF_F_HW_VLAN_FILTER */  "rx-vlan-filter",
-       /* NETIF_F_VLAN_CHALLENGED */ "vlan-challenged",
-       /* NETIF_F_GSO */             "tx-generic-segmentation",
-       /* NETIF_F_LLTX */            "tx-lockless",
-       /* NETIF_F_NETNS_LOCAL */     "netns-local",
-       /* NETIF_F_GRO */             "rx-gro",
-       /* NETIF_F_LRO */             "rx-lro",
-
-       /* NETIF_F_TSO */             "tx-tcp-segmentation",
-       /* NETIF_F_UFO */             "tx-udp-fragmentation",
-       /* NETIF_F_GSO_ROBUST */      "tx-gso-robust",
-       /* NETIF_F_TSO_ECN */         "tx-tcp-ecn-segmentation",
-       /* NETIF_F_TSO6 */            "tx-tcp6-segmentation",
-       /* NETIF_F_FSO */             "tx-fcoe-segmentation",
-       "",
-       "",
-
-       /* NETIF_F_FCOE_CRC */        "tx-checksum-fcoe-crc",
-       /* NETIF_F_SCTP_CSUM */       "tx-checksum-sctp",
-       /* NETIF_F_FCOE_MTU */        "fcoe-mtu",
-       /* NETIF_F_NTUPLE */          "rx-ntuple-filter",
-       /* NETIF_F_RXHASH */          "rx-hashing",
-       /* NETIF_F_RXCSUM */          "rx-checksum",
-       /* NETIF_F_NOCACHE_COPY */    "tx-nocache-copy",
-       /* NETIF_F_LOOPBACK */        "loopback",
-};
-
 static int __ethtool_get_sset_count(struct net_device *dev, int sset)
 {
        const struct ethtool_ops *ops = dev->ethtool_ops;
@@ -402,7 +179,7 @@ static void __ethtool_get_strings(struct net_device *dev,
                ops->get_strings(dev, stringset, data);
 }
 
-static u32 ethtool_get_feature_mask(u32 eth_cmd)
+static netdev_features_t ethtool_get_feature_mask(u32 eth_cmd)
 {
        /* feature masks of legacy discrete ethtool ops */
 
@@ -433,136 +210,82 @@ static u32 ethtool_get_feature_mask(u32 eth_cmd)
        }
 }
 
-static void *__ethtool_get_one_feature_actor(struct net_device *dev, u32 ethcmd)
-{
-       const struct ethtool_ops *ops = dev->ethtool_ops;
-
-       if (!ops)
-               return NULL;
-
-       switch (ethcmd) {
-       case ETHTOOL_GTXCSUM:
-               return ops->get_tx_csum;
-       case ETHTOOL_GRXCSUM:
-               return ops->get_rx_csum;
-       case ETHTOOL_SSG:
-               return ops->get_sg;
-       case ETHTOOL_STSO:
-               return ops->get_tso;
-       case ETHTOOL_SUFO:
-               return ops->get_ufo;
-       default:
-               return NULL;
-       }
-}
-
-static u32 __ethtool_get_rx_csum_oldbug(struct net_device *dev)
-{
-       return !!(dev->features & NETIF_F_ALL_CSUM);
-}
-
 static int ethtool_get_one_feature(struct net_device *dev,
        char __user *useraddr, u32 ethcmd)
 {
-       u32 mask = ethtool_get_feature_mask(ethcmd);
+       netdev_features_t mask = ethtool_get_feature_mask(ethcmd);
        struct ethtool_value edata = {
                .cmd = ethcmd,
                .data = !!(dev->features & mask),
        };
 
-       /* compatibility with discrete get_ ops */
-       if (!(dev->hw_features & mask)) {
-               u32 (*actor)(struct net_device *);
-
-               actor = __ethtool_get_one_feature_actor(dev, ethcmd);
-
-               /* bug compatibility with old get_rx_csum */
-               if (ethcmd == ETHTOOL_GRXCSUM && !actor)
-                       actor = __ethtool_get_rx_csum_oldbug;
-
-               if (actor)
-                       edata.data = actor(dev);
-       }
-
        if (copy_to_user(useraddr, &edata, sizeof(edata)))
                return -EFAULT;
        return 0;
 }
 
-static int __ethtool_set_tx_csum(struct net_device *dev, u32 data);
-static int __ethtool_set_rx_csum(struct net_device *dev, u32 data);
-static int __ethtool_set_sg(struct net_device *dev, u32 data);
-static int __ethtool_set_tso(struct net_device *dev, u32 data);
-static int __ethtool_set_ufo(struct net_device *dev, u32 data);
-
 static int ethtool_set_one_feature(struct net_device *dev,
        void __user *useraddr, u32 ethcmd)
 {
        struct ethtool_value edata;
-       u32 mask;
+       netdev_features_t mask;
 
        if (copy_from_user(&edata, useraddr, sizeof(edata)))
                return -EFAULT;
 
        mask = ethtool_get_feature_mask(ethcmd);
        mask &= dev->hw_features;
-       if (mask) {
-               if (edata.data)
-                       dev->wanted_features |= mask;
-               else
-                       dev->wanted_features &= ~mask;
+       if (!mask)
+               return -EOPNOTSUPP;
 
-               __netdev_update_features(dev);
-               return 0;
-       }
+       if (edata.data)
+               dev->wanted_features |= mask;
+       else
+               dev->wanted_features &= ~mask;
 
-       /* Driver is not converted to ndo_fix_features or does not
-        * support changing this offload. In the latter case it won't
-        * have corresponding ethtool_ops field set.
-        *
-        * Following part is to be removed after all drivers advertise
-        * their changeable features in netdev->hw_features and stop
-        * using discrete offload setting ops.
-        */
+       __netdev_update_features(dev);
 
-       switch (ethcmd) {
-       case ETHTOOL_STXCSUM:
-               return __ethtool_set_tx_csum(dev, edata.data);
-       case ETHTOOL_SRXCSUM:
-               return __ethtool_set_rx_csum(dev, edata.data);
-       case ETHTOOL_SSG:
-               return __ethtool_set_sg(dev, edata.data);
-       case ETHTOOL_STSO:
-               return __ethtool_set_tso(dev, edata.data);
-       case ETHTOOL_SUFO:
-               return __ethtool_set_ufo(dev, edata.data);
-       default:
-               return -EOPNOTSUPP;
-       }
+       return 0;
+}
+
+#define ETH_ALL_FLAGS    (ETH_FLAG_LRO | ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN | \
+                         ETH_FLAG_NTUPLE | ETH_FLAG_RXHASH)
+#define ETH_ALL_FEATURES (NETIF_F_LRO | NETIF_F_HW_VLAN_RX | \
+                         NETIF_F_HW_VLAN_TX | NETIF_F_NTUPLE | NETIF_F_RXHASH)
+
+static u32 __ethtool_get_flags(struct net_device *dev)
+{
+       u32 flags = 0;
+
+       if (dev->features & NETIF_F_LRO)        flags |= ETH_FLAG_LRO;
+       if (dev->features & NETIF_F_HW_VLAN_RX) flags |= ETH_FLAG_RXVLAN;
+       if (dev->features & NETIF_F_HW_VLAN_TX) flags |= ETH_FLAG_TXVLAN;
+       if (dev->features & NETIF_F_NTUPLE)     flags |= ETH_FLAG_NTUPLE;
+       if (dev->features & NETIF_F_RXHASH)     flags |= ETH_FLAG_RXHASH;
+
+       return flags;
 }
 
-int __ethtool_set_flags(struct net_device *dev, u32 data)
+static int __ethtool_set_flags(struct net_device *dev, u32 data)
 {
-       u32 changed;
+       netdev_features_t features = 0, changed;
 
-       if (data & ~flags_dup_features)
+       if (data & ~ETH_ALL_FLAGS)
                return -EINVAL;
 
-       /* legacy set_flags() op */
-       if (dev->ethtool_ops->set_flags) {
-               if (unlikely(dev->hw_features & flags_dup_features))
-                       netdev_warn(dev,
-                               "driver BUG: mixed hw_features and set_flags()\n");
-               return dev->ethtool_ops->set_flags(dev, data);
-       }
+       if (data & ETH_FLAG_LRO)        features |= NETIF_F_LRO;
+       if (data & ETH_FLAG_RXVLAN)     features |= NETIF_F_HW_VLAN_RX;
+       if (data & ETH_FLAG_TXVLAN)     features |= NETIF_F_HW_VLAN_TX;
+       if (data & ETH_FLAG_NTUPLE)     features |= NETIF_F_NTUPLE;
+       if (data & ETH_FLAG_RXHASH)     features |= NETIF_F_RXHASH;
 
        /* allow changing only bits set in hw_features */
-       changed = (data ^ dev->features) & flags_dup_features;
+       changed = (features ^ dev->features) & ETH_ALL_FEATURES;
        if (changed & ~dev->hw_features)
                return (changed & dev->hw_features) ? -EINVAL : -EOPNOTSUPP;
 
        dev->wanted_features =
-               (dev->wanted_features & ~changed) | (data & dev->hw_features);
+               (dev->wanted_features & ~changed) | (features & changed);
 
        __netdev_update_features(dev);
 
@@ -1231,81 +954,6 @@ static int ethtool_set_pauseparam(struct net_device *dev, void __user *useraddr)
        return dev->ethtool_ops->set_pauseparam(dev, &pauseparam);
 }
 
-static int __ethtool_set_sg(struct net_device *dev, u32 data)
-{
-       int err;
-
-       if (!dev->ethtool_ops->set_sg)
-               return -EOPNOTSUPP;
-
-       if (data && !(dev->features & NETIF_F_ALL_CSUM))
-               return -EINVAL;
-
-       if (!data && dev->ethtool_ops->set_tso) {
-               err = dev->ethtool_ops->set_tso(dev, 0);
-               if (err)
-                       return err;
-       }
-
-       if (!data && dev->ethtool_ops->set_ufo) {
-               err = dev->ethtool_ops->set_ufo(dev, 0);
-               if (err)
-                       return err;
-       }
-       return dev->ethtool_ops->set_sg(dev, data);
-}
-
-static int __ethtool_set_tx_csum(struct net_device *dev, u32 data)
-{
-       int err;
-
-       if (!dev->ethtool_ops->set_tx_csum)
-               return -EOPNOTSUPP;
-
-       if (!data && dev->ethtool_ops->set_sg) {
-               err = __ethtool_set_sg(dev, 0);
-               if (err)
-                       return err;
-       }
-
-       return dev->ethtool_ops->set_tx_csum(dev, data);
-}
-
-static int __ethtool_set_rx_csum(struct net_device *dev, u32 data)
-{
-       if (!dev->ethtool_ops->set_rx_csum)
-               return -EOPNOTSUPP;
-
-       if (!data)
-               dev->features &= ~NETIF_F_GRO;
-
-       return dev->ethtool_ops->set_rx_csum(dev, data);
-}
-
-static int __ethtool_set_tso(struct net_device *dev, u32 data)
-{
-       if (!dev->ethtool_ops->set_tso)
-               return -EOPNOTSUPP;
-
-       if (data && !(dev->features & NETIF_F_SG))
-               return -EINVAL;
-
-       return dev->ethtool_ops->set_tso(dev, data);
-}
-
-static int __ethtool_set_ufo(struct net_device *dev, u32 data)
-{
-       if (!dev->ethtool_ops->set_ufo)
-               return -EOPNOTSUPP;
-       if (data && !(dev->features & NETIF_F_SG))
-               return -EINVAL;
-       if (data && !((dev->features & NETIF_F_GEN_CSUM) ||
-               (dev->features & (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM))
-                       == (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM)))
-               return -EINVAL;
-       return dev->ethtool_ops->set_ufo(dev, data);
-}
-
 static int ethtool_self_test(struct net_device *dev, char __user *useraddr)
 {
        struct ethtool_test test;
@@ -1771,9 +1419,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
                break;
        case ETHTOOL_GFLAGS:
                rc = ethtool_get_value(dev, useraddr, ethcmd,
-                                      (dev->ethtool_ops->get_flags ?
-                                       dev->ethtool_ops->get_flags :
-                                       ethtool_op_get_flags));
+                                       __ethtool_get_flags);
                break;
        case ETHTOOL_SFLAGS:
                rc = ethtool_set_value(dev, useraddr, __ethtool_set_flags);
index 039d51e..2684794 100644 (file)
@@ -238,6 +238,7 @@ static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev)
                                   it to safe state.
                                 */
                                skb_queue_purge(&n->arp_queue);
+                               n->arp_queue_len_bytes = 0;
                                n->output = neigh_blackhole;
                                if (n->nud_state & NUD_VALID)
                                        n->nud_state = NUD_NOARP;
@@ -702,6 +703,7 @@ void neigh_destroy(struct neighbour *neigh)
                printk(KERN_WARNING "Impossible event.\n");
 
        skb_queue_purge(&neigh->arp_queue);
+       neigh->arp_queue_len_bytes = 0;
 
        dev_put(neigh->dev);
        neigh_parms_put(neigh->parms);
@@ -842,6 +844,7 @@ static void neigh_invalidate(struct neighbour *neigh)
                write_lock(&neigh->lock);
        }
        skb_queue_purge(&neigh->arp_queue);
+       neigh->arp_queue_len_bytes = 0;
 }
 
 static void neigh_probe(struct neighbour *neigh)
@@ -980,15 +983,20 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
 
        if (neigh->nud_state == NUD_INCOMPLETE) {
                if (skb) {
-                       if (skb_queue_len(&neigh->arp_queue) >=
-                           neigh->parms->queue_len) {
+                       while (neigh->arp_queue_len_bytes + skb->truesize >
+                              neigh->parms->queue_len_bytes) {
                                struct sk_buff *buff;
+
                                buff = __skb_dequeue(&neigh->arp_queue);
+                               if (!buff)
+                                       break;
+                               neigh->arp_queue_len_bytes -= buff->truesize;
                                kfree_skb(buff);
                                NEIGH_CACHE_STAT_INC(neigh->tbl, unres_discards);
                        }
                        skb_dst_force(skb);
                        __skb_queue_tail(&neigh->arp_queue, skb);
+                       neigh->arp_queue_len_bytes += skb->truesize;
                }
                rc = 1;
        }
@@ -1175,6 +1183,7 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
                        write_lock_bh(&neigh->lock);
                }
                skb_queue_purge(&neigh->arp_queue);
+               neigh->arp_queue_len_bytes = 0;
        }
 out:
        if (update_isrouter) {
@@ -1747,7 +1756,11 @@ static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
                NLA_PUT_U32(skb, NDTPA_IFINDEX, parms->dev->ifindex);
 
        NLA_PUT_U32(skb, NDTPA_REFCNT, atomic_read(&parms->refcnt));
-       NLA_PUT_U32(skb, NDTPA_QUEUE_LEN, parms->queue_len);
+       NLA_PUT_U32(skb, NDTPA_QUEUE_LENBYTES, parms->queue_len_bytes);
+       /* approximative value for deprecated QUEUE_LEN (in packets) */
+       NLA_PUT_U32(skb, NDTPA_QUEUE_LEN,
+                   DIV_ROUND_UP(parms->queue_len_bytes,
+                                SKB_TRUESIZE(ETH_FRAME_LEN)));
        NLA_PUT_U32(skb, NDTPA_PROXY_QLEN, parms->proxy_qlen);
        NLA_PUT_U32(skb, NDTPA_APP_PROBES, parms->app_probes);
        NLA_PUT_U32(skb, NDTPA_UCAST_PROBES, parms->ucast_probes);
@@ -1974,7 +1987,11 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 
                        switch (i) {
                        case NDTPA_QUEUE_LEN:
-                               p->queue_len = nla_get_u32(tbp[i]);
+                               p->queue_len_bytes = nla_get_u32(tbp[i]) *
+                                                    SKB_TRUESIZE(ETH_FRAME_LEN);
+                               break;
+                       case NDTPA_QUEUE_LENBYTES:
+                               p->queue_len_bytes = nla_get_u32(tbp[i]);
                                break;
                        case NDTPA_PROXY_QLEN:
                                p->proxy_qlen = nla_get_u32(tbp[i]);
@@ -2635,117 +2652,158 @@ EXPORT_SYMBOL(neigh_app_ns);
 
 #ifdef CONFIG_SYSCTL
 
-#define NEIGH_VARS_MAX 19
+static int proc_unres_qlen(ctl_table *ctl, int write, void __user *buffer,
+                          size_t *lenp, loff_t *ppos)
+{
+       int size, ret;
+       ctl_table tmp = *ctl;
+
+       tmp.data = &size;
+       size = DIV_ROUND_UP(*(int *)ctl->data, SKB_TRUESIZE(ETH_FRAME_LEN));
+       ret = proc_dointvec(&tmp, write, buffer, lenp, ppos);
+       if (write && !ret)
+               *(int *)ctl->data = size * SKB_TRUESIZE(ETH_FRAME_LEN);
+       return ret;
+}
+
+enum {
+       NEIGH_VAR_MCAST_PROBE,
+       NEIGH_VAR_UCAST_PROBE,
+       NEIGH_VAR_APP_PROBE,
+       NEIGH_VAR_RETRANS_TIME,
+       NEIGH_VAR_BASE_REACHABLE_TIME,
+       NEIGH_VAR_DELAY_PROBE_TIME,
+       NEIGH_VAR_GC_STALETIME,
+       NEIGH_VAR_QUEUE_LEN,
+       NEIGH_VAR_QUEUE_LEN_BYTES,
+       NEIGH_VAR_PROXY_QLEN,
+       NEIGH_VAR_ANYCAST_DELAY,
+       NEIGH_VAR_PROXY_DELAY,
+       NEIGH_VAR_LOCKTIME,
+       NEIGH_VAR_RETRANS_TIME_MS,
+       NEIGH_VAR_BASE_REACHABLE_TIME_MS,
+       NEIGH_VAR_GC_INTERVAL,
+       NEIGH_VAR_GC_THRESH1,
+       NEIGH_VAR_GC_THRESH2,
+       NEIGH_VAR_GC_THRESH3,
+       NEIGH_VAR_MAX
+};
 
 static struct neigh_sysctl_table {
        struct ctl_table_header *sysctl_header;
-       struct ctl_table neigh_vars[NEIGH_VARS_MAX];
+       struct ctl_table neigh_vars[NEIGH_VAR_MAX + 1];
        char *dev_name;
 } neigh_sysctl_template __read_mostly = {
        .neigh_vars = {
-               {
+               [NEIGH_VAR_MCAST_PROBE] = {
                        .procname       = "mcast_solicit",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec,
                },
-               {
+               [NEIGH_VAR_UCAST_PROBE] = {
                        .procname       = "ucast_solicit",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec,
                },
-               {
+               [NEIGH_VAR_APP_PROBE] = {
                        .procname       = "app_solicit",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec,
                },
-               {
+               [NEIGH_VAR_RETRANS_TIME] = {
                        .procname       = "retrans_time",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec_userhz_jiffies,
                },
-               {
+               [NEIGH_VAR_BASE_REACHABLE_TIME] = {
                        .procname       = "base_reachable_time",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec_jiffies,
                },
-               {
+               [NEIGH_VAR_DELAY_PROBE_TIME] = {
                        .procname       = "delay_first_probe_time",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec_jiffies,
                },
-               {
+               [NEIGH_VAR_GC_STALETIME] = {
                        .procname       = "gc_stale_time",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec_jiffies,
                },
-               {
+               [NEIGH_VAR_QUEUE_LEN] = {
                        .procname       = "unres_qlen",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
+                       .proc_handler   = proc_unres_qlen,
+               },
+               [NEIGH_VAR_QUEUE_LEN_BYTES] = {
+                       .procname       = "unres_qlen_bytes",
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
                        .proc_handler   = proc_dointvec,
                },
-               {
+               [NEIGH_VAR_PROXY_QLEN] = {
                        .procname       = "proxy_qlen",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec,
                },
-               {
+               [NEIGH_VAR_ANYCAST_DELAY] = {
                        .procname       = "anycast_delay",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec_userhz_jiffies,
                },
-               {
+               [NEIGH_VAR_PROXY_DELAY] = {
                        .procname       = "proxy_delay",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec_userhz_jiffies,
                },
-               {
+               [NEIGH_VAR_LOCKTIME] = {
                        .procname       = "locktime",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec_userhz_jiffies,
                },
-               {
+               [NEIGH_VAR_RETRANS_TIME_MS] = {
                        .procname       = "retrans_time_ms",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec_ms_jiffies,
                },
-               {
+               [NEIGH_VAR_BASE_REACHABLE_TIME_MS] = {
                        .procname       = "base_reachable_time_ms",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec_ms_jiffies,
                },
-               {
+               [NEIGH_VAR_GC_INTERVAL] = {
                        .procname       = "gc_interval",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec_jiffies,
                },
-               {
+               [NEIGH_VAR_GC_THRESH1] = {
                        .procname       = "gc_thresh1",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec,
                },
-               {
+               [NEIGH_VAR_GC_THRESH2] = {
                        .procname       = "gc_thresh2",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec,
                },
-               {
+               [NEIGH_VAR_GC_THRESH3] = {
                        .procname       = "gc_thresh3",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
@@ -2778,47 +2836,49 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
        if (!t)
                goto err;
 
-       t->neigh_vars[0].data  = &p->mcast_probes;
-       t->neigh_vars[1].data  = &p->ucast_probes;
-       t->neigh_vars[2].data  = &p->app_probes;
-       t->neigh_vars[3].data  = &p->retrans_time;
-       t->neigh_vars[4].data  = &p->base_reachable_time;
-       t->neigh_vars[5].data  = &p->delay_probe_time;
-       t->neigh_vars[6].data  = &p->gc_staletime;
-       t->neigh_vars[7].data  = &p->queue_len;
-       t->neigh_vars[8].data  = &p->proxy_qlen;
-       t->neigh_vars[9].data  = &p->anycast_delay;
-       t->neigh_vars[10].data = &p->proxy_delay;
-       t->neigh_vars[11].data = &p->locktime;
-       t->neigh_vars[12].data  = &p->retrans_time;
-       t->neigh_vars[13].data  = &p->base_reachable_time;
+       t->neigh_vars[NEIGH_VAR_MCAST_PROBE].data  = &p->mcast_probes;
+       t->neigh_vars[NEIGH_VAR_UCAST_PROBE].data  = &p->ucast_probes;
+       t->neigh_vars[NEIGH_VAR_APP_PROBE].data  = &p->app_probes;
+       t->neigh_vars[NEIGH_VAR_RETRANS_TIME].data  = &p->retrans_time;
+       t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].data  = &p->base_reachable_time;
+       t->neigh_vars[NEIGH_VAR_DELAY_PROBE_TIME].data  = &p->delay_probe_time;
+       t->neigh_vars[NEIGH_VAR_GC_STALETIME].data  = &p->gc_staletime;
+       t->neigh_vars[NEIGH_VAR_QUEUE_LEN].data  = &p->queue_len_bytes;
+       t->neigh_vars[NEIGH_VAR_QUEUE_LEN_BYTES].data  = &p->queue_len_bytes;
+       t->neigh_vars[NEIGH_VAR_PROXY_QLEN].data  = &p->proxy_qlen;
+       t->neigh_vars[NEIGH_VAR_ANYCAST_DELAY].data  = &p->anycast_delay;
+       t->neigh_vars[NEIGH_VAR_PROXY_DELAY].data = &p->proxy_delay;
+       t->neigh_vars[NEIGH_VAR_LOCKTIME].data = &p->locktime;
+       t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].data  = &p->retrans_time;
+       t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].data  = &p->base_reachable_time;
 
        if (dev) {
                dev_name_source = dev->name;
                /* Terminate the table early */
-               memset(&t->neigh_vars[14], 0, sizeof(t->neigh_vars[14]));
+               memset(&t->neigh_vars[NEIGH_VAR_GC_INTERVAL], 0,
+                      sizeof(t->neigh_vars[NEIGH_VAR_GC_INTERVAL]));
        } else {
                dev_name_source = neigh_path[NEIGH_CTL_PATH_DEV].procname;
-               t->neigh_vars[14].data = (int *)(p + 1);
-               t->neigh_vars[15].data = (int *)(p + 1) + 1;
-               t->neigh_vars[16].data = (int *)(p + 1) + 2;
-               t->neigh_vars[17].data = (int *)(p + 1) + 3;
+               t->neigh_vars[NEIGH_VAR_GC_INTERVAL].data = (int *)(p + 1);
+               t->neigh_vars[NEIGH_VAR_GC_THRESH1].data = (int *)(p + 1) + 1;
+               t->neigh_vars[NEIGH_VAR_GC_THRESH2].data = (int *)(p + 1) + 2;
+               t->neigh_vars[NEIGH_VAR_GC_THRESH3].data = (int *)(p + 1) + 3;
        }
 
 
        if (handler) {
                /* RetransTime */
-               t->neigh_vars[3].proc_handler = handler;
-               t->neigh_vars[3].extra1 = dev;
+               t->neigh_vars[NEIGH_VAR_RETRANS_TIME].proc_handler = handler;
+               t->neigh_vars[NEIGH_VAR_RETRANS_TIME].extra1 = dev;
                /* ReachableTime */
-               t->neigh_vars[4].proc_handler = handler;
-               t->neigh_vars[4].extra1 = dev;
+               t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler = handler;
+               t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].extra1 = dev;
                /* RetransTime (in milliseconds)*/
-               t->neigh_vars[12].proc_handler = handler;
-               t->neigh_vars[12].extra1 = dev;
+               t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].proc_handler = handler;
+               t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].extra1 = dev;
                /* ReachableTime (in milliseconds) */
-               t->neigh_vars[13].proc_handler = handler;
-               t->neigh_vars[13].extra1 = dev;
+               t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler = handler;
+               t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].extra1 = dev;
        }
 
        t->dev_name = kstrdup(dev_name_source, GFP_KERNEL);
index c71c434..db6c2f8 100644 (file)
@@ -606,9 +606,12 @@ static ssize_t store_rps_map(struct netdev_rx_queue *queue,
        rcu_assign_pointer(queue->rps_map, map);
        spin_unlock(&rps_map_lock);
 
-       if (old_map)
+       if (map)
+               jump_label_inc(&rps_needed);
+       if (old_map) {
                kfree_rcu(old_map, rcu);
-
+               jump_label_dec(&rps_needed);
+       }
        free_cpumask_var(mask);
        return len;
 }
@@ -780,7 +783,7 @@ net_rx_queue_update_kobjects(struct net_device *net, int old_num, int new_num)
 #endif
 }
 
-#ifdef CONFIG_XPS
+#ifdef CONFIG_SYSFS
 /*
  * netdev_queue sysfs structures and functions.
  */
@@ -826,6 +829,23 @@ static const struct sysfs_ops netdev_queue_sysfs_ops = {
        .store = netdev_queue_attr_store,
 };
 
+static ssize_t show_trans_timeout(struct netdev_queue *queue,
+                                 struct netdev_queue_attribute *attribute,
+                                 char *buf)
+{
+       unsigned long trans_timeout;
+
+       spin_lock_irq(&queue->_xmit_lock);
+       trans_timeout = queue->trans_timeout;
+       spin_unlock_irq(&queue->_xmit_lock);
+
+       return sprintf(buf, "%lu", trans_timeout);
+}
+
+static struct netdev_queue_attribute queue_trans_timeout =
+       __ATTR(tx_timeout, S_IRUGO, show_trans_timeout, NULL);
+
+#ifdef CONFIG_XPS
 static inline unsigned int get_netdev_queue_index(struct netdev_queue *queue)
 {
        struct net_device *dev = queue->dev;
@@ -901,7 +921,7 @@ static ssize_t store_xps_map(struct netdev_queue *queue,
        struct xps_map *map, *new_map;
        struct xps_dev_maps *dev_maps, *new_dev_maps;
        int nonempty = 0;
-       int numa_node = -2;
+       int numa_node_id = -2;
 
        if (!capable(CAP_NET_ADMIN))
                return -EPERM;
@@ -944,10 +964,10 @@ static ssize_t store_xps_map(struct netdev_queue *queue,
                need_set = cpumask_test_cpu(cpu, mask) && cpu_online(cpu);
 #ifdef CONFIG_NUMA
                if (need_set) {
-                       if (numa_node == -2)
-                               numa_node = cpu_to_node(cpu);
-                       else if (numa_node != cpu_to_node(cpu))
-                               numa_node = -1;
+                       if (numa_node_id == -2)
+                               numa_node_id = cpu_to_node(cpu);
+                       else if (numa_node_id != cpu_to_node(cpu))
+                               numa_node_id = -1;
                }
 #endif
                if (need_set && pos >= map_len) {
@@ -997,7 +1017,7 @@ static ssize_t store_xps_map(struct netdev_queue *queue,
        if (dev_maps)
                kfree_rcu(dev_maps, rcu);
 
-       netdev_queue_numa_node_write(queue, (numa_node >= 0) ? numa_node :
+       netdev_queue_numa_node_write(queue, (numa_node_id >= 0) ? numa_node_id :
                                            NUMA_NO_NODE);
 
        mutex_unlock(&xps_map_mutex);
@@ -1020,12 +1040,17 @@ error:
 
 static struct netdev_queue_attribute xps_cpus_attribute =
     __ATTR(xps_cpus, S_IRUGO | S_IWUSR, show_xps_map, store_xps_map);
+#endif /* CONFIG_XPS */
 
 static struct attribute *netdev_queue_default_attrs[] = {
+       &queue_trans_timeout.attr,
+#ifdef CONFIG_XPS
        &xps_cpus_attribute.attr,
+#endif
        NULL
 };
 
+#ifdef CONFIG_XPS
 static void netdev_queue_release(struct kobject *kobj)
 {
        struct netdev_queue *queue = to_netdev_queue(kobj);
@@ -1076,10 +1101,13 @@ static void netdev_queue_release(struct kobject *kobj)
        memset(kobj, 0, sizeof(*kobj));
        dev_put(queue->dev);
 }
+#endif /* CONFIG_XPS */
 
 static struct kobj_type netdev_queue_ktype = {
        .sysfs_ops = &netdev_queue_sysfs_ops,
+#ifdef CONFIG_XPS
        .release = netdev_queue_release,
+#endif
        .default_attrs = netdev_queue_default_attrs,
 };
 
@@ -1102,12 +1130,12 @@ static int netdev_queue_add_kobject(struct net_device *net, int index)
 
        return error;
 }
-#endif /* CONFIG_XPS */
+#endif /* CONFIG_SYSFS */
 
 int
 netdev_queue_update_kobjects(struct net_device *net, int old_num, int new_num)
 {
-#ifdef CONFIG_XPS
+#ifdef CONFIG_SYSFS
        int i;
        int error = 0;
 
@@ -1125,14 +1153,14 @@ netdev_queue_update_kobjects(struct net_device *net, int old_num, int new_num)
        return error;
 #else
        return 0;
-#endif
+#endif /* CONFIG_SYSFS */
 }
 
 static int register_queue_kobjects(struct net_device *net)
 {
        int error = 0, txq = 0, rxq = 0, real_rx = 0, real_tx = 0;
 
-#if defined(CONFIG_RPS) || defined(CONFIG_XPS)
+#ifdef CONFIG_SYSFS
        net->queues_kset = kset_create_and_add("queues",
            NULL, &net->dev.kobj);
        if (!net->queues_kset)
@@ -1173,7 +1201,7 @@ static void remove_queue_kobjects(struct net_device *net)
 
        net_rx_queue_update_kobjects(net, real_rx, 0);
        netdev_queue_update_kobjects(net, real_tx, 0);
-#if defined(CONFIG_RPS) || defined(CONFIG_XPS)
+#ifdef CONFIG_SYSFS
        kset_unregister(net->queues_kset);
 #endif
 }
index cf64c1f..1a7d8e2 100644 (file)
@@ -422,6 +422,7 @@ static void arp_reply(struct sk_buff *skb)
        struct sk_buff *send_skb;
        struct netpoll *np, *tmp;
        unsigned long flags;
+       int hlen, tlen;
        int hits = 0;
 
        if (list_empty(&npinfo->rx_np))
@@ -479,8 +480,9 @@ static void arp_reply(struct sk_buff *skb)
                if (tip != np->local_ip)
                        continue;
 
-               send_skb = find_skb(np, size + LL_ALLOCATED_SPACE(np->dev),
-                                   LL_RESERVED_SPACE(np->dev));
+               hlen = LL_RESERVED_SPACE(np->dev);
+               tlen = np->dev->needed_tailroom;
+               send_skb = find_skb(np, size + hlen + tlen, hlen);
                if (!send_skb)
                        continue;
 
diff --git a/net/core/netprio_cgroup.c b/net/core/netprio_cgroup.c
new file mode 100644 (file)
index 0000000..3a9fd48
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+ * net/core/netprio_cgroup.c   Priority Control Group
+ *
+ *             This program is free software; you can redistribute it and/or
+ *             modify it under the terms of the GNU General Public License
+ *             as published by the Free Software Foundation; either version
+ *             2 of the License, or (at your option) any later version.
+ *
+ * Authors:    Neil Horman <nhorman@tuxdriver.com>
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/skbuff.h>
+#include <linux/cgroup.h>
+#include <linux/rcupdate.h>
+#include <linux/atomic.h>
+#include <net/rtnetlink.h>
+#include <net/pkt_cls.h>
+#include <net/sock.h>
+#include <net/netprio_cgroup.h>
+
+static struct cgroup_subsys_state *cgrp_create(struct cgroup_subsys *ss,
+                                              struct cgroup *cgrp);
+static void cgrp_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp);
+static int cgrp_populate(struct cgroup_subsys *ss, struct cgroup *cgrp);
+
+struct cgroup_subsys net_prio_subsys = {
+       .name           = "net_prio",
+       .create         = cgrp_create,
+       .destroy        = cgrp_destroy,
+       .populate       = cgrp_populate,
+#ifdef CONFIG_NETPRIO_CGROUP
+       .subsys_id      = net_prio_subsys_id,
+#endif
+       .module         = THIS_MODULE
+};
+
+#define PRIOIDX_SZ 128
+
+static unsigned long prioidx_map[PRIOIDX_SZ];
+static DEFINE_SPINLOCK(prioidx_map_lock);
+static atomic_t max_prioidx = ATOMIC_INIT(0);
+
+static inline struct cgroup_netprio_state *cgrp_netprio_state(struct cgroup *cgrp)
+{
+       return container_of(cgroup_subsys_state(cgrp, net_prio_subsys_id),
+                           struct cgroup_netprio_state, css);
+}
+
+static int get_prioidx(u32 *prio)
+{
+       unsigned long flags;
+       u32 prioidx;
+
+       spin_lock_irqsave(&prioidx_map_lock, flags);
+       prioidx = find_first_zero_bit(prioidx_map, sizeof(unsigned long) * PRIOIDX_SZ);
+       set_bit(prioidx, prioidx_map);
+       spin_unlock_irqrestore(&prioidx_map_lock, flags);
+       if (prioidx == sizeof(unsigned long) * PRIOIDX_SZ)
+               return -ENOSPC;
+
+       atomic_set(&max_prioidx, prioidx);
+       *prio = prioidx;
+       return 0;
+}
+
+static void put_prioidx(u32 idx)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&prioidx_map_lock, flags);
+       clear_bit(idx, prioidx_map);
+       spin_unlock_irqrestore(&prioidx_map_lock, flags);
+}
+
+static void extend_netdev_table(struct net_device *dev, u32 new_len)
+{
+       size_t new_size = sizeof(struct netprio_map) +
+                          ((sizeof(u32) * new_len));
+       struct netprio_map *new_priomap = kzalloc(new_size, GFP_KERNEL);
+       struct netprio_map *old_priomap;
+       int i;
+
+       old_priomap  = rtnl_dereference(dev->priomap);
+
+       if (!new_priomap) {
+               printk(KERN_WARNING "Unable to alloc new priomap!\n");
+               return;
+       }
+
+       for (i = 0;
+            old_priomap && (i < old_priomap->priomap_len);
+            i++)
+               new_priomap->priomap[i] = old_priomap->priomap[i];
+
+       new_priomap->priomap_len = new_len;
+
+       rcu_assign_pointer(dev->priomap, new_priomap);
+       if (old_priomap)
+               kfree_rcu(old_priomap, rcu);
+}
+
+static void update_netdev_tables(void)
+{
+       struct net_device *dev;
+       u32 max_len = atomic_read(&max_prioidx);
+       struct netprio_map *map;
+
+       rtnl_lock();
+       for_each_netdev(&init_net, dev) {
+               map = rtnl_dereference(dev->priomap);
+               if ((!map) ||
+                   (map->priomap_len < max_len))
+                       extend_netdev_table(dev, max_len);
+       }
+       rtnl_unlock();
+}
+
+static struct cgroup_subsys_state *cgrp_create(struct cgroup_subsys *ss,
+                                                struct cgroup *cgrp)
+{
+       struct cgroup_netprio_state *cs;
+       int ret;
+
+       cs = kzalloc(sizeof(*cs), GFP_KERNEL);
+       if (!cs)
+               return ERR_PTR(-ENOMEM);
+
+       if (cgrp->parent && cgrp_netprio_state(cgrp->parent)->prioidx) {
+               kfree(cs);
+               return ERR_PTR(-EINVAL);
+       }
+
+       ret = get_prioidx(&cs->prioidx);
+       if (ret != 0) {
+               printk(KERN_WARNING "No space in priority index array\n");
+               kfree(cs);
+               return ERR_PTR(ret);
+       }
+
+       return &cs->css;
+}
+
+static void cgrp_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp)
+{
+       struct cgroup_netprio_state *cs;
+       struct net_device *dev;
+       struct netprio_map *map;
+
+       cs = cgrp_netprio_state(cgrp);
+       rtnl_lock();
+       for_each_netdev(&init_net, dev) {
+               map = rtnl_dereference(dev->priomap);
+               if (map)
+                       map->priomap[cs->prioidx] = 0;
+       }
+       rtnl_unlock();
+       put_prioidx(cs->prioidx);
+       kfree(cs);
+}
+
+static u64 read_prioidx(struct cgroup *cgrp, struct cftype *cft)
+{
+       return (u64)cgrp_netprio_state(cgrp)->prioidx;
+}
+
+static int read_priomap(struct cgroup *cont, struct cftype *cft,
+                       struct cgroup_map_cb *cb)
+{
+       struct net_device *dev;
+       u32 prioidx = cgrp_netprio_state(cont)->prioidx;
+       u32 priority;
+       struct netprio_map *map;
+
+       rcu_read_lock();
+       for_each_netdev_rcu(&init_net, dev) {
+               map = rcu_dereference(dev->priomap);
+               priority = map ? map->priomap[prioidx] : 0;
+               cb->fill(cb, dev->name, priority);
+       }
+       rcu_read_unlock();
+       return 0;
+}
+
+static int write_priomap(struct cgroup *cgrp, struct cftype *cft,
+                        const char *buffer)
+{
+       char *devname = kstrdup(buffer, GFP_KERNEL);
+       int ret = -EINVAL;
+       u32 prioidx = cgrp_netprio_state(cgrp)->prioidx;
+       unsigned long priority;
+       char *priostr;
+       struct net_device *dev;
+       struct netprio_map *map;
+
+       if (!devname)
+               return -ENOMEM;
+
+       /*
+        * Minimally sized valid priomap string
+        */
+       if (strlen(devname) < 3)
+               goto out_free_devname;
+
+       priostr = strstr(devname, " ");
+       if (!priostr)
+               goto out_free_devname;
+
+       /*
+        *Separate the devname from the associated priority
+        *and advance the priostr poitner to the priority value
+        */
+       *priostr = '\0';
+       priostr++;
+
+       /*
+        * If the priostr points to NULL, we're at the end of the passed
+        * in string, and its not a valid write
+        */
+       if (*priostr == '\0')
+               goto out_free_devname;
+
+       ret = kstrtoul(priostr, 10, &priority);
+       if (ret < 0)
+               goto out_free_devname;
+
+       ret = -ENODEV;
+
+       dev = dev_get_by_name(&init_net, devname);
+       if (!dev)
+               goto out_free_devname;
+
+       update_netdev_tables();
+       ret = 0;
+       rcu_read_lock();
+       map = rcu_dereference(dev->priomap);
+       if (map)
+               map->priomap[prioidx] = priority;
+       rcu_read_unlock();
+       dev_put(dev);
+
+out_free_devname:
+       kfree(devname);
+       return ret;
+}
+
+static struct cftype ss_files[] = {
+       {
+               .name = "prioidx",
+               .read_u64 = read_prioidx,
+       },
+       {
+               .name = "ifpriomap",
+               .read_map = read_priomap,
+               .write_string = write_priomap,
+       },
+};
+
+static int cgrp_populate(struct cgroup_subsys *ss, struct cgroup *cgrp)
+{
+       return cgroup_add_files(cgrp, ss, ss_files, ARRAY_SIZE(ss_files));
+}
+
+static int netprio_device_event(struct notifier_block *unused,
+                               unsigned long event, void *ptr)
+{
+       struct net_device *dev = ptr;
+       struct netprio_map *old;
+       u32 max_len = atomic_read(&max_prioidx);
+
+       /*
+        * Note this is called with rtnl_lock held so we have update side
+        * protection on our rcu assignments
+        */
+
+       switch (event) {
+
+       case NETDEV_REGISTER:
+               if (max_len)
+                       extend_netdev_table(dev, max_len);
+               break;
+       case NETDEV_UNREGISTER:
+               old = rtnl_dereference(dev->priomap);
+               RCU_INIT_POINTER(dev->priomap, NULL);
+               if (old)
+                       kfree_rcu(old, rcu);
+               break;
+       }
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block netprio_device_notifier = {
+       .notifier_call = netprio_device_event
+};
+
+static int __init init_cgroup_netprio(void)
+{
+       int ret;
+
+       ret = cgroup_load_subsys(&net_prio_subsys);
+       if (ret)
+               goto out;
+#ifndef CONFIG_NETPRIO_CGROUP
+       smp_wmb();
+       net_prio_subsys_id = net_prio_subsys.subsys_id;
+#endif
+
+       register_netdevice_notifier(&netprio_device_notifier);
+
+out:
+       return ret;
+}
+
+static void __exit exit_cgroup_netprio(void)
+{
+       struct netprio_map *old;
+       struct net_device *dev;
+
+       unregister_netdevice_notifier(&netprio_device_notifier);
+
+       cgroup_unload_subsys(&net_prio_subsys);
+
+#ifndef CONFIG_NETPRIO_CGROUP
+       net_prio_subsys_id = -1;
+       synchronize_rcu();
+#endif
+
+       rtnl_lock();
+       for_each_netdev(&init_net, dev) {
+               old = rtnl_dereference(dev->priomap);
+               RCU_INIT_POINTER(dev->priomap, NULL);
+               if (old)
+                       kfree_rcu(old, rcu);
+       }
+       rtnl_unlock();
+}
+
+module_init(init_cgroup_netprio);
+module_exit(exit_cgroup_netprio);
+MODULE_LICENSE("GPL v2");
index 0001c24..aa53a35 100644 (file)
@@ -1304,7 +1304,7 @@ static ssize_t pktgen_if_write(struct file *file,
                scan_ip6(buf, pkt_dev->in6_daddr.s6_addr);
                snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->in6_daddr);
 
-               ipv6_addr_copy(&pkt_dev->cur_in6_daddr, &pkt_dev->in6_daddr);
+               pkt_dev->cur_in6_daddr = pkt_dev->in6_daddr;
 
                if (debug)
                        printk(KERN_DEBUG "pktgen: dst6 set to: %s\n", buf);
@@ -1327,8 +1327,7 @@ static ssize_t pktgen_if_write(struct file *file,
                scan_ip6(buf, pkt_dev->min_in6_daddr.s6_addr);
                snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->min_in6_daddr);
 
-               ipv6_addr_copy(&pkt_dev->cur_in6_daddr,
-                              &pkt_dev->min_in6_daddr);
+               pkt_dev->cur_in6_daddr = pkt_dev->min_in6_daddr;
                if (debug)
                        printk(KERN_DEBUG "pktgen: dst6_min set to: %s\n", buf);
 
@@ -1371,7 +1370,7 @@ static ssize_t pktgen_if_write(struct file *file,
                scan_ip6(buf, pkt_dev->in6_saddr.s6_addr);
                snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->in6_saddr);
 
-               ipv6_addr_copy(&pkt_dev->cur_in6_saddr, &pkt_dev->in6_saddr);
+               pkt_dev->cur_in6_saddr = pkt_dev->in6_saddr;
 
                if (debug)
                        printk(KERN_DEBUG "pktgen: src6 set to: %s\n", buf);
@@ -2079,9 +2078,7 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev)
                                     ifp = ifp->if_next) {
                                        if (ifp->scope == IFA_LINK &&
                                            !(ifp->flags & IFA_F_TENTATIVE)) {
-                                               ipv6_addr_copy(&pkt_dev->
-                                                              cur_in6_saddr,
-                                                              &ifp->addr);
+                                               pkt_dev->cur_in6_saddr = ifp->addr;
                                                err = 0;
                                                break;
                                        }
@@ -2958,8 +2955,8 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
        iph->payload_len = htons(sizeof(struct udphdr) + datalen);
        iph->nexthdr = IPPROTO_UDP;
 
-       ipv6_addr_copy(&iph->daddr, &pkt_dev->cur_in6_daddr);
-       ipv6_addr_copy(&iph->saddr, &pkt_dev->cur_in6_saddr);
+       iph->daddr = pkt_dev->cur_in6_daddr;
+       iph->saddr = pkt_dev->cur_in6_saddr;
 
        skb->mac_header = (skb->network_header - ETH_HLEN -
                           pkt_dev->pkt_overhead);
index 18a3ceb..7dc05ec 100644 (file)
@@ -245,6 +245,55 @@ nodata:
 EXPORT_SYMBOL(__alloc_skb);
 
 /**
+ * build_skb - build a network buffer
+ * @data: data buffer provided by caller
+ *
+ * Allocate a new &sk_buff. Caller provides space holding head and
+ * skb_shared_info. @data must have been allocated by kmalloc()
+ * The return is the new skb buffer.
+ * On a failure the return is %NULL, and @data is not freed.
+ * Notes :
+ *  Before IO, driver allocates only data buffer where NIC put incoming frame
+ *  Driver should add room at head (NET_SKB_PAD) and
+ *  MUST add room at tail (SKB_DATA_ALIGN(skb_shared_info))
+ *  After IO, driver calls build_skb(), to allocate sk_buff and populate it
+ *  before giving packet to stack.
+ *  RX rings only contains data buffers, not full skbs.
+ */
+struct sk_buff *build_skb(void *data)
+{
+       struct skb_shared_info *shinfo;
+       struct sk_buff *skb;
+       unsigned int size;
+
+       skb = kmem_cache_alloc(skbuff_head_cache, GFP_ATOMIC);
+       if (!skb)
+               return NULL;
+
+       size = ksize(data) - SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+
+       memset(skb, 0, offsetof(struct sk_buff, tail));
+       skb->truesize = SKB_TRUESIZE(size);
+       atomic_set(&skb->users, 1);
+       skb->head = data;
+       skb->data = data;
+       skb_reset_tail_pointer(skb);
+       skb->end = skb->tail + size;
+#ifdef NET_SKBUFF_DATA_USES_OFFSET
+       skb->mac_header = ~0U;
+#endif
+
+       /* make sure we initialize shinfo sequentially */
+       shinfo = skb_shinfo(skb);
+       memset(shinfo, 0, offsetof(struct skb_shared_info, dataref));
+       atomic_set(&shinfo->dataref, 1);
+       kmemcheck_annotate_variable(shinfo->destructor_arg);
+
+       return skb;
+}
+EXPORT_SYMBOL(build_skb);
+
+/**
  *     __netdev_alloc_skb - allocate an skbuff for rx on a specific device
  *     @dev: network device to receive on
  *     @length: length to allocate
@@ -2621,7 +2670,7 @@ EXPORT_SYMBOL_GPL(skb_pull_rcsum);
  *     a pointer to the first in a list of new skbs for the segments.
  *     In case of error it returns ERR_PTR(err).
  */
-struct sk_buff *skb_segment(struct sk_buff *skb, u32 features)
+struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
 {
        struct sk_buff *segs = NULL;
        struct sk_buff *tail = NULL;
@@ -3169,6 +3218,26 @@ void skb_tstamp_tx(struct sk_buff *orig_skb,
 }
 EXPORT_SYMBOL_GPL(skb_tstamp_tx);
 
+void skb_complete_wifi_ack(struct sk_buff *skb, bool acked)
+{
+       struct sock *sk = skb->sk;
+       struct sock_exterr_skb *serr;
+       int err;
+
+       skb->wifi_acked_valid = 1;
+       skb->wifi_acked = acked;
+
+       serr = SKB_EXT_ERR(skb);
+       memset(serr, 0, sizeof(*serr));
+       serr->ee.ee_errno = ENOMSG;
+       serr->ee.ee_origin = SO_EE_ORIGIN_TXSTATUS;
+
+       err = sock_queue_err_skb(sk, skb);
+       if (err)
+               kfree_skb(skb);
+}
+EXPORT_SYMBOL_GPL(skb_complete_wifi_ack);
+
 
 /**
  * skb_partial_csum_set - set up and verify partial csum values for packet
index 4ed7b1d..1606913 100644 (file)
 #include <net/xfrm.h>
 #include <linux/ipsec.h>
 #include <net/cls_cgroup.h>
+#include <net/netprio_cgroup.h>
 
 #include <linux/filter.h>
 
@@ -221,10 +222,16 @@ __u32 sysctl_rmem_default __read_mostly = SK_RMEM_MAX;
 int sysctl_optmem_max __read_mostly = sizeof(unsigned long)*(2*UIO_MAXIOV+512);
 EXPORT_SYMBOL(sysctl_optmem_max);
 
-#if defined(CONFIG_CGROUPS) && !defined(CONFIG_NET_CLS_CGROUP)
+#if defined(CONFIG_CGROUPS)
+#if !defined(CONFIG_NET_CLS_CGROUP)
 int net_cls_subsys_id = -1;
 EXPORT_SYMBOL_GPL(net_cls_subsys_id);
 #endif
+#if !defined(CONFIG_NETPRIO_CGROUP)
+int net_prio_subsys_id = -1;
+EXPORT_SYMBOL_GPL(net_prio_subsys_id);
+#endif
+#endif
 
 static int sock_set_timeout(long *timeo_p, char __user *optval, int optlen)
 {
@@ -740,6 +747,11 @@ set_rcvbuf:
        case SO_RXQ_OVFL:
                sock_valbool_flag(sk, SOCK_RXQ_OVFL, valbool);
                break;
+
+       case SO_WIFI_STATUS:
+               sock_valbool_flag(sk, SOCK_WIFI_STATUS, valbool);
+               break;
+
        default:
                ret = -ENOPROTOOPT;
                break;
@@ -961,6 +973,10 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
                v.val = !!sock_flag(sk, SOCK_RXQ_OVFL);
                break;
 
+       case SO_WIFI_STATUS:
+               v.val = !!sock_flag(sk, SOCK_WIFI_STATUS);
+               break;
+
        default:
                return -ENOPROTOOPT;
        }
@@ -1111,6 +1127,18 @@ void sock_update_classid(struct sock *sk)
                sk->sk_classid = classid;
 }
 EXPORT_SYMBOL(sock_update_classid);
+
+void sock_update_netprioidx(struct sock *sk)
+{
+       struct cgroup_netprio_state *state;
+       if (in_interrupt())
+               return;
+       rcu_read_lock();
+       state = task_netprio_state(current);
+       sk->sk_cgrp_prioidx = state ? state->prioidx : 0;
+       rcu_read_unlock();
+}
+EXPORT_SYMBOL_GPL(sock_update_netprioidx);
 #endif
 
 /**
@@ -1138,6 +1166,7 @@ struct sock *sk_alloc(struct net *net, int family, gfp_t priority,
                atomic_set(&sk->sk_wmem_alloc, 1);
 
                sock_update_classid(sk);
+               sock_update_netprioidx(sk);
        }
 
        return sk;
@@ -1204,7 +1233,14 @@ void sk_release_kernel(struct sock *sk)
 }
 EXPORT_SYMBOL(sk_release_kernel);
 
-struct sock *sk_clone(const struct sock *sk, const gfp_t priority)
+/**
+ *     sk_clone_lock - clone a socket, and lock its clone
+ *     @sk: the socket to clone
+ *     @priority: for allocation (%GFP_KERNEL, %GFP_ATOMIC, etc)
+ *
+ *     Caller must unlock socket even in error path (bh_unlock_sock(newsk))
+ */
+struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)
 {
        struct sock *newsk;
 
@@ -1297,7 +1333,7 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority)
 out:
        return newsk;
 }
-EXPORT_SYMBOL_GPL(sk_clone);
+EXPORT_SYMBOL_GPL(sk_clone_lock);
 
 void sk_setup_caps(struct sock *sk, struct dst_entry *dst)
 {
index 77a65f0..d05559d 100644 (file)
@@ -68,8 +68,13 @@ static int rps_sock_flow_sysctl(ctl_table *table, int write,
 
                if (sock_table != orig_sock_table) {
                        rcu_assign_pointer(rps_sock_flow_table, sock_table);
-                       synchronize_rcu();
-                       vfree(orig_sock_table);
+                       if (sock_table)
+                               jump_label_inc(&rps_needed);
+                       if (orig_sock_table) {
+                               jump_label_dec(&rps_needed);
+                               synchronize_rcu();
+                               vfree(orig_sock_table);
+                       }
                }
        }
 
index 17ee85c..ce903f7 100644 (file)
@@ -150,8 +150,8 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                         */
                        memset(&fl6, 0, sizeof(fl6));
                        fl6.flowi6_proto = IPPROTO_DCCP;
-                       ipv6_addr_copy(&fl6.daddr, &np->daddr);
-                       ipv6_addr_copy(&fl6.saddr, &np->saddr);
+                       fl6.daddr = np->daddr;
+                       fl6.saddr = np->saddr;
                        fl6.flowi6_oif = sk->sk_bound_dev_if;
                        fl6.fl6_dport = inet->inet_dport;
                        fl6.fl6_sport = inet->inet_sport;
@@ -244,8 +244,8 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,
 
        memset(&fl6, 0, sizeof(fl6));
        fl6.flowi6_proto = IPPROTO_DCCP;
-       ipv6_addr_copy(&fl6.daddr, &ireq6->rmt_addr);
-       ipv6_addr_copy(&fl6.saddr, &ireq6->loc_addr);
+       fl6.daddr = ireq6->rmt_addr;
+       fl6.saddr = ireq6->loc_addr;
        fl6.flowlabel = 0;
        fl6.flowi6_oif = ireq6->iif;
        fl6.fl6_dport = inet_rsk(req)->rmt_port;
@@ -270,7 +270,7 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,
                dh->dccph_checksum = dccp_v6_csum_finish(skb,
                                                         &ireq6->loc_addr,
                                                         &ireq6->rmt_addr);
-               ipv6_addr_copy(&fl6.daddr, &ireq6->rmt_addr);
+               fl6.daddr = ireq6->rmt_addr;
                err = ip6_xmit(sk, skb, &fl6, opt, np->tclass);
                err = net_xmit_eval(err);
        }
@@ -313,8 +313,8 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
                                                            &rxip6h->daddr);
 
        memset(&fl6, 0, sizeof(fl6));
-       ipv6_addr_copy(&fl6.daddr, &rxip6h->saddr);
-       ipv6_addr_copy(&fl6.saddr, &rxip6h->daddr);
+       fl6.daddr = rxip6h->saddr;
+       fl6.saddr = rxip6h->daddr;
 
        fl6.flowi6_proto = IPPROTO_DCCP;
        fl6.flowi6_oif = inet6_iif(rxskb);
@@ -419,8 +419,8 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
                goto drop_and_free;
 
        ireq6 = inet6_rsk(req);
-       ipv6_addr_copy(&ireq6->rmt_addr, &ipv6_hdr(skb)->saddr);
-       ipv6_addr_copy(&ireq6->loc_addr, &ipv6_hdr(skb)->daddr);
+       ireq6->rmt_addr = ipv6_hdr(skb)->saddr;
+       ireq6->loc_addr = ipv6_hdr(skb)->daddr;
 
        if (ipv6_opt_accepted(sk, skb) ||
            np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
@@ -491,7 +491,7 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
 
                ipv6_addr_set_v4mapped(newinet->inet_saddr, &newnp->saddr);
 
-               ipv6_addr_copy(&newnp->rcv_saddr, &newnp->saddr);
+               newnp->rcv_saddr = newnp->saddr;
 
                inet_csk(newsk)->icsk_af_ops = &dccp_ipv6_mapped;
                newsk->sk_backlog_rcv = dccp_v4_do_rcv;
@@ -526,9 +526,9 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
 
                memset(&fl6, 0, sizeof(fl6));
                fl6.flowi6_proto = IPPROTO_DCCP;
-               ipv6_addr_copy(&fl6.daddr, &ireq6->rmt_addr);
+               fl6.daddr = ireq6->rmt_addr;
                final_p = fl6_update_dst(&fl6, opt, &final);
-               ipv6_addr_copy(&fl6.saddr, &ireq6->loc_addr);
+               fl6.saddr = ireq6->loc_addr;
                fl6.flowi6_oif = sk->sk_bound_dev_if;
                fl6.fl6_dport = inet_rsk(req)->rmt_port;
                fl6.fl6_sport = inet_rsk(req)->loc_port;
@@ -559,9 +559,9 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
 
        memcpy(newnp, np, sizeof(struct ipv6_pinfo));
 
-       ipv6_addr_copy(&newnp->daddr, &ireq6->rmt_addr);
-       ipv6_addr_copy(&newnp->saddr, &ireq6->loc_addr);
-       ipv6_addr_copy(&newnp->rcv_saddr, &ireq6->loc_addr);
+       newnp->daddr = ireq6->rmt_addr;
+       newnp->saddr = ireq6->loc_addr;
+       newnp->rcv_saddr = ireq6->loc_addr;
        newsk->sk_bound_dev_if = ireq6->iif;
 
        /* Now IPv6 options...
@@ -877,7 +877,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
                        flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);
                        if (flowlabel == NULL)
                                return -EINVAL;
-                       ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst);
+                       usin->sin6_addr = flowlabel->dst;
                        fl6_sock_release(flowlabel);
                }
        }
@@ -910,7 +910,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
                        return -EINVAL;
        }
 
-       ipv6_addr_copy(&np->daddr, &usin->sin6_addr);
+       np->daddr = usin->sin6_addr;
        np->flow_label = fl6.flowlabel;
 
        /*
@@ -949,8 +949,8 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
                saddr = &np->rcv_saddr;
 
        fl6.flowi6_proto = IPPROTO_DCCP;
-       ipv6_addr_copy(&fl6.daddr, &np->daddr);
-       ipv6_addr_copy(&fl6.saddr, saddr ? saddr : &np->saddr);
+       fl6.daddr = np->daddr;
+       fl6.saddr = saddr ? *saddr : np->saddr;
        fl6.flowi6_oif = sk->sk_bound_dev_if;
        fl6.fl6_dport = usin->sin6_port;
        fl6.fl6_sport = inet->inet_sport;
@@ -966,11 +966,11 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
 
        if (saddr == NULL) {
                saddr = &fl6.saddr;
-               ipv6_addr_copy(&np->rcv_saddr, saddr);
+               np->rcv_saddr = *saddr;
        }
 
        /* set the source address */
-       ipv6_addr_copy(&np->saddr, saddr);
+       np->saddr = *saddr;
        inet->inet_rcv_saddr = LOOPBACK4_IPV6;
 
        __ip6_dst_store(sk, dst, NULL, NULL);
index d7041a0..b50d5fd 100644 (file)
@@ -60,8 +60,8 @@ void dccp_time_wait(struct sock *sk, int state, int timeo)
 
                        tw->tw_ipv6_offset = inet6_tw_offset(sk->sk_prot);
                        tw6 = inet6_twsk((struct sock *)tw);
-                       ipv6_addr_copy(&tw6->tw_v6_daddr, &np->daddr);
-                       ipv6_addr_copy(&tw6->tw_v6_rcv_saddr, &np->rcv_saddr);
+                       tw6->tw_v6_daddr = np->daddr;
+                       tw6->tw_v6_rcv_saddr = np->rcv_saddr;
                        tw->tw_ipv6only = np->ipv6only;
                }
 #endif
@@ -100,7 +100,7 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
         *   (* Generate a new socket and switch to that socket *)
         *   Set S := new socket for this port pair
         */
-       struct sock *newsk = inet_csk_clone(sk, req, GFP_ATOMIC);
+       struct sock *newsk = inet_csk_clone_lock(sk, req, GFP_ATOMIC);
 
        if (newsk != NULL) {
                struct dccp_request_sock *dreq = dccp_rsk(req);
index 7f0eb08..3532ac6 100644 (file)
@@ -107,7 +107,7 @@ struct neigh_table dn_neigh_table = {
                .gc_staletime = 60 * HZ,
                .reachable_time =               30 * HZ,
                .delay_probe_time =     5 * HZ,
-               .queue_len =            3,
+               .queue_len_bytes =      64*1024,
                .ucast_probes = 0,
                .app_probes =           0,
                .mcast_probes = 0,
index 1c1f26c..7e717cb 100644 (file)
@@ -322,6 +322,7 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock,
                /* Real hardware Econet.  We're not worthy etc. */
 #ifdef CONFIG_ECONET_NATIVE
                unsigned short proto = 0;
+               int hlen, tlen;
                int res;
 
                if (len + 15 > dev->mtu) {
@@ -331,12 +332,14 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock,
 
                dev_hold(dev);
 
-               skb = sock_alloc_send_skb(sk, len + LL_ALLOCATED_SPACE(dev),
+               hlen = LL_RESERVED_SPACE(dev);
+               tlen = dev->needed_tailroom;
+               skb = sock_alloc_send_skb(sk, len + hlen + tlen,
                                          msg->msg_flags & MSG_DONTWAIT, &err);
                if (skb == NULL)
                        goto out_unlock;
 
-               skb_reserve(skb, LL_RESERVED_SPACE(dev));
+               skb_reserve(skb, hlen);
                skb_reset_network_header(skb);
 
                eb = (struct ec_cb *)&skb->cb;
index 19d6aef..e4ecc1e 100644 (file)
@@ -50,8 +50,6 @@
  * SUCH DAMAGE.
  */
 
-#define DEBUG
-
 #include <linux/bitops.h>
 #include <linux/if_arp.h>
 #include <linux/module.h>
@@ -113,6 +111,20 @@ struct lowpan_dev_record {
        struct list_head list;
 };
 
+struct lowpan_fragment {
+       struct sk_buff          *skb;           /* skb to be assembled */
+       spinlock_t              lock;           /* concurency lock */
+       u16                     length;         /* length to be assemled */
+       u32                     bytes_rcv;      /* bytes received */
+       u16                     tag;            /* current fragment tag */
+       struct timer_list       timer;          /* assembling timer */
+       struct list_head        list;           /* fragments list */
+};
+
+static unsigned short fragment_tag;
+static LIST_HEAD(lowpan_fragments);
+spinlock_t flist_lock;
+
 static inline struct
 lowpan_dev_info *lowpan_dev_info(const struct net_device *dev)
 {
@@ -234,6 +246,50 @@ lowpan_uncompress_addr(struct sk_buff *skb, struct in6_addr *ipaddr,
        return 0;
 }
 
+static void
+lowpan_compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb)
+{
+       struct udphdr *uh = udp_hdr(skb);
+
+       pr_debug("(%s): UDP header compression\n", __func__);
+
+       if (((uh->source & LOWPAN_NHC_UDP_4BIT_MASK) ==
+                               LOWPAN_NHC_UDP_4BIT_PORT) &&
+           ((uh->dest & LOWPAN_NHC_UDP_4BIT_MASK) ==
+                               LOWPAN_NHC_UDP_4BIT_PORT)) {
+               pr_debug("(%s): both ports compression to 4 bits\n", __func__);
+               **hc06_ptr = LOWPAN_NHC_UDP_CS_P_11;
+               **(hc06_ptr + 1) = /* subtraction is faster */
+                  (u8)((uh->dest - LOWPAN_NHC_UDP_4BIT_PORT) +
+                      ((uh->source & LOWPAN_NHC_UDP_4BIT_PORT) << 4));
+               *hc06_ptr += 2;
+       } else if ((uh->dest & LOWPAN_NHC_UDP_8BIT_MASK) ==
+                       LOWPAN_NHC_UDP_8BIT_PORT) {
+               pr_debug("(%s): remove 8 bits of dest\n", __func__);
+               **hc06_ptr = LOWPAN_NHC_UDP_CS_P_01;
+               memcpy(*hc06_ptr + 1, &uh->source, 2);
+               **(hc06_ptr + 3) = (u8)(uh->dest - LOWPAN_NHC_UDP_8BIT_PORT);
+               *hc06_ptr += 4;
+       } else if ((uh->source & LOWPAN_NHC_UDP_8BIT_MASK) ==
+                       LOWPAN_NHC_UDP_8BIT_PORT) {
+               pr_debug("(%s): remove 8 bits of source\n", __func__);
+               **hc06_ptr = LOWPAN_NHC_UDP_CS_P_10;
+               memcpy(*hc06_ptr + 1, &uh->dest, 2);
+               **(hc06_ptr + 3) = (u8)(uh->source - LOWPAN_NHC_UDP_8BIT_PORT);
+               *hc06_ptr += 4;
+       } else {
+               pr_debug("(%s): can't compress header\n", __func__);
+               **hc06_ptr = LOWPAN_NHC_UDP_CS_P_00;
+               memcpy(*hc06_ptr + 1, &uh->source, 2);
+               memcpy(*hc06_ptr + 3, &uh->dest, 2);
+               *hc06_ptr += 5;
+       }
+
+       /* checksum is always inline */
+       memcpy(*hc06_ptr, &uh->check, 2);
+       *hc06_ptr += 2;
+}
+
 static u8 lowpan_fetch_skb_u8(struct sk_buff *skb)
 {
        u8 ret;
@@ -244,6 +300,73 @@ static u8 lowpan_fetch_skb_u8(struct sk_buff *skb)
        return ret;
 }
 
+static u16 lowpan_fetch_skb_u16(struct sk_buff *skb)
+{
+       u16 ret;
+
+       BUG_ON(!pskb_may_pull(skb, 2));
+
+       ret = skb->data[0] | (skb->data[1] << 8);
+       skb_pull(skb, 2);
+       return ret;
+}
+
+static int
+lowpan_uncompress_udp_header(struct sk_buff *skb)
+{
+       struct udphdr *uh = udp_hdr(skb);
+       u8 tmp;
+
+       tmp = lowpan_fetch_skb_u8(skb);
+
+       if ((tmp & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) {
+               pr_debug("(%s): UDP header uncompression\n", __func__);
+               switch (tmp & LOWPAN_NHC_UDP_CS_P_11) {
+               case LOWPAN_NHC_UDP_CS_P_00:
+                       memcpy(&uh->source, &skb->data[0], 2);
+                       memcpy(&uh->dest, &skb->data[2], 2);
+                       skb_pull(skb, 4);
+                       break;
+               case LOWPAN_NHC_UDP_CS_P_01:
+                       memcpy(&uh->source, &skb->data[0], 2);
+                       uh->dest =
+                          skb->data[2] + LOWPAN_NHC_UDP_8BIT_PORT;
+                       skb_pull(skb, 3);
+                       break;
+               case LOWPAN_NHC_UDP_CS_P_10:
+                       uh->source = skb->data[0] + LOWPAN_NHC_UDP_8BIT_PORT;
+                       memcpy(&uh->dest, &skb->data[1], 2);
+                       skb_pull(skb, 3);
+                       break;
+               case LOWPAN_NHC_UDP_CS_P_11:
+                       uh->source =
+                          LOWPAN_NHC_UDP_4BIT_PORT + (skb->data[0] >> 4);
+                       uh->dest =
+                          LOWPAN_NHC_UDP_4BIT_PORT + (skb->data[0] & 0x0f);
+                       skb_pull(skb, 1);
+                       break;
+               default:
+                       pr_debug("(%s) ERROR: unknown UDP format\n", __func__);
+                       goto err;
+                       break;
+               }
+
+               pr_debug("(%s): uncompressed UDP ports: src = %d, dst = %d\n",
+                                       __func__, uh->source, uh->dest);
+
+               /* copy checksum */
+               memcpy(&uh->check, &skb->data[0], 2);
+               skb_pull(skb, 2);
+       } else {
+               pr_debug("(%s): ERROR: unsupported NH format\n", __func__);
+               goto err;
+       }
+
+       return 0;
+err:
+       return -EINVAL;
+}
+
 static int lowpan_header_create(struct sk_buff *skb,
                           struct net_device *dev,
                           unsigned short type, const void *_daddr,
@@ -342,8 +465,6 @@ static int lowpan_header_create(struct sk_buff *skb,
        if (hdr->nexthdr == UIP_PROTO_UDP)
                iphc0 |= LOWPAN_IPHC_NH_C;
 
-/* TODO: next header compression */
-
        if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) {
                *hc06_ptr = hdr->nexthdr;
                hc06_ptr += 1;
@@ -431,8 +552,9 @@ static int lowpan_header_create(struct sk_buff *skb,
                }
        }
 
-       /* TODO: UDP header compression */
-       /* TODO: Next Header compression */
+       /* UDP header compression */
+       if (hdr->nexthdr == UIP_PROTO_UDP)
+               lowpan_compress_udp_header(&hc06_ptr, skb);
 
        head[0] = iphc0;
        head[1] = iphc1;
@@ -467,6 +589,7 @@ static int lowpan_header_create(struct sk_buff *skb,
                memcpy(&(sa.hwaddr), saddr, 8);
 
                mac_cb(skb)->flags = IEEE802154_FC_TYPE_DATA;
+
                return dev_hard_header(skb, lowpan_dev_info(dev)->real_dev,
                                type, (void *)&da, (void *)&sa, skb->len);
        }
@@ -511,6 +634,21 @@ static int lowpan_skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr)
        return stat;
 }
 
+static void lowpan_fragment_timer_expired(unsigned long entry_addr)
+{
+       struct lowpan_fragment *entry = (struct lowpan_fragment *)entry_addr;
+
+       pr_debug("%s: timer expired for frame with tag %d\n", __func__,
+                                                               entry->tag);
+
+       spin_lock(&flist_lock);
+       list_del(&entry->list);
+       spin_unlock(&flist_lock);
+
+       dev_kfree_skb(entry->skb);
+       kfree(entry);
+}
+
 static int
 lowpan_process_data(struct sk_buff *skb)
 {
@@ -525,6 +663,107 @@ lowpan_process_data(struct sk_buff *skb)
        if (skb->len < 2)
                goto drop;
        iphc0 = lowpan_fetch_skb_u8(skb);
+
+       /* fragments assembling */
+       switch (iphc0 & LOWPAN_DISPATCH_MASK) {
+       case LOWPAN_DISPATCH_FRAG1:
+       case LOWPAN_DISPATCH_FRAGN:
+       {
+               struct lowpan_fragment *frame;
+               u8 len, offset;
+               u16 tag;
+               bool found = false;
+
+               len = lowpan_fetch_skb_u8(skb); /* frame length */
+               tag = lowpan_fetch_skb_u16(skb);
+
+               /*
+                * check if frame assembling with the same tag is
+                * already in progress
+                */
+               spin_lock(&flist_lock);
+
+               list_for_each_entry(frame, &lowpan_fragments, list)
+                       if (frame->tag == tag) {
+                               found = true;
+                               break;
+                       }
+
+               /* alloc new frame structure */
+               if (!found) {
+                       frame = kzalloc(sizeof(struct lowpan_fragment),
+                                                               GFP_ATOMIC);
+                       if (!frame)
+                               goto unlock_and_drop;
+
+                       INIT_LIST_HEAD(&frame->list);
+
+                       frame->length = (iphc0 & 7) | (len << 3);
+                       frame->tag = tag;
+
+                       /* allocate buffer for frame assembling */
+                       frame->skb = alloc_skb(frame->length +
+                                       sizeof(struct ipv6hdr), GFP_ATOMIC);
+
+                       if (!frame->skb) {
+                               kfree(frame);
+                               goto unlock_and_drop;
+                       }
+
+                       frame->skb->priority = skb->priority;
+                       frame->skb->dev = skb->dev;
+
+                       /* reserve headroom for uncompressed ipv6 header */
+                       skb_reserve(frame->skb, sizeof(struct ipv6hdr));
+                       skb_put(frame->skb, frame->length);
+
+                       init_timer(&frame->timer);
+                       /* time out is the same as for ipv6 - 60 sec */
+                       frame->timer.expires = jiffies + LOWPAN_FRAG_TIMEOUT;
+                       frame->timer.data = (unsigned long)frame;
+                       frame->timer.function = lowpan_fragment_timer_expired;
+
+                       add_timer(&frame->timer);
+
+                       list_add_tail(&frame->list, &lowpan_fragments);
+               }
+
+               if ((iphc0 & LOWPAN_DISPATCH_MASK) == LOWPAN_DISPATCH_FRAG1)
+                       goto unlock_and_drop;
+
+               offset = lowpan_fetch_skb_u8(skb); /* fetch offset */
+
+               /* if payload fits buffer, copy it */
+               if (likely((offset * 8 + skb->len) <= frame->length))
+                       skb_copy_to_linear_data_offset(frame->skb, offset * 8,
+                                                       skb->data, skb->len);
+               else
+                       goto unlock_and_drop;
+
+               frame->bytes_rcv += skb->len;
+
+               /* frame assembling complete */
+               if ((frame->bytes_rcv == frame->length) &&
+                    frame->timer.expires > jiffies) {
+                       /* if timer haven't expired - first of all delete it */
+                       del_timer(&frame->timer);
+                       list_del(&frame->list);
+                       spin_unlock(&flist_lock);
+
+                       dev_kfree_skb(skb);
+                       skb = frame->skb;
+                       kfree(frame);
+                       iphc0 = lowpan_fetch_skb_u8(skb);
+                       break;
+               }
+               spin_unlock(&flist_lock);
+
+               return kfree_skb(skb), 0;
+       }
+       default:
+               break;
+       }
+
        iphc1 = lowpan_fetch_skb_u8(skb);
 
        _saddr = mac_cb(skb)->sa.hwaddr;
@@ -659,7 +898,10 @@ lowpan_process_data(struct sk_buff *skb)
                        goto drop;
        }
 
-       /* TODO: UDP header parse */
+       /* UDP data uncompression */
+       if (iphc0 & LOWPAN_IPHC_NH_C)
+               if (lowpan_uncompress_udp_header(skb))
+                       goto drop;
 
        /* Not fragmented package */
        hdr.payload_len = htons(skb->len);
@@ -674,6 +916,9 @@ lowpan_process_data(struct sk_buff *skb)
        lowpan_raw_dump_table(__func__, "raw header dump", (u8 *)&hdr,
                                                        sizeof(hdr));
        return lowpan_skb_deliver(skb, &hdr);
+
+unlock_and_drop:
+       spin_unlock(&flist_lock);
 drop:
        kfree_skb(skb);
        return -EINVAL;
@@ -692,18 +937,115 @@ static int lowpan_set_address(struct net_device *dev, void *p)
        return 0;
 }
 
+static int lowpan_get_mac_header_length(struct sk_buff *skb)
+{
+       /*
+        * Currently long addressing mode is supported only, so the overall
+        * header size is 21:
+        * FC SeqNum DPAN DA  SA  Sec
+        * 2  +  1  +  2 + 8 + 8 + 0  = 21
+        */
+       return 21;
+}
+
+static int
+lowpan_fragment_xmit(struct sk_buff *skb, u8 *head,
+                       int mlen, int plen, int offset)
+{
+       struct sk_buff *frag;
+       int hlen, ret;
+
+       /* if payload length is zero, therefore it's a first fragment */
+       hlen = (plen == 0 ? LOWPAN_FRAG1_HEAD_SIZE :  LOWPAN_FRAGN_HEAD_SIZE);
+
+       lowpan_raw_dump_inline(__func__, "6lowpan fragment header", head, hlen);
+
+       frag = dev_alloc_skb(hlen + mlen + plen + IEEE802154_MFR_SIZE);
+       if (!frag)
+               return -ENOMEM;
+
+       frag->priority = skb->priority;
+       frag->dev = skb->dev;
+
+       /* copy header, MFR and payload */
+       memcpy(skb_put(frag, mlen), skb->data, mlen);
+       memcpy(skb_put(frag, hlen), head, hlen);
+
+       if (plen)
+               skb_copy_from_linear_data_offset(skb, offset + mlen,
+                                       skb_put(frag, plen), plen);
+
+       lowpan_raw_dump_table(__func__, " raw fragment dump", frag->data,
+                                                               frag->len);
+
+       ret = dev_queue_xmit(frag);
+
+       return ret;
+}
+
+static int
+lowpan_skb_fragmentation(struct sk_buff *skb)
+{
+       int  err, header_length, payload_length, tag, offset = 0;
+       u8 head[5];
+
+       header_length = lowpan_get_mac_header_length(skb);
+       payload_length = skb->len - header_length;
+       tag = fragment_tag++;
+
+       /* first fragment header */
+       head[0] = LOWPAN_DISPATCH_FRAG1 | (payload_length & 0x7);
+       head[1] = (payload_length >> 3) & 0xff;
+       head[2] = tag & 0xff;
+       head[3] = tag >> 8;
+
+       err = lowpan_fragment_xmit(skb, head, header_length, 0, 0);
+
+       /* next fragment header */
+       head[0] &= ~LOWPAN_DISPATCH_FRAG1;
+       head[0] |= LOWPAN_DISPATCH_FRAGN;
+
+       while ((payload_length - offset > 0) && (err >= 0)) {
+               int len = LOWPAN_FRAG_SIZE;
+
+               head[4] = offset / 8;
+
+               if (payload_length - offset < len)
+                       len = payload_length - offset;
+
+               err = lowpan_fragment_xmit(skb, head, header_length,
+                                                       len, offset);
+               offset += len;
+       }
+
+       return err;
+}
+
 static netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-       int err = 0;
+       int err = -1;
 
        pr_debug("(%s): package xmit\n", __func__);
 
        skb->dev = lowpan_dev_info(dev)->real_dev;
        if (skb->dev == NULL) {
                pr_debug("(%s) ERROR: no real wpan device found\n", __func__);
-               dev_kfree_skb(skb);
-       } else
+               goto error;
+       }
+
+       if (skb->len <= IEEE802154_MTU) {
                err = dev_queue_xmit(skb);
+               goto out;
+       }
+
+       pr_debug("(%s): frame is too big, fragmentation is needed\n",
+                                                               __func__);
+       err = lowpan_skb_fragmentation(skb);
+error:
+       dev_kfree_skb(skb);
+out:
+       if (err < 0)
+               pr_debug("(%s): ERROR: xmit failed\n", __func__);
 
        return (err < 0 ? NETDEV_TX_BUSY : NETDEV_TX_OK);
 }
@@ -730,13 +1072,12 @@ static void lowpan_setup(struct net_device *dev)
        dev->addr_len           = IEEE802154_ADDR_LEN;
        memset(dev->broadcast, 0xff, IEEE802154_ADDR_LEN);
        dev->type               = ARPHRD_IEEE802154;
-       dev->features           = NETIF_F_NO_CSUM;
        /* Frame Control + Sequence Number + Address fields + Security Header */
        dev->hard_header_len    = 2 + 1 + 20 + 14;
        dev->needed_tailroom    = 2; /* FCS */
        dev->mtu                = 1281;
        dev->tx_queue_len       = 0;
-       dev->flags              = IFF_NOARP | IFF_BROADCAST;
+       dev->flags              = IFF_BROADCAST | IFF_MULTICAST;
        dev->watchdog_timeo     = 0;
 
        dev->netdev_ops         = &lowpan_netdev_ops;
@@ -765,8 +1106,15 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
                goto drop;
 
        /* check that it's our buffer */
-       if ((skb->data[0] & 0xe0) == 0x60)
+       switch (skb->data[0] & 0xe0) {
+       case LOWPAN_DISPATCH_IPHC:      /* ipv6 datagram */
+       case LOWPAN_DISPATCH_FRAG1:     /* first fragment header */
+       case LOWPAN_DISPATCH_FRAGN:     /* next fragments headers */
                lowpan_process_data(skb);
+               break;
+       default:
+               break;
+       }
 
        return NET_RX_SUCCESS;
 
index 5d8cf80..aeff3f3 100644 (file)
 #define LOWPAN_DISPATCH_FRAG1  0xc0 /* 11000xxx */
 #define LOWPAN_DISPATCH_FRAGN  0xe0 /* 11100xxx */
 
+#define LOWPAN_DISPATCH_MASK   0xf8 /* 11111000 */
+
+#define LOWPAN_FRAG_TIMEOUT    (HZ * 60)       /* time-out 60 sec */
+
+#define LOWPAN_FRAG1_HEAD_SIZE 0x4
+#define LOWPAN_FRAGN_HEAD_SIZE 0x5
+
+/*
+ * According IEEE802.15.4 standard:
+ *   - MTU is 127 octets
+ *   - maximum MHR size is 37 octets
+ *   - MFR size is 2 octets
+ *
+ * so minimal payload size that we may guarantee is:
+ *   MTU - MHR - MFR = 88 octets
+ */
+#define LOWPAN_FRAG_SIZE       88
+
 /*
  * Values of fields within the IPHC encoding first byte
  * (C stands for compressed and I for inline)
 #define LOWPAN_NHC_UDP_CHECKSUMC       0x04
 #define LOWPAN_NHC_UDP_CHECKSUMI       0x00
 
+#define LOWPAN_NHC_UDP_4BIT_PORT       0xF0B0
+#define LOWPAN_NHC_UDP_4BIT_MASK       0xFFF0
+#define LOWPAN_NHC_UDP_8BIT_PORT       0xF000
+#define LOWPAN_NHC_UDP_8BIT_MASK       0xFF00
+
 /* values for port compression, _with checksum_ ie bit 5 set to 0 */
 #define LOWPAN_NHC_UDP_CS_P_00 0xF0 /* all inline */
 #define LOWPAN_NHC_UDP_CS_P_01 0xF1 /* source 16bit inline,
index faecf64..1b09eaa 100644 (file)
@@ -209,6 +209,7 @@ static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk,
        unsigned mtu;
        struct sk_buff *skb;
        struct dgram_sock *ro = dgram_sk(sk);
+       int hlen, tlen;
        int err;
 
        if (msg->msg_flags & MSG_OOB) {
@@ -229,13 +230,15 @@ static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk,
        mtu = dev->mtu;
        pr_debug("name = %s, mtu = %u\n", dev->name, mtu);
 
-       skb = sock_alloc_send_skb(sk, LL_ALLOCATED_SPACE(dev) + size,
+       hlen = LL_RESERVED_SPACE(dev);
+       tlen = dev->needed_tailroom;
+       skb = sock_alloc_send_skb(sk, hlen + tlen + size,
                        msg->msg_flags & MSG_DONTWAIT,
                        &err);
        if (!skb)
                goto out_dev;
 
-       skb_reserve(skb, LL_RESERVED_SPACE(dev));
+       skb_reserve(skb, hlen);
 
        skb_reset_network_header(skb);
 
index 10970ca..f96bae8 100644 (file)
@@ -108,6 +108,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
        struct net_device *dev;
        unsigned mtu;
        struct sk_buff *skb;
+       int hlen, tlen;
        int err;
 
        if (msg->msg_flags & MSG_OOB) {
@@ -137,12 +138,14 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
                goto out_dev;
        }
 
-       skb = sock_alloc_send_skb(sk, LL_ALLOCATED_SPACE(dev) + size,
+       hlen = LL_RESERVED_SPACE(dev);
+       tlen = dev->needed_tailroom;
+       skb = sock_alloc_send_skb(sk, hlen + tlen + size,
                        msg->msg_flags & MSG_DONTWAIT, &err);
        if (!skb)
                goto out_dev;
 
-       skb_reserve(skb, LL_RESERVED_SPACE(dev));
+       skb_reserve(skb, hlen);
 
        skb_reset_mac_header(skb);
        skb_reset_network_header(skb);
index 1b5096a..15dc4c4 100644 (file)
@@ -1250,7 +1250,8 @@ out:
        return err;
 }
 
-static struct sk_buff *inet_gso_segment(struct sk_buff *skb, u32 features)
+static struct sk_buff *inet_gso_segment(struct sk_buff *skb,
+       netdev_features_t features)
 {
        struct sk_buff *segs = ERR_PTR(-EINVAL);
        struct iphdr *iph;
@@ -1572,9 +1573,9 @@ static __net_init int ipv4_mib_init_net(struct net *net)
                          sizeof(struct icmp_mib),
                          __alignof__(struct icmp_mib)) < 0)
                goto err_icmp_mib;
-       if (snmp_mib_init((void __percpu **)net->mib.icmpmsg_statistics,
-                         sizeof(struct icmpmsg_mib),
-                         __alignof__(struct icmpmsg_mib)) < 0)
+       net->mib.icmpmsg_statistics = kzalloc(sizeof(struct icmpmsg_mib),
+                                             GFP_KERNEL);
+       if (!net->mib.icmpmsg_statistics)
                goto err_icmpmsg_mib;
 
        tcp_mib_init(net);
@@ -1598,7 +1599,7 @@ err_tcp_mib:
 
 static __net_exit void ipv4_mib_exit_net(struct net *net)
 {
-       snmp_mib_free((void __percpu **)net->mib.icmpmsg_statistics);
+       kfree(net->mib.icmpmsg_statistics);
        snmp_mib_free((void __percpu **)net->mib.icmp_statistics);
        snmp_mib_free((void __percpu **)net->mib.udplite_statistics);
        snmp_mib_free((void __percpu **)net->mib.udp_statistics);
index c1f4154..36d1440 100644 (file)
@@ -136,8 +136,6 @@ static void ah_output_done(struct crypto_async_request *base, int err)
                memcpy(top_iph+1, iph+1, top_iph->ihl*4 - sizeof(struct iphdr));
        }
 
-       err = ah->nexthdr;
-
        kfree(AH_SKB_CB(skb)->tmp);
        xfrm_output_resume(skb, err);
 }
@@ -264,12 +262,12 @@ static void ah_input_done(struct crypto_async_request *base, int err)
        if (err)
                goto out;
 
+       err = ah->nexthdr;
+
        skb->network_header += ah_hlen;
        memcpy(skb_network_header(skb), work_iph, ihl);
        __skb_pull(skb, ah_hlen + ihl);
        skb_set_transport_header(skb, -ihl);
-
-       err = ah->nexthdr;
 out:
        kfree(AH_SKB_CB(skb)->tmp);
        xfrm_input_resume(skb, err);
@@ -371,8 +369,6 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb)
                if (err == -EINPROGRESS)
                        goto out;
 
-               if (err == -EBUSY)
-                       err = NET_XMIT_DROP;
                goto out_free;
        }
 
index 96a164a..5c29ac5 100644 (file)
@@ -177,7 +177,7 @@ struct neigh_table arp_tbl = {
                .gc_staletime           = 60 * HZ,
                .reachable_time         = 30 * HZ,
                .delay_probe_time       = 5 * HZ,
-               .queue_len              = 3,
+               .queue_len_bytes        = 64*1024,
                .ucast_probes           = 3,
                .mcast_probes           = 3,
                .anycast_delay          = 1 * HZ,
@@ -592,16 +592,18 @@ struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip,
        struct sk_buff *skb;
        struct arphdr *arp;
        unsigned char *arp_ptr;
+       int hlen = LL_RESERVED_SPACE(dev);
+       int tlen = dev->needed_tailroom;
 
        /*
         *      Allocate a buffer
         */
 
-       skb = alloc_skb(arp_hdr_len(dev) + LL_ALLOCATED_SPACE(dev), GFP_ATOMIC);
+       skb = alloc_skb(arp_hdr_len(dev) + hlen + tlen, GFP_ATOMIC);
        if (skb == NULL)
                return NULL;
 
-       skb_reserve(skb, LL_RESERVED_SPACE(dev));
+       skb_reserve(skb, hlen);
        skb_reset_network_header(skb);
        arp = (struct arphdr *) skb_put(skb, arp_hdr_len(dev));
        skb->dev = dev;
index c7472ef..fbc5376 100644 (file)
@@ -304,9 +304,11 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size)
        struct igmpv3_report *pig;
        struct net *net = dev_net(dev);
        struct flowi4 fl4;
+       int hlen = LL_RESERVED_SPACE(dev);
+       int tlen = dev->needed_tailroom;
 
        while (1) {
-               skb = alloc_skb(size + LL_ALLOCATED_SPACE(dev),
+               skb = alloc_skb(size + hlen + tlen,
                                GFP_ATOMIC | __GFP_NOWARN);
                if (skb)
                        break;
@@ -327,7 +329,7 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size)
        skb_dst_set(skb, &rt->dst);
        skb->dev = dev;
 
-       skb_reserve(skb, LL_RESERVED_SPACE(dev));
+       skb_reserve(skb, hlen);
 
        skb_reset_network_header(skb);
        pip = ip_hdr(skb);
@@ -647,6 +649,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc,
        __be32  group = pmc ? pmc->multiaddr : 0;
        struct flowi4 fl4;
        __be32  dst;
+       int hlen, tlen;
 
        if (type == IGMPV3_HOST_MEMBERSHIP_REPORT)
                return igmpv3_send_report(in_dev, pmc);
@@ -661,7 +664,9 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc,
        if (IS_ERR(rt))
                return -1;
 
-       skb = alloc_skb(IGMP_SIZE+LL_ALLOCATED_SPACE(dev), GFP_ATOMIC);
+       hlen = LL_RESERVED_SPACE(dev);
+       tlen = dev->needed_tailroom;
+       skb = alloc_skb(IGMP_SIZE + hlen + tlen, GFP_ATOMIC);
        if (skb == NULL) {
                ip_rt_put(rt);
                return -1;
@@ -669,7 +674,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc,
 
        skb_dst_set(skb, &rt->dst);
 
-       skb_reserve(skb, LL_RESERVED_SPACE(dev));
+       skb_reserve(skb, hlen);
 
        skb_reset_network_header(skb);
        iph = ip_hdr(skb);
index c14d88a..a598768 100644 (file)
@@ -588,10 +588,19 @@ void inet_csk_reqsk_queue_prune(struct sock *parent,
 }
 EXPORT_SYMBOL_GPL(inet_csk_reqsk_queue_prune);
 
-struct sock *inet_csk_clone(struct sock *sk, const struct request_sock *req,
-                           const gfp_t priority)
+/**
+ *     inet_csk_clone_lock - clone an inet socket, and lock its clone
+ *     @sk: the socket to clone
+ *     @req: request_sock
+ *     @priority: for allocation (%GFP_KERNEL, %GFP_ATOMIC, etc)
+ *
+ *     Caller must unlock socket even in error path (bh_unlock_sock(newsk))
+ */
+struct sock *inet_csk_clone_lock(const struct sock *sk,
+                                const struct request_sock *req,
+                                const gfp_t priority)
 {
-       struct sock *newsk = sk_clone(sk, priority);
+       struct sock *newsk = sk_clone_lock(sk, priority);
 
        if (newsk != NULL) {
                struct inet_connection_sock *newicsk = inet_csk(newsk);
@@ -615,7 +624,7 @@ struct sock *inet_csk_clone(struct sock *sk, const struct request_sock *req,
        }
        return newsk;
 }
-EXPORT_SYMBOL_GPL(inet_csk_clone);
+EXPORT_SYMBOL_GPL(inet_csk_clone_lock);
 
 /*
  * At this point, there should be no process reference to this
index f5e2bda..bbebdec 100644 (file)
@@ -129,12 +129,10 @@ static int inet_csk_diag_fill(struct sock *sk,
        if (r->idiag_family == AF_INET6) {
                const struct ipv6_pinfo *np = inet6_sk(sk);
 
-               ipv6_addr_copy((struct in6_addr *)r->id.idiag_src,
-                              &np->rcv_saddr);
-               ipv6_addr_copy((struct in6_addr *)r->id.idiag_dst,
-                              &np->daddr);
-               if (ext & (1 << (INET_DIAG_TOS - 1)))
-                       RTA_PUT_U8(skb, INET_DIAG_TOS, np->tclass);
+               *(struct in6_addr *)r->id.idiag_src = np->rcv_saddr;
+               *(struct in6_addr *)r->id.idiag_dst = np->daddr;
+               if (ext & (1 << (INET_DIAG_TCLASS - 1)))
+                       RTA_PUT_U8(skb, INET_DIAG_TCLASS, np->tclass);
        }
 #endif
 
@@ -224,10 +222,8 @@ static int inet_twsk_diag_fill(struct inet_timewait_sock *tw,
                const struct inet6_timewait_sock *tw6 =
                                                inet6_twsk((struct sock *)tw);
 
-               ipv6_addr_copy((struct in6_addr *)r->id.idiag_src,
-                              &tw6->tw_v6_rcv_saddr);
-               ipv6_addr_copy((struct in6_addr *)r->id.idiag_dst,
-                              &tw6->tw_v6_daddr);
+               *(struct in6_addr *)r->id.idiag_src = tw6->tw_v6_rcv_saddr;
+               *(struct in6_addr *)r->id.idiag_dst = tw6->tw_v6_daddr;
        }
 #endif
        nlh->nlmsg_len = skb_tail_pointer(skb) - previous_tail;
@@ -603,10 +599,8 @@ static int inet_diag_fill_req(struct sk_buff *skb, struct sock *sk,
        r->idiag_inode = 0;
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
        if (r->idiag_family == AF_INET6) {
-               ipv6_addr_copy((struct in6_addr *)r->id.idiag_src,
-                              &inet6_rsk(req)->loc_addr);
-               ipv6_addr_copy((struct in6_addr *)r->id.idiag_dst,
-                              &inet6_rsk(req)->rmt_addr);
+               *(struct in6_addr *)r->id.idiag_src = inet6_rsk(req)->loc_addr;
+               *(struct in6_addr *)r->id.idiag_dst = inet6_rsk(req)->rmt_addr;
        }
 #endif
        nlh->nlmsg_len = skb_tail_pointer(skb) - b;
index d55110e..2b32296 100644 (file)
@@ -171,7 +171,7 @@ struct pcpu_tstats {
        unsigned long   rx_bytes;
        unsigned long   tx_packets;
        unsigned long   tx_bytes;
-};
+} __attribute__((aligned(4*sizeof(unsigned long))));
 
 static struct net_device_stats *ipgre_get_stats(struct net_device *dev)
 {
@@ -835,6 +835,8 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
        if (skb_headroom(skb) < max_headroom || skb_shared(skb)||
            (skb_cloned(skb) && !skb_clone_writable(skb, 0))) {
                struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
+               if (max_headroom > dev->needed_headroom)
+                       dev->needed_headroom = max_headroom;
                if (!new_skb) {
                        ip_rt_put(rt);
                        dev->stats.tx_dropped++;
index ec93335..05d20cc 100644 (file)
@@ -640,6 +640,7 @@ int ip_options_rcv_srr(struct sk_buff *skb)
        }
        if (srrptr <= srrspace) {
                opt->srr_is_hit = 1;
+               iph->daddr = nexthop;
                opt->is_changed = 1;
        }
        return 0;
index 09ff51b..80d5fa4 100644 (file)
 /*
  *     SOL_IP control messages.
  */
+#define PKTINFO_SKB_CB(__skb) ((struct in_pktinfo *)((__skb)->cb))
 
 static void ip_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb)
 {
-       struct in_pktinfo info;
-       struct rtable *rt = skb_rtable(skb);
+       struct in_pktinfo info = *PKTINFO_SKB_CB(skb);
 
        info.ipi_addr.s_addr = ip_hdr(skb)->daddr;
-       if (rt) {
-               info.ipi_ifindex = rt->rt_iif;
-               info.ipi_spec_dst.s_addr = rt->rt_spec_dst;
-       } else {
-               info.ipi_ifindex = 0;
-               info.ipi_spec_dst.s_addr = 0;
-       }
 
        put_cmsg(msg, SOL_IP, IP_PKTINFO, sizeof(info), &info);
 }
@@ -992,20 +985,28 @@ e_inval:
 }
 
 /**
- * ip_queue_rcv_skb - Queue an skb into sock receive queue
+ * ipv4_pktinfo_prepare - transfert some info from rtable to skb
  * @sk: socket
  * @skb: buffer
  *
- * Queues an skb into socket receive queue. If IP_CMSG_PKTINFO option
- * is not set, we drop skb dst entry now, while dst cache line is hot.
+ * To support IP_CMSG_PKTINFO option, we store rt_iif and rt_spec_dst
+ * in skb->cb[] before dst drop.
+ * This way, receiver doesnt make cache line misses to read rtable.
  */
-int ip_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
+void ipv4_pktinfo_prepare(struct sk_buff *skb)
 {
-       if (!(inet_sk(sk)->cmsg_flags & IP_CMSG_PKTINFO))
-               skb_dst_drop(skb);
-       return sock_queue_rcv_skb(sk, skb);
+       struct in_pktinfo *pktinfo = PKTINFO_SKB_CB(skb);
+       const struct rtable *rt = skb_rtable(skb);
+
+       if (rt) {
+               pktinfo->ipi_ifindex = rt->rt_iif;
+               pktinfo->ipi_spec_dst.s_addr = rt->rt_spec_dst;
+       } else {
+               pktinfo->ipi_ifindex = 0;
+               pktinfo->ipi_spec_dst.s_addr = 0;
+       }
+       skb_dst_drop(skb);
 }
-EXPORT_SYMBOL(ip_queue_rcv_skb);
 
 int ip_setsockopt(struct sock *sk, int level,
                int optname, char __user *optval, unsigned int optlen)
index 0da2afc..915eb52 100644 (file)
@@ -763,13 +763,15 @@ static void __init ic_bootp_send_if(struct ic_device *d, unsigned long jiffies_d
        struct sk_buff *skb;
        struct bootp_pkt *b;
        struct iphdr *h;
+       int hlen = LL_RESERVED_SPACE(dev);
+       int tlen = dev->needed_tailroom;
 
        /* Allocate packet */
-       skb = alloc_skb(sizeof(struct bootp_pkt) + LL_ALLOCATED_SPACE(dev) + 15,
+       skb = alloc_skb(sizeof(struct bootp_pkt) + hlen + tlen + 15,
                        GFP_KERNEL);
        if (!skb)
                return;
-       skb_reserve(skb, LL_RESERVED_SPACE(dev));
+       skb_reserve(skb, hlen);
        b = (struct bootp_pkt *) skb_put(skb, sizeof(struct bootp_pkt));
        memset(b, 0, sizeof(struct bootp_pkt));
 
@@ -822,8 +824,13 @@ static void __init ic_bootp_send_if(struct ic_device *d, unsigned long jiffies_d
        skb->dev = dev;
        skb->protocol = htons(ETH_P_IP);
        if (dev_hard_header(skb, dev, ntohs(skb->protocol),
-                           dev->broadcast, dev->dev_addr, skb->len) < 0 ||
-           dev_queue_xmit(skb) < 0)
+                           dev->broadcast, dev->dev_addr, skb->len) < 0) {
+               kfree_skb(skb);
+               printk("E");
+               return;
+       }
+
+       if (dev_queue_xmit(skb) < 0)
                printk("E");
 }
 
index 065effd..9490690 100644 (file)
@@ -148,7 +148,7 @@ struct pcpu_tstats {
        unsigned long   rx_bytes;
        unsigned long   tx_packets;
        unsigned long   tx_bytes;
-};
+} __attribute__((aligned(4*sizeof(unsigned long))));
 
 static struct net_device_stats *ipip_get_stats(struct net_device *dev)
 {
index a06f73f..43d4c3b 100644 (file)
@@ -339,7 +339,6 @@ void ping_err(struct sk_buff *skb, u32 info)
        sk = ping_v4_lookup(net, iph->daddr, iph->saddr,
                            ntohs(icmph->un.echo.id), skb->dev->ifindex);
        if (sk == NULL) {
-               ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS);
                pr_debug("no socket, dropping\n");
                return; /* No socket for error */
        }
@@ -679,7 +678,6 @@ static int ping_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
        pr_debug("ping_queue_rcv_skb(sk=%p,sk->num=%d,skb=%p)\n",
                inet_sk(sk), inet_sk(sk)->inet_num, skb);
        if (sock_queue_rcv_skb(sk, skb) < 0) {
-               ICMP_INC_STATS_BH(sock_net(sk), ICMP_MIB_INERRORS);
                kfree_skb(skb);
                pr_debug("ping_queue_rcv_skb -> failed\n");
                return -1;
index 466ea8b..961eed4 100644 (file)
@@ -288,7 +288,7 @@ static void icmpmsg_put(struct seq_file *seq)
 
        count = 0;
        for (i = 0; i < ICMPMSG_MIB_MAX; i++) {
-               val = snmp_fold_field((void __percpu **) net->mib.icmpmsg_statistics, i);
+               val = atomic_long_read(&net->mib.icmpmsg_statistics->mibs[i]);
                if (val) {
                        type[count] = i;
                        vals[count++] = val;
@@ -307,6 +307,7 @@ static void icmp_put(struct seq_file *seq)
 {
        int i;
        struct net *net = seq->private;
+       atomic_long_t *ptr = net->mib.icmpmsg_statistics->mibs;
 
        seq_puts(seq, "\nIcmp: InMsgs InErrors");
        for (i=0; icmpmibmap[i].name != NULL; i++)
@@ -319,15 +320,13 @@ static void icmp_put(struct seq_file *seq)
                snmp_fold_field((void __percpu **) net->mib.icmp_statistics, ICMP_MIB_INERRORS));
        for (i=0; icmpmibmap[i].name != NULL; i++)
                seq_printf(seq, " %lu",
-                       snmp_fold_field((void __percpu **) net->mib.icmpmsg_statistics,
-                               icmpmibmap[i].index));
+                          atomic_long_read(ptr + icmpmibmap[i].index));
        seq_printf(seq, " %lu %lu",
                snmp_fold_field((void __percpu **) net->mib.icmp_statistics, ICMP_MIB_OUTMSGS),
                snmp_fold_field((void __percpu **) net->mib.icmp_statistics, ICMP_MIB_OUTERRORS));
        for (i=0; icmpmibmap[i].name != NULL; i++)
                seq_printf(seq, " %lu",
-                       snmp_fold_field((void __percpu **) net->mib.icmpmsg_statistics,
-                               icmpmibmap[i].index | 0x100));
+                          atomic_long_read(ptr + (icmpmibmap[i].index | 0x100)));
 }
 
 /*
index 007e2eb..3ccda5a 100644 (file)
@@ -292,7 +292,8 @@ static int raw_rcv_skb(struct sock * sk, struct sk_buff * skb)
 {
        /* Charge it to the socket. */
 
-       if (ip_queue_rcv_skb(sk, skb) < 0) {
+       ipv4_pktinfo_prepare(skb);
+       if (sock_queue_rcv_skb(sk, skb) < 0) {
                kfree_skb(skb);
                return NET_RX_DROP;
        }
@@ -327,6 +328,7 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4,
        unsigned int iphlen;
        int err;
        struct rtable *rt = *rtp;
+       int hlen, tlen;
 
        if (length > rt->dst.dev->mtu) {
                ip_local_error(sk, EMSGSIZE, fl4->daddr, inet->inet_dport,
@@ -336,12 +338,14 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4,
        if (flags&MSG_PROBE)
                goto out;
 
+       hlen = LL_RESERVED_SPACE(rt->dst.dev);
+       tlen = rt->dst.dev->needed_tailroom;
        skb = sock_alloc_send_skb(sk,
-                                 length + LL_ALLOCATED_SPACE(rt->dst.dev) + 15,
+                                 length + hlen + tlen + 15,
                                  flags & MSG_DONTWAIT, &err);
        if (skb == NULL)
                goto error;
-       skb_reserve(skb, LL_RESERVED_SPACE(rt->dst.dev));
+       skb_reserve(skb, hlen);
 
        skb->priority = sk->sk_priority;
        skb->mark = sk->sk_mark;
index 155138d..0c74da8 100644 (file)
@@ -1304,16 +1304,42 @@ static void rt_del(unsigned hash, struct rtable *rt)
        spin_unlock_bh(rt_hash_lock_addr(hash));
 }
 
+static int check_peer_redir(struct dst_entry *dst, struct inet_peer *peer)
+{
+       struct rtable *rt = (struct rtable *) dst;
+       __be32 orig_gw = rt->rt_gateway;
+       struct neighbour *n, *old_n;
+
+       dst_confirm(&rt->dst);
+
+       rt->rt_gateway = peer->redirect_learned.a4;
+
+       n = ipv4_neigh_lookup(&rt->dst, &rt->rt_gateway);
+       if (IS_ERR(n))
+               return PTR_ERR(n);
+       old_n = xchg(&rt->dst._neighbour, n);
+       if (old_n)
+               neigh_release(old_n);
+       if (!n || !(n->nud_state & NUD_VALID)) {
+               if (n)
+                       neigh_event_send(n, NULL);
+               rt->rt_gateway = orig_gw;
+               return -EAGAIN;
+       } else {
+               rt->rt_flags |= RTCF_REDIRECTED;
+               call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, n);
+       }
+       return 0;
+}
+
 /* called in rcu_read_lock() section */
 void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
                    __be32 saddr, struct net_device *dev)
 {
        int s, i;
        struct in_device *in_dev = __in_dev_get_rcu(dev);
-       struct rtable *rt;
        __be32 skeys[2] = { saddr, 0 };
        int    ikeys[2] = { dev->ifindex, 0 };
-       struct flowi4 fl4;
        struct inet_peer *peer;
        struct net *net;
 
@@ -1336,33 +1362,42 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
                        goto reject_redirect;
        }
 
-       memset(&fl4, 0, sizeof(fl4));
-       fl4.daddr = daddr;
        for (s = 0; s < 2; s++) {
                for (i = 0; i < 2; i++) {
-                       fl4.flowi4_oif = ikeys[i];
-                       fl4.saddr = skeys[s];
-                       rt = __ip_route_output_key(net, &fl4);
-                       if (IS_ERR(rt))
-                               continue;
-
-                       if (rt->dst.error || rt->dst.dev != dev ||
-                           rt->rt_gateway != old_gw) {
-                               ip_rt_put(rt);
-                               continue;
-                       }
+                       unsigned int hash;
+                       struct rtable __rcu **rthp;
+                       struct rtable *rt;
+
+                       hash = rt_hash(daddr, skeys[s], ikeys[i], rt_genid(net));
+
+                       rthp = &rt_hash_table[hash].chain;
+
+                       while ((rt = rcu_dereference(*rthp)) != NULL) {
+                               rthp = &rt->dst.rt_next;
+
+                               if (rt->rt_key_dst != daddr ||
+                                   rt->rt_key_src != skeys[s] ||
+                                   rt->rt_oif != ikeys[i] ||
+                                   rt_is_input_route(rt) ||
+                                   rt_is_expired(rt) ||
+                                   !net_eq(dev_net(rt->dst.dev), net) ||
+                                   rt->dst.error ||
+                                   rt->dst.dev != dev ||
+                                   rt->rt_gateway != old_gw)
+                                       continue;
 
-                       if (!rt->peer)
-                               rt_bind_peer(rt, rt->rt_dst, 1);
+                               if (!rt->peer)
+                                       rt_bind_peer(rt, rt->rt_dst, 1);
 
-                       peer = rt->peer;
-                       if (peer) {
-                               peer->redirect_learned.a4 = new_gw;
-                               atomic_inc(&__rt_peer_genid);
+                               peer = rt->peer;
+                               if (peer) {
+                                       if (peer->redirect_learned.a4 != new_gw) {
+                                               peer->redirect_learned.a4 = new_gw;
+                                               atomic_inc(&__rt_peer_genid);
+                                       }
+                                       check_peer_redir(&rt->dst, peer);
+                               }
                        }
-
-                       ip_rt_put(rt);
-                       return;
                }
        }
        return;
@@ -1649,33 +1684,6 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu)
        }
 }
 
-static int check_peer_redir(struct dst_entry *dst, struct inet_peer *peer)
-{
-       struct rtable *rt = (struct rtable *) dst;
-       __be32 orig_gw = rt->rt_gateway;
-       struct neighbour *n, *old_n;
-
-       dst_confirm(&rt->dst);
-
-       rt->rt_gateway = peer->redirect_learned.a4;
-
-       n = ipv4_neigh_lookup(&rt->dst, &rt->rt_gateway);
-       if (IS_ERR(n))
-               return PTR_ERR(n);
-       old_n = xchg(&rt->dst._neighbour, n);
-       if (old_n)
-               neigh_release(old_n);
-       if (!n || !(n->nud_state & NUD_VALID)) {
-               if (n)
-                       neigh_event_send(n, NULL);
-               rt->rt_gateway = orig_gw;
-               return -EAGAIN;
-       } else {
-               rt->rt_flags |= RTCF_REDIRECTED;
-               call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, n);
-       }
-       return 0;
-}
 
 static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie)
 {
@@ -2845,7 +2853,7 @@ static int rt_fill_info(struct net *net,
        struct rtable *rt = skb_rtable(skb);
        struct rtmsg *r;
        struct nlmsghdr *nlh;
-       long expires = 0;
+       unsigned long expires = 0;
        const struct inet_peer *peer = rt->peer;
        u32 id = 0, ts = 0, tsage = 0, error;
 
@@ -2902,8 +2910,12 @@ static int rt_fill_info(struct net *net,
                        tsage = get_seconds() - peer->tcp_ts_stamp;
                }
                expires = ACCESS_ONCE(peer->pmtu_expires);
-               if (expires)
-                       expires -= jiffies;
+               if (expires) {
+                       if (time_before(jiffies, expires))
+                               expires -= jiffies;
+                       else
+                               expires = 0;
+               }
        }
 
        if (rt_is_input_route(rt)) {
index 34f5db1..50c3596 100644 (file)
@@ -2653,7 +2653,8 @@ int compat_tcp_getsockopt(struct sock *sk, int level, int optname,
 EXPORT_SYMBOL(compat_tcp_getsockopt);
 #endif
 
-struct sk_buff *tcp_tso_segment(struct sk_buff *skb, u32 features)
+struct sk_buff *tcp_tso_segment(struct sk_buff *skb,
+       netdev_features_t features)
 {
        struct sk_buff *segs = ERR_PTR(-EINVAL);
        struct tcphdr *th;
index a744315..a9db4b1 100644 (file)
@@ -1510,6 +1510,7 @@ exit:
        NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
        return NULL;
 put_and_exit:
+       tcp_clear_xmit_timers(newsk);
        bh_unlock_sock(newsk);
        sock_put(newsk);
        goto exit;
index 66363b6..945efff 100644 (file)
@@ -343,8 +343,8 @@ void tcp_time_wait(struct sock *sk, int state, int timeo)
 
                        tw->tw_ipv6_offset = inet6_tw_offset(sk->sk_prot);
                        tw6 = inet6_twsk((struct sock *)tw);
-                       ipv6_addr_copy(&tw6->tw_v6_daddr, &np->daddr);
-                       ipv6_addr_copy(&tw6->tw_v6_rcv_saddr, &np->rcv_saddr);
+                       tw6->tw_v6_daddr = np->daddr;
+                       tw6->tw_v6_rcv_saddr = np->rcv_saddr;
                        tw->tw_tclass = np->tclass;
                        tw->tw_ipv6only = np->ipv6only;
                }
@@ -425,7 +425,7 @@ static inline void TCP_ECN_openreq_child(struct tcp_sock *tp,
  */
 struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, struct sk_buff *skb)
 {
-       struct sock *newsk = inet_csk_clone(sk, req, GFP_ATOMIC);
+       struct sock *newsk = inet_csk_clone_lock(sk, req, GFP_ATOMIC);
 
        if (newsk != NULL) {
                const struct inet_request_sock *ireq = inet_rsk(req);
index 980b98f..63170e2 100644 (file)
@@ -1382,7 +1382,7 @@ static inline int tcp_minshall_check(const struct tcp_sock *tp)
 /* Return 0, if packet can be sent now without violation Nagle's rules:
  * 1. It is full sized.
  * 2. Or it contains FIN. (already checked by caller)
- * 3. Or TCP_NODELAY was set.
+ * 3. Or TCP_CORK is not set, and TCP_NODELAY is set.
  * 4. Or TCP_CORK is not set, and all sent packets are ACKed.
  *    With Minshall's modification: all sent small packets are ACKed.
  */
index ab0966d..b867ea2 100644 (file)
@@ -1357,7 +1357,7 @@ static int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
        if (inet_sk(sk)->inet_daddr)
                sock_rps_save_rxhash(sk, skb);
 
-       rc = ip_queue_rcv_skb(sk, skb);
+       rc = sock_queue_rcv_skb(sk, skb);
        if (rc < 0) {
                int is_udplite = IS_UDPLITE(sk);
 
@@ -1473,6 +1473,7 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
 
        rc = 0;
 
+       ipv4_pktinfo_prepare(skb);
        bh_lock_sock(sk);
        if (!sock_owned_by_user(sk))
                rc = __udp_queue_rcv_skb(sk, skb);
@@ -2246,7 +2247,8 @@ int udp4_ufo_send_check(struct sk_buff *skb)
        return 0;
 }
 
-struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, u32 features)
+struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb,
+       netdev_features_t features)
 {
        struct sk_buff *segs = ERR_PTR(-EINVAL);
        unsigned int mss;
index cf88df8..5860517 100644 (file)
@@ -636,7 +636,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
                goto out;
        }
 
-       ipv6_addr_copy(&ifa->addr, addr);
+       ifa->addr = *addr;
 
        spin_lock_init(&ifa->lock);
        spin_lock_init(&ifa->state_lock);
@@ -1228,7 +1228,7 @@ try_nextdev:
        if (!hiscore->ifa)
                return -EADDRNOTAVAIL;
 
-       ipv6_addr_copy(saddr, &hiscore->ifa->addr);
+       *saddr = hiscore->ifa->addr;
        in6_ifa_put(hiscore->ifa);
        return 0;
 }
@@ -1249,7 +1249,7 @@ int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr,
                list_for_each_entry(ifp, &idev->addr_list, if_list) {
                        if (ifp->scope == IFA_LINK &&
                            !(ifp->flags & banned_flags)) {
-                               ipv6_addr_copy(addr, &ifp->addr);
+                               *addr = ifp->addr;
                                err = 0;
                                break;
                        }
@@ -1700,7 +1700,7 @@ addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev,
                .fc_protocol = RTPROT_KERNEL,
        };
 
-       ipv6_addr_copy(&cfg.fc_dst, pfx);
+       cfg.fc_dst = *pfx;
 
        /* Prevent useless cloning on PtP SIT.
           This thing is done here expecting that the whole
index d27c797..7694c82 100644 (file)
@@ -347,7 +347,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
                         */
                        v4addr = LOOPBACK4_IPV6;
                        if (!(addr_type & IPV6_ADDR_MULTICAST)) {
-                               if (!inet->transparent &&
+                               if (!(inet->freebind || inet->transparent) &&
                                    !ipv6_chk_addr(net, &addr->sin6_addr,
                                                   dev, 0)) {
                                        err = -EADDRNOTAVAIL;
@@ -361,10 +361,10 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
        inet->inet_rcv_saddr = v4addr;
        inet->inet_saddr = v4addr;
 
-       ipv6_addr_copy(&np->rcv_saddr, &addr->sin6_addr);
+       np->rcv_saddr = addr->sin6_addr;
 
        if (!(addr_type & IPV6_ADDR_MULTICAST))
-               ipv6_addr_copy(&np->saddr, &addr->sin6_addr);
+               np->saddr = addr->sin6_addr;
 
        /* Make sure we are allowed to bind here. */
        if (sk->sk_prot->get_port(sk, snum)) {
@@ -458,14 +458,14 @@ int inet6_getname(struct socket *sock, struct sockaddr *uaddr,
                    peer == 1)
                        return -ENOTCONN;
                sin->sin6_port = inet->inet_dport;
-               ipv6_addr_copy(&sin->sin6_addr, &np->daddr);
+               sin->sin6_addr = np->daddr;
                if (np->sndflow)
                        sin->sin6_flowinfo = np->flow_label;
        } else {
                if (ipv6_addr_any(&np->rcv_saddr))
-                       ipv6_addr_copy(&sin->sin6_addr, &np->saddr);
+                       sin->sin6_addr = np->saddr;
                else
-                       ipv6_addr_copy(&sin->sin6_addr, &np->rcv_saddr);
+                       sin->sin6_addr = np->rcv_saddr;
 
                sin->sin6_port = inet->inet_sport;
        }
@@ -660,8 +660,8 @@ int inet6_sk_rebuild_header(struct sock *sk)
 
                memset(&fl6, 0, sizeof(fl6));
                fl6.flowi6_proto = sk->sk_protocol;
-               ipv6_addr_copy(&fl6.daddr, &np->daddr);
-               ipv6_addr_copy(&fl6.saddr, &np->saddr);
+               fl6.daddr = np->daddr;
+               fl6.saddr = np->saddr;
                fl6.flowlabel = np->flow_label;
                fl6.flowi6_oif = sk->sk_bound_dev_if;
                fl6.flowi6_mark = sk->sk_mark;
@@ -769,7 +769,8 @@ out:
        return err;
 }
 
-static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, u32 features)
+static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
+       netdev_features_t features)
 {
        struct sk_buff *segs = ERR_PTR(-EINVAL);
        struct ipv6hdr *ipv6h;
@@ -985,9 +986,9 @@ static int __net_init ipv6_init_mibs(struct net *net)
                          sizeof(struct icmpv6_mib),
                          __alignof__(struct icmpv6_mib)) < 0)
                goto err_icmp_mib;
-       if (snmp_mib_init((void __percpu **)net->mib.icmpv6msg_statistics,
-                         sizeof(struct icmpv6msg_mib),
-                         __alignof__(struct icmpv6msg_mib)) < 0)
+       net->mib.icmpv6msg_statistics = kzalloc(sizeof(struct icmpv6msg_mib),
+                                               GFP_KERNEL);
+       if (!net->mib.icmpv6msg_statistics)
                goto err_icmpmsg_mib;
        return 0;
 
@@ -1008,7 +1009,7 @@ static void ipv6_cleanup_mibs(struct net *net)
        snmp_mib_free((void __percpu **)net->mib.udplite_stats_in6);
        snmp_mib_free((void __percpu **)net->mib.ipv6_statistics);
        snmp_mib_free((void __percpu **)net->mib.icmpv6_statistics);
-       snmp_mib_free((void __percpu **)net->mib.icmpv6msg_statistics);
+       kfree(net->mib.icmpv6msg_statistics);
 }
 
 static int __net_init inet6_net_init(struct net *net)
index 2195ae6..2ae79db 100644 (file)
@@ -193,9 +193,9 @@ static void ipv6_rearrange_destopt(struct ipv6hdr *iph, struct ipv6_opt_hdr *des
                                                printk(KERN_WARNING "destopt hao: invalid header length: %u\n", hao->length);
                                        goto bad;
                                }
-                               ipv6_addr_copy(&final_addr, &hao->addr);
-                               ipv6_addr_copy(&hao->addr, &iph->saddr);
-                               ipv6_addr_copy(&iph->saddr, &final_addr);
+                               final_addr = hao->addr;
+                               hao->addr = iph->saddr;
+                               iph->saddr = final_addr;
                        }
                        break;
                }
@@ -241,13 +241,13 @@ static void ipv6_rearrange_rthdr(struct ipv6hdr *iph, struct ipv6_rt_hdr *rthdr)
        segments = rthdr->hdrlen >> 1;
 
        addrs = ((struct rt0_hdr *)rthdr)->addr;
-       ipv6_addr_copy(&final_addr, addrs + segments - 1);
+       final_addr = addrs[segments - 1];
 
        addrs += segments - segments_left;
        memmove(addrs + 1, addrs, (segments_left - 1) * sizeof(*addrs));
 
-       ipv6_addr_copy(addrs, &iph->daddr);
-       ipv6_addr_copy(&iph->daddr, &final_addr);
+       addrs[0] = iph->daddr;
+       iph->daddr = final_addr;
 }
 
 static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len, int dir)
@@ -324,8 +324,6 @@ static void ah6_output_done(struct crypto_async_request *base, int err)
 #endif
        }
 
-       err = ah->nexthdr;
-
        kfree(AH_SKB_CB(skb)->tmp);
        xfrm_output_resume(skb, err);
 }
@@ -466,12 +464,12 @@ static void ah6_input_done(struct crypto_async_request *base, int err)
        if (err)
                goto out;
 
+       err = ah->nexthdr;
+
        skb->network_header += ah_hlen;
        memcpy(skb_network_header(skb), work_iph, hdr_len);
        __skb_pull(skb, ah_hlen + hdr_len);
        skb_set_transport_header(skb, -hdr_len);
-
-       err = ah->nexthdr;
 out:
        kfree(AH_SKB_CB(skb)->tmp);
        xfrm_input_resume(skb, err);
@@ -583,8 +581,6 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
                if (err == -EINPROGRESS)
                        goto out;
 
-               if (err == -EBUSY)
-                       err = NET_XMIT_DROP;
                goto out_free;
        }
 
index 674255f..fc1cdcd 100644 (file)
@@ -75,7 +75,7 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
        if (pac == NULL)
                return -ENOMEM;
        pac->acl_next = NULL;
-       ipv6_addr_copy(&pac->acl_addr, addr);
+       pac->acl_addr = *addr;
 
        rcu_read_lock();
        if (ifindex == 0) {
@@ -296,7 +296,7 @@ int ipv6_dev_ac_inc(struct net_device *dev, const struct in6_addr *addr)
                goto out;
        }
 
-       ipv6_addr_copy(&aca->aca_addr, addr);
+       aca->aca_addr = *addr;
        aca->aca_idev = idev;
        aca->aca_rt = rt;
        aca->aca_users = 1;
index e248069..ae08aee 100644 (file)
@@ -71,7 +71,7 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
                        flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);
                        if (flowlabel == NULL)
                                return -EINVAL;
-                       ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst);
+                       usin->sin6_addr = flowlabel->dst;
                }
        }
 
@@ -143,7 +143,7 @@ ipv4_connected:
                }
        }
 
-       ipv6_addr_copy(&np->daddr, daddr);
+       np->daddr = *daddr;
        np->flow_label = fl6.flowlabel;
 
        inet->inet_dport = usin->sin6_port;
@@ -154,8 +154,8 @@ ipv4_connected:
         */
 
        fl6.flowi6_proto = sk->sk_protocol;
-       ipv6_addr_copy(&fl6.daddr, &np->daddr);
-       ipv6_addr_copy(&fl6.saddr, &np->saddr);
+       fl6.daddr = np->daddr;
+       fl6.saddr = np->saddr;
        fl6.flowi6_oif = sk->sk_bound_dev_if;
        fl6.flowi6_mark = sk->sk_mark;
        fl6.fl6_dport = inet->inet_dport;
@@ -179,10 +179,10 @@ ipv4_connected:
        /* source address lookup done in ip6_dst_lookup */
 
        if (ipv6_addr_any(&np->saddr))
-               ipv6_addr_copy(&np->saddr, &fl6.saddr);
+               np->saddr = fl6.saddr;
 
        if (ipv6_addr_any(&np->rcv_saddr)) {
-               ipv6_addr_copy(&np->rcv_saddr, &fl6.saddr);
+               np->rcv_saddr = fl6.saddr;
                inet->inet_rcv_saddr = LOOPBACK4_IPV6;
                if (sk->sk_prot->rehash)
                        sk->sk_prot->rehash(sk);
@@ -257,7 +257,7 @@ void ipv6_local_error(struct sock *sk, int err, struct flowi6 *fl6, u32 info)
        skb_put(skb, sizeof(struct ipv6hdr));
        skb_reset_network_header(skb);
        iph = ipv6_hdr(skb);
-       ipv6_addr_copy(&iph->daddr, &fl6->daddr);
+       iph->daddr = fl6->daddr;
 
        serr = SKB_EXT_ERR(skb);
        serr->ee.ee_errno = err;
@@ -294,7 +294,7 @@ void ipv6_local_rxpmtu(struct sock *sk, struct flowi6 *fl6, u32 mtu)
        skb_put(skb, sizeof(struct ipv6hdr));
        skb_reset_network_header(skb);
        iph = ipv6_hdr(skb);
-       ipv6_addr_copy(&iph->daddr, &fl6->daddr);
+       iph->daddr = fl6->daddr;
 
        mtu_info = IP6CBMTU(skb);
 
@@ -303,7 +303,7 @@ void ipv6_local_rxpmtu(struct sock *sk, struct flowi6 *fl6, u32 mtu)
        mtu_info->ip6m_addr.sin6_port = 0;
        mtu_info->ip6m_addr.sin6_flowinfo = 0;
        mtu_info->ip6m_addr.sin6_scope_id = fl6->flowi6_oif;
-       ipv6_addr_copy(&mtu_info->ip6m_addr.sin6_addr, &ipv6_hdr(skb)->daddr);
+       mtu_info->ip6m_addr.sin6_addr = ipv6_hdr(skb)->daddr;
 
        __skb_pull(skb, skb_tail_pointer(skb) - skb->data);
        skb_reset_transport_header(skb);
@@ -354,8 +354,8 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len)
                sin->sin6_port = serr->port;
                sin->sin6_scope_id = 0;
                if (skb->protocol == htons(ETH_P_IPV6)) {
-                       ipv6_addr_copy(&sin->sin6_addr,
-                                 (struct in6_addr *)(nh + serr->addr_offset));
+                       sin->sin6_addr =
+                               *(struct in6_addr *)(nh + serr->addr_offset);
                        if (np->sndflow)
                                sin->sin6_flowinfo =
                                        (*(__be32 *)(nh + serr->addr_offset - 24) &
@@ -376,7 +376,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len)
                sin->sin6_flowinfo = 0;
                sin->sin6_scope_id = 0;
                if (skb->protocol == htons(ETH_P_IPV6)) {
-                       ipv6_addr_copy(&sin->sin6_addr, &ipv6_hdr(skb)->saddr);
+                       sin->sin6_addr = ipv6_hdr(skb)->saddr;
                        if (np->rxopt.all)
                                datagram_recv_ctl(sk, msg, skb);
                        if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL)
@@ -451,7 +451,7 @@ int ipv6_recv_rxpmtu(struct sock *sk, struct msghdr *msg, int len)
                sin->sin6_flowinfo = 0;
                sin->sin6_port = 0;
                sin->sin6_scope_id = mtu_info.ip6m_addr.sin6_scope_id;
-               ipv6_addr_copy(&sin->sin6_addr, &mtu_info.ip6m_addr.sin6_addr);
+               sin->sin6_addr = mtu_info.ip6m_addr.sin6_addr;
        }
 
        put_cmsg(msg, SOL_IPV6, IPV6_PATHMTU, sizeof(mtu_info), &mtu_info);
@@ -475,7 +475,7 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
                struct in6_pktinfo src_info;
 
                src_info.ipi6_ifindex = opt->iif;
-               ipv6_addr_copy(&src_info.ipi6_addr, &ipv6_hdr(skb)->daddr);
+               src_info.ipi6_addr = ipv6_hdr(skb)->daddr;
                put_cmsg(msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info);
        }
 
@@ -550,7 +550,7 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
                struct in6_pktinfo src_info;
 
                src_info.ipi6_ifindex = opt->iif;
-               ipv6_addr_copy(&src_info.ipi6_addr, &ipv6_hdr(skb)->daddr);
+               src_info.ipi6_addr = ipv6_hdr(skb)->daddr;
                put_cmsg(msg, SOL_IPV6, IPV6_2292PKTINFO, sizeof(src_info), &src_info);
        }
        if (np->rxopt.bits.rxohlim) {
@@ -584,7 +584,7 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
                         */
 
                        sin6.sin6_family = AF_INET6;
-                       ipv6_addr_copy(&sin6.sin6_addr, &ipv6_hdr(skb)->daddr);
+                       sin6.sin6_addr = ipv6_hdr(skb)->daddr;
                        sin6.sin6_port = ports[1];
                        sin6.sin6_flowinfo = 0;
                        sin6.sin6_scope_id = 0;
@@ -654,12 +654,12 @@ int datagram_send_ctl(struct net *net, struct sock *sk,
 
                        if (addr_type != IPV6_ADDR_ANY) {
                                int strict = __ipv6_addr_src_scope(addr_type) <= IPV6_ADDR_SCOPE_LINKLOCAL;
-                               if (!inet_sk(sk)->transparent &&
+                               if (!(inet_sk(sk)->freebind || inet_sk(sk)->transparent) &&
                                    !ipv6_chk_addr(net, &src_info->ipi6_addr,
                                                   strict ? dev : NULL, 0))
                                        err = -EINVAL;
                                else
-                                       ipv6_addr_copy(&fl6->saddr, &src_info->ipi6_addr);
+                                       fl6->saddr = src_info->ipi6_addr;
                        }
 
                        rcu_read_unlock();
index bf22a22..3d641b6 100644 (file)
@@ -243,9 +243,9 @@ static int ipv6_dest_hao(struct sk_buff *skb, int optoff)
        if (skb->ip_summed == CHECKSUM_COMPLETE)
                skb->ip_summed = CHECKSUM_NONE;
 
-       ipv6_addr_copy(&tmp_addr, &ipv6h->saddr);
-       ipv6_addr_copy(&ipv6h->saddr, &hao->addr);
-       ipv6_addr_copy(&hao->addr, &tmp_addr);
+       tmp_addr = ipv6h->saddr;
+       ipv6h->saddr = hao->addr;
+       hao->addr = tmp_addr;
 
        if (skb->tstamp.tv64 == 0)
                __net_timestamp(skb);
@@ -461,9 +461,9 @@ looped_back:
                return -1;
        }
 
-       ipv6_addr_copy(&daddr, addr);
-       ipv6_addr_copy(addr, &ipv6_hdr(skb)->daddr);
-       ipv6_addr_copy(&ipv6_hdr(skb)->daddr, &daddr);
+       daddr = *addr;
+       *addr = ipv6_hdr(skb)->daddr;
+       ipv6_hdr(skb)->daddr = daddr;
 
        skb_dst_drop(skb);
        ip6_route_input(skb);
@@ -690,7 +690,7 @@ static void ipv6_push_rthdr(struct sk_buff *skb, u8 *proto,
                memcpy(phdr->addr, ihdr->addr + 1,
                       (hops - 1) * sizeof(struct in6_addr));
 
-       ipv6_addr_copy(phdr->addr + (hops - 1), *addr_p);
+       phdr->addr[hops - 1] = **addr_p;
        *addr_p = ihdr->addr;
 
        phdr->rt_hdr.nexthdr = *proto;
@@ -888,8 +888,8 @@ struct in6_addr *fl6_update_dst(struct flowi6 *fl6,
        if (!opt || !opt->srcrt)
                return NULL;
 
-       ipv6_addr_copy(orig, &fl6->daddr);
-       ipv6_addr_copy(&fl6->daddr, ((struct rt0_hdr *)opt->srcrt)->addr);
+       *orig = fl6->daddr;
+       fl6->daddr = *((struct rt0_hdr *)opt->srcrt)->addr;
        return orig;
 }
 
index 2955715..b6c5731 100644 (file)
@@ -96,7 +96,7 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
                        if (!ipv6_prefix_equal(&saddr, &r->src.addr,
                                               r->src.plen))
                                goto again;
-                       ipv6_addr_copy(&flp6->saddr, &saddr);
+                       flp6->saddr = saddr;
                }
                goto out;
        }
index 90868fb..9e2bdcc 100644 (file)
@@ -290,9 +290,9 @@ static void mip6_addr_swap(struct sk_buff *skb)
                if (likely(off >= 0)) {
                        hao = (struct ipv6_destopt_hao *)
                                        (skb_network_header(skb) + off);
-                       ipv6_addr_copy(&tmp, &iph->saddr);
-                       ipv6_addr_copy(&iph->saddr, &hao->addr);
-                       ipv6_addr_copy(&hao->addr, &tmp);
+                       tmp = iph->saddr;
+                       iph->saddr = hao->addr;
+                       hao->addr = tmp;
                }
        }
 }
@@ -444,9 +444,9 @@ void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
 
        memset(&fl6, 0, sizeof(fl6));
        fl6.flowi6_proto = IPPROTO_ICMPV6;
-       ipv6_addr_copy(&fl6.daddr, &hdr->saddr);
+       fl6.daddr = hdr->saddr;
        if (saddr)
-               ipv6_addr_copy(&fl6.saddr, saddr);
+               fl6.saddr = *saddr;
        fl6.flowi6_oif = iif;
        fl6.fl6_icmp_type = type;
        fl6.fl6_icmp_code = code;
@@ -538,9 +538,9 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
 
        memset(&fl6, 0, sizeof(fl6));
        fl6.flowi6_proto = IPPROTO_ICMPV6;
-       ipv6_addr_copy(&fl6.daddr, &ipv6_hdr(skb)->saddr);
+       fl6.daddr = ipv6_hdr(skb)->saddr;
        if (saddr)
-               ipv6_addr_copy(&fl6.saddr, saddr);
+               fl6.saddr = *saddr;
        fl6.flowi6_oif = skb->dev->ifindex;
        fl6.fl6_icmp_type = ICMPV6_ECHO_REPLY;
        security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));
@@ -786,8 +786,8 @@ void icmpv6_flow_init(struct sock *sk, struct flowi6 *fl6,
                      int oif)
 {
        memset(fl6, 0, sizeof(*fl6));
-       ipv6_addr_copy(&fl6->saddr, saddr);
-       ipv6_addr_copy(&fl6->daddr, daddr);
+       fl6->saddr = *saddr;
+       fl6->daddr = *daddr;
        fl6->flowi6_proto       = IPPROTO_ICMPV6;
        fl6->fl6_icmp_type      = type;
        fl6->fl6_icmp_code      = 0;
index fee46d5..4d7bfb3 100644 (file)
@@ -65,9 +65,9 @@ struct dst_entry *inet6_csk_route_req(struct sock *sk,
 
        memset(&fl6, 0, sizeof(fl6));
        fl6.flowi6_proto = IPPROTO_TCP;
-       ipv6_addr_copy(&fl6.daddr, &treq->rmt_addr);
+       fl6.daddr = treq->rmt_addr;
        final_p = fl6_update_dst(&fl6, np->opt, &final);
-       ipv6_addr_copy(&fl6.saddr, &treq->loc_addr);
+       fl6.saddr = treq->loc_addr;
        fl6.flowi6_oif = sk->sk_bound_dev_if;
        fl6.flowi6_mark = sk->sk_mark;
        fl6.fl6_dport = inet_rsk(req)->rmt_port;
@@ -157,7 +157,7 @@ void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr)
        struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) uaddr;
 
        sin6->sin6_family = AF_INET6;
-       ipv6_addr_copy(&sin6->sin6_addr, &np->daddr);
+       sin6->sin6_addr = np->daddr;
        sin6->sin6_port = inet_sk(sk)->inet_dport;
        /* We do not store received flowlabel for TCP */
        sin6->sin6_flowinfo = 0;
@@ -215,8 +215,8 @@ int inet6_csk_xmit(struct sk_buff *skb, struct flowi *fl_unused)
 
        memset(&fl6, 0, sizeof(fl6));
        fl6.flowi6_proto = sk->sk_protocol;
-       ipv6_addr_copy(&fl6.daddr, &np->daddr);
-       ipv6_addr_copy(&fl6.saddr, &np->saddr);
+       fl6.daddr = np->daddr;
+       fl6.saddr = np->saddr;
        fl6.flowlabel = np->flow_label;
        IP6_ECN_flow_xmit(sk, fl6.flowlabel);
        fl6.flowi6_oif = sk->sk_bound_dev_if;
@@ -246,7 +246,7 @@ int inet6_csk_xmit(struct sk_buff *skb, struct flowi *fl_unused)
        skb_dst_set_noref(skb, dst);
 
        /* Restore final destination back after routing done */
-       ipv6_addr_copy(&fl6.daddr, &np->daddr);
+       fl6.daddr = np->daddr;
 
        res = ip6_xmit(sk, skb, &fl6, np->opt, np->tclass);
        rcu_read_unlock();
index 93718f3..424f063 100644 (file)
@@ -425,7 +425,8 @@ out:
 
 static struct fib6_node * fib6_add_1(struct fib6_node *root, void *addr,
                                     int addrlen, int plen,
-                                    int offset)
+                                    int offset, int allow_create,
+                                    int replace_required)
 {
        struct fib6_node *fn, *in, *ln;
        struct fib6_node *pn = NULL;
@@ -447,8 +448,18 @@ static struct fib6_node * fib6_add_1(struct fib6_node *root, void *addr,
                 *      Prefix match
                 */
                if (plen < fn->fn_bit ||
-                   !ipv6_prefix_equal(&key->addr, addr, fn->fn_bit))
+                   !ipv6_prefix_equal(&key->addr, addr, fn->fn_bit)) {
+                       if (!allow_create) {
+                               if (replace_required) {
+                                       pr_warn("IPv6: Can't replace route, "
+                                               "no match found\n");
+                                       return ERR_PTR(-ENOENT);
+                               }
+                               pr_warn("IPv6: NLM_F_CREATE should be set "
+                                       "when creating new route\n");
+                       }
                        goto insert_above;
+               }
 
                /*
                 *      Exact match ?
@@ -477,6 +488,23 @@ static struct fib6_node * fib6_add_1(struct fib6_node *root, void *addr,
                fn = dir ? fn->right: fn->left;
        } while (fn);
 
+       if (!allow_create) {
+               /* We should not create new node because
+                * NLM_F_REPLACE was specified without NLM_F_CREATE
+                * I assume it is safe to require NLM_F_CREATE when
+                * REPLACE flag is used! Later we may want to remove the
+                * check for replace_required, because according
+                * to netlink specification, NLM_F_CREATE
+                * MUST be specified if new route is created.
+                * That would keep IPv6 consistent with IPv4
+                */
+               if (replace_required) {
+                       pr_warn("IPv6: Can't replace route, no match found\n");
+                       return ERR_PTR(-ENOENT);
+               }
+               pr_warn("IPv6: NLM_F_CREATE should be set "
+                       "when creating new route\n");
+       }
        /*
         *      We walked to the bottom of tree.
         *      Create new leaf node without children.
@@ -614,6 +642,11 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
 {
        struct rt6_info *iter = NULL;
        struct rt6_info **ins;
+       int replace = (NULL != info->nlh &&
+           (info->nlh->nlmsg_flags&NLM_F_REPLACE));
+       int add = (NULL == info->nlh ||
+           (info->nlh->nlmsg_flags&NLM_F_CREATE));
+       int found = 0;
 
        ins = &fn->leaf;
 
@@ -626,6 +659,13 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
                        /*
                         *      Same priority level
                         */
+                       if (NULL != info->nlh &&
+                           (info->nlh->nlmsg_flags&NLM_F_EXCL))
+                               return -EEXIST;
+                       if (replace) {
+                               found++;
+                               break;
+                       }
 
                        if (iter->rt6i_dev == rt->rt6i_dev &&
                            iter->rt6i_idev == rt->rt6i_idev &&
@@ -655,17 +695,40 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
        /*
         *      insert node
         */
+       if (!replace) {
+               if (!add)
+                       pr_warn("IPv6: NLM_F_CREATE should be set when creating new route\n");
+
+add:
+               rt->dst.rt6_next = iter;
+               *ins = rt;
+               rt->rt6i_node = fn;
+               atomic_inc(&rt->rt6i_ref);
+               inet6_rt_notify(RTM_NEWROUTE, rt, info);
+               info->nl_net->ipv6.rt6_stats->fib_rt_entries++;
+
+               if ((fn->fn_flags & RTN_RTINFO) == 0) {
+                       info->nl_net->ipv6.rt6_stats->fib_route_nodes++;
+                       fn->fn_flags |= RTN_RTINFO;
+               }
 
-       rt->dst.rt6_next = iter;
-       *ins = rt;
-       rt->rt6i_node = fn;
-       atomic_inc(&rt->rt6i_ref);
-       inet6_rt_notify(RTM_NEWROUTE, rt, info);
-       info->nl_net->ipv6.rt6_stats->fib_rt_entries++;
-
-       if ((fn->fn_flags & RTN_RTINFO) == 0) {
-               info->nl_net->ipv6.rt6_stats->fib_route_nodes++;
-               fn->fn_flags |= RTN_RTINFO;
+       } else {
+               if (!found) {
+                       if (add)
+                               goto add;
+                       pr_warn("IPv6: NLM_F_REPLACE set, but no existing node found!\n");
+                       return -ENOENT;
+               }
+               *ins = rt;
+               rt->rt6i_node = fn;
+               rt->dst.rt6_next = iter->dst.rt6_next;
+               atomic_inc(&rt->rt6i_ref);
+               inet6_rt_notify(RTM_NEWROUTE, rt, info);
+               rt6_release(iter);
+               if ((fn->fn_flags & RTN_RTINFO) == 0) {
+                       info->nl_net->ipv6.rt6_stats->fib_route_nodes++;
+                       fn->fn_flags |= RTN_RTINFO;
+               }
        }
 
        return 0;
@@ -696,9 +759,25 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info)
 {
        struct fib6_node *fn, *pn = NULL;
        int err = -ENOMEM;
+       int allow_create = 1;
+       int replace_required = 0;
+       if (NULL != info->nlh) {
+               if (!(info->nlh->nlmsg_flags&NLM_F_CREATE))
+                       allow_create = 0;
+               if ((info->nlh->nlmsg_flags&NLM_F_REPLACE))
+                       replace_required = 1;
+       }
+       if (!allow_create && !replace_required)
+               pr_warn("IPv6: RTM_NEWROUTE with no NLM_F_CREATE or NLM_F_REPLACE\n");
 
        fn = fib6_add_1(root, &rt->rt6i_dst.addr, sizeof(struct in6_addr),
-                       rt->rt6i_dst.plen, offsetof(struct rt6_info, rt6i_dst));
+                   rt->rt6i_dst.plen, offsetof(struct rt6_info, rt6i_dst),
+                   allow_create, replace_required);
+
+       if (IS_ERR(fn)) {
+               err = PTR_ERR(fn);
+               fn = NULL;
+       }
 
        if (fn == NULL)
                goto out;
@@ -736,7 +815,8 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info)
 
                        sn = fib6_add_1(sfn, &rt->rt6i_src.addr,
                                        sizeof(struct in6_addr), rt->rt6i_src.plen,
-                                       offsetof(struct rt6_info, rt6i_src));
+                                       offsetof(struct rt6_info, rt6i_src),
+                                       allow_create, replace_required);
 
                        if (sn == NULL) {
                                /* If it is failed, discard just allocated
@@ -753,8 +833,13 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info)
                } else {
                        sn = fib6_add_1(fn->subtree, &rt->rt6i_src.addr,
                                        sizeof(struct in6_addr), rt->rt6i_src.plen,
-                                       offsetof(struct rt6_info, rt6i_src));
+                                       offsetof(struct rt6_info, rt6i_src),
+                                       allow_create, replace_required);
 
+                       if (IS_ERR(sn)) {
+                               err = PTR_ERR(sn);
+                               sn = NULL;
+                       }
                        if (sn == NULL)
                                goto st_failure;
                }
index 4566dbd..b7867a1 100644 (file)
@@ -386,7 +386,7 @@ fl_create(struct net *net, struct sock *sk, struct in6_flowlabel_req *freq,
                err = -EINVAL;
                goto done;
        }
-       ipv6_addr_copy(&fl->dst, &freq->flr_dst);
+       fl->dst = freq->flr_dst;
        atomic_set(&fl->users, 1);
        switch (fl->share) {
        case IPV6_FL_S_EXCL:
index 027c7ff..a46c64e 100644 (file)
@@ -111,6 +111,14 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
            ipv6_addr_loopback(&hdr->daddr))
                goto err;
 
+       /*
+        * RFC4291 2.7
+        * Multicast addresses must not be used as source addresses in IPv6
+        * packets or appear in any Routing header.
+        */
+       if (ipv6_addr_is_multicast(&hdr->saddr))
+               goto err;
+
        skb->transport_header = skb->network_header + sizeof(*hdr);
        IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr);
 
index 84d0bd5..a24e155 100644 (file)
@@ -238,8 +238,8 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
        hdr->nexthdr = proto;
        hdr->hop_limit = hlimit;
 
-       ipv6_addr_copy(&hdr->saddr, &fl6->saddr);
-       ipv6_addr_copy(&hdr->daddr, first_hop);
+       hdr->saddr = fl6->saddr;
+       hdr->daddr = *first_hop;
 
        skb->priority = sk->sk_priority;
        skb->mark = sk->sk_mark;
@@ -290,8 +290,8 @@ int ip6_nd_hdr(struct sock *sk, struct sk_buff *skb, struct net_device *dev,
        hdr->nexthdr = proto;
        hdr->hop_limit = np->hop_limit;
 
-       ipv6_addr_copy(&hdr->saddr, saddr);
-       ipv6_addr_copy(&hdr->daddr, daddr);
+       hdr->saddr = *saddr;
+       hdr->daddr = *daddr;
 
        return 0;
 }
@@ -631,6 +631,7 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
        struct ipv6hdr *tmp_hdr;
        struct frag_hdr *fh;
        unsigned int mtu, hlen, left, len;
+       int hroom, troom;
        __be32 frag_id = 0;
        int ptr, offset = 0, err=0;
        u8 *prevhdr, nexthdr = 0;
@@ -797,6 +798,8 @@ slow_path:
         */
 
        *prevhdr = NEXTHDR_FRAGMENT;
+       hroom = LL_RESERVED_SPACE(rt->dst.dev);
+       troom = rt->dst.dev->needed_tailroom;
 
        /*
         *      Keep copying data until we run out.
@@ -815,7 +818,8 @@ slow_path:
                 *      Allocate buffer.
                 */
 
-               if ((frag = alloc_skb(len+hlen+sizeof(struct frag_hdr)+LL_ALLOCATED_SPACE(rt->dst.dev), GFP_ATOMIC)) == NULL) {
+               if ((frag = alloc_skb(len + hlen + sizeof(struct frag_hdr) +
+                                     hroom + troom, GFP_ATOMIC)) == NULL) {
                        NETDEBUG(KERN_INFO "IPv6: frag: no memory for new fragment!\n");
                        IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
                                      IPSTATS_MIB_FRAGFAILS);
@@ -828,7 +832,7 @@ slow_path:
                 */
 
                ip6_copy_metadata(frag, skb);
-               skb_reserve(frag, LL_RESERVED_SPACE(rt->dst.dev));
+               skb_reserve(frag, hroom);
                skb_put(frag, len + hlen + sizeof(struct frag_hdr));
                skb_reset_network_header(frag);
                fh = (struct frag_hdr *)(skb_network_header(frag) + hlen);
@@ -1059,7 +1063,7 @@ struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6,
        if (err)
                return ERR_PTR(err);
        if (final_dst)
-               ipv6_addr_copy(&fl6->daddr, final_dst);
+               fl6->daddr = *final_dst;
        if (can_sleep)
                fl6->flowi6_flags |= FLOWI_FLAG_CAN_SLEEP;
 
@@ -1095,7 +1099,7 @@ struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6,
        if (err)
                return ERR_PTR(err);
        if (final_dst)
-               ipv6_addr_copy(&fl6->daddr, final_dst);
+               fl6->daddr = *final_dst;
        if (can_sleep)
                fl6->flowi6_flags |= FLOWI_FLAG_CAN_SLEEP;
 
@@ -1588,7 +1592,7 @@ int ip6_push_pending_frames(struct sock *sk)
        if (np->pmtudisc < IPV6_PMTUDISC_DO)
                skb->local_df = 1;
 
-       ipv6_addr_copy(final_dst, &fl6->daddr);
+       *final_dst = fl6->daddr;
        __skb_pull(skb, skb_network_header_len(skb));
        if (opt && opt->opt_flen)
                ipv6_push_frag_opts(skb, opt, &proto);
@@ -1604,8 +1608,8 @@ int ip6_push_pending_frames(struct sock *sk)
 
        hdr->hop_limit = np->cork.hop_limit;
        hdr->nexthdr = proto;
-       ipv6_addr_copy(&hdr->saddr, &fl6->saddr);
-       ipv6_addr_copy(&hdr->daddr, final_dst);
+       hdr->saddr = fl6->saddr;
+       hdr->daddr = *final_dst;
 
        skb->priority = sk->sk_priority;
        skb->mark = sk->sk_mark;
index bdc15c9..f5f98f5 100644 (file)
@@ -93,7 +93,7 @@ struct pcpu_tstats {
        unsigned long   rx_bytes;
        unsigned long   tx_packets;
        unsigned long   tx_bytes;
-};
+} __attribute__((aligned(4*sizeof(unsigned long))));
 
 static struct net_device_stats *ip6_get_stats(struct net_device *dev)
 {
@@ -289,6 +289,8 @@ static struct ip6_tnl *ip6_tnl_create(struct net *net, struct ip6_tnl_parm *p)
        if ((err = register_netdevice(dev)) < 0)
                goto failed_free;
 
+       strcpy(t->parms.name, dev->name);
+
        dev_hold(dev);
        ip6_tnl_link(ip6n, t);
        return t;
@@ -977,8 +979,8 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
        ipv6_change_dsfield(ipv6h, ~INET_ECN_MASK, dsfield);
        ipv6h->hop_limit = t->parms.hop_limit;
        ipv6h->nexthdr = proto;
-       ipv6_addr_copy(&ipv6h->saddr, &fl6->saddr);
-       ipv6_addr_copy(&ipv6h->daddr, &fl6->daddr);
+       ipv6h->saddr = fl6->saddr;
+       ipv6h->daddr = fl6->daddr;
        nf_reset(skb);
        pkt_len = skb->len;
        err = ip6_local_out(skb);
@@ -1153,8 +1155,8 @@ static void ip6_tnl_link_config(struct ip6_tnl *t)
        memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr));
 
        /* Set up flowi template */
-       ipv6_addr_copy(&fl6->saddr, &p->laddr);
-       ipv6_addr_copy(&fl6->daddr, &p->raddr);
+       fl6->saddr = p->laddr;
+       fl6->daddr = p->raddr;
        fl6->flowi6_oif = p->link;
        fl6->flowlabel = 0;
 
@@ -1210,8 +1212,8 @@ static void ip6_tnl_link_config(struct ip6_tnl *t)
 static int
 ip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p)
 {
-       ipv6_addr_copy(&t->parms.laddr, &p->laddr);
-       ipv6_addr_copy(&t->parms.raddr, &p->raddr);
+       t->parms.laddr = p->laddr;
+       t->parms.raddr = p->raddr;
        t->parms.flags = p->flags;
        t->parms.hop_limit = p->hop_limit;
        t->parms.encap_limit = p->encap_limit;
@@ -1407,7 +1409,6 @@ ip6_tnl_dev_init_gen(struct net_device *dev)
        struct ip6_tnl *t = netdev_priv(dev);
 
        t->dev = dev;
-       strcpy(t->parms.name, dev->name);
        dev->tstats = alloc_percpu(struct pcpu_tstats);
        if (!dev->tstats)
                return -ENOMEM;
@@ -1487,6 +1488,7 @@ static void __net_exit ip6_tnl_destroy_tunnels(struct ip6_tnl_net *ip6n)
 static int __net_init ip6_tnl_init_net(struct net *net)
 {
        struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
+       struct ip6_tnl *t = NULL;
        int err;
 
        ip6n->tnls[0] = ip6n->tnls_wc;
@@ -1507,6 +1509,10 @@ static int __net_init ip6_tnl_init_net(struct net *net)
        err = register_netdev(ip6n->fb_tnl_dev);
        if (err < 0)
                goto err_register;
+
+       t = netdev_priv(ip6n->fb_tnl_dev);
+
+       strcpy(t->parms.name, ip6n->fb_tnl_dev->name);
        return 0;
 
 err_register:
index 449a918..c7e95c8 100644 (file)
@@ -1105,8 +1105,8 @@ static int ip6mr_cache_report(struct mr6_table *mrt, struct sk_buff *pkt,
                msg->im6_msgtype = MRT6MSG_WHOLEPKT;
                msg->im6_mif = mrt->mroute_reg_vif_num;
                msg->im6_pad = 0;
-               ipv6_addr_copy(&msg->im6_src, &ipv6_hdr(pkt)->saddr);
-               ipv6_addr_copy(&msg->im6_dst, &ipv6_hdr(pkt)->daddr);
+               msg->im6_src = ipv6_hdr(pkt)->saddr;
+               msg->im6_dst = ipv6_hdr(pkt)->daddr;
 
                skb->ip_summed = CHECKSUM_UNNECESSARY;
        } else
@@ -1131,8 +1131,8 @@ static int ip6mr_cache_report(struct mr6_table *mrt, struct sk_buff *pkt,
        msg->im6_msgtype = assert;
        msg->im6_mif = mifi;
        msg->im6_pad = 0;
-       ipv6_addr_copy(&msg->im6_src, &ipv6_hdr(pkt)->saddr);
-       ipv6_addr_copy(&msg->im6_dst, &ipv6_hdr(pkt)->daddr);
+       msg->im6_src = ipv6_hdr(pkt)->saddr;
+       msg->im6_dst = ipv6_hdr(pkt)->daddr;
 
        skb_dst_set(skb, dst_clone(skb_dst(pkt)));
        skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -2181,8 +2181,8 @@ int ip6mr_get_route(struct net *net,
                iph->payload_len = 0;
                iph->nexthdr = IPPROTO_NONE;
                iph->hop_limit = 0;
-               ipv6_addr_copy(&iph->saddr, &rt->rt6i_src.addr);
-               ipv6_addr_copy(&iph->daddr, &rt->rt6i_dst.addr);
+               iph->saddr = rt->rt6i_src.addr;
+               iph->daddr = rt->rt6i_dst.addr;
 
                err = ip6mr_cache_unresolved(mrt, vif, skb2);
                read_unlock(&mrt_lock);
index c99e3ee..29993b7 100644 (file)
@@ -435,7 +435,7 @@ sticky_done:
                        goto e_inval;
 
                np->sticky_pktinfo.ipi6_ifindex = pkt.ipi6_ifindex;
-               ipv6_addr_copy(&np->sticky_pktinfo.ipi6_addr, &pkt.ipi6_addr);
+               np->sticky_pktinfo.ipi6_addr = pkt.ipi6_addr;
                retv = 0;
                break;
        }
@@ -980,8 +980,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
                                struct in6_pktinfo src_info;
                                src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif :
                                        np->sticky_pktinfo.ipi6_ifindex;
-                               np->mcast_oif? ipv6_addr_copy(&src_info.ipi6_addr, &np->daddr) :
-                                       ipv6_addr_copy(&src_info.ipi6_addr, &(np->sticky_pktinfo.ipi6_addr));
+                               src_info.ipi6_addr = np->mcast_oif ? np->daddr : np->sticky_pktinfo.ipi6_addr;
                                put_cmsg(&msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info);
                        }
                        if (np->rxopt.bits.rxhlim) {
@@ -992,8 +991,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
                                struct in6_pktinfo src_info;
                                src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif :
                                        np->sticky_pktinfo.ipi6_ifindex;
-                               np->mcast_oif? ipv6_addr_copy(&src_info.ipi6_addr, &np->daddr) :
-                                       ipv6_addr_copy(&src_info.ipi6_addr, &(np->sticky_pktinfo.ipi6_addr));
+                               src_info.ipi6_addr = np->mcast_oif ? np->daddr : np->sticky_pktinfo.ipi6_addr;
                                put_cmsg(&msg, SOL_IPV6, IPV6_2292PKTINFO, sizeof(src_info), &src_info);
                        }
                        if (np->rxopt.bits.rxohlim) {
index ee7839f..6cc4d1f 100644 (file)
@@ -155,7 +155,7 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
                return -ENOMEM;
 
        mc_lst->next = NULL;
-       ipv6_addr_copy(&mc_lst->addr, addr);
+       mc_lst->addr = *addr;
 
        rcu_read_lock();
        if (ifindex == 0) {
@@ -858,7 +858,7 @@ int ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr)
 
        setup_timer(&mc->mca_timer, igmp6_timer_handler, (unsigned long)mc);
 
-       ipv6_addr_copy(&mc->mca_addr, addr);
+       mc->mca_addr = *addr;
        mc->idev = idev; /* (reference taken) */
        mc->mca_users = 1;
        /* mca_stamp should be updated upon changes */
@@ -1343,13 +1343,15 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size)
        struct mld2_report *pmr;
        struct in6_addr addr_buf;
        const struct in6_addr *saddr;
+       int hlen = LL_RESERVED_SPACE(dev);
+       int tlen = dev->needed_tailroom;
        int err;
        u8 ra[8] = { IPPROTO_ICMPV6, 0,
                     IPV6_TLV_ROUTERALERT, 2, 0, 0,
                     IPV6_TLV_PADN, 0 };
 
        /* we assume size > sizeof(ra) here */
-       size += LL_ALLOCATED_SPACE(dev);
+       size += hlen + tlen;
        /* limit our allocations to order-0 page */
        size = min_t(int, size, SKB_MAX_ORDER(0, 0));
        skb = sock_alloc_send_skb(sk, size, 1, &err);
@@ -1357,7 +1359,7 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size)
        if (!skb)
                return NULL;
 
-       skb_reserve(skb, LL_RESERVED_SPACE(dev));
+       skb_reserve(skb, hlen);
 
        if (ipv6_get_lladdr(dev, &addr_buf, IFA_F_TENTATIVE)) {
                /* <draft-ietf-magma-mld-source-05.txt>:
@@ -1723,6 +1725,8 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
        struct mld_msg *hdr;
        const struct in6_addr *snd_addr, *saddr;
        struct in6_addr addr_buf;
+       int hlen = LL_RESERVED_SPACE(dev);
+       int tlen = dev->needed_tailroom;
        int err, len, payload_len, full_len;
        u8 ra[8] = { IPPROTO_ICMPV6, 0,
                     IPV6_TLV_ROUTERALERT, 2, 0, 0,
@@ -1744,7 +1748,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
                      IPSTATS_MIB_OUT, full_len);
        rcu_read_unlock();
 
-       skb = sock_alloc_send_skb(sk, LL_ALLOCATED_SPACE(dev) + full_len, 1, &err);
+       skb = sock_alloc_send_skb(sk, hlen + tlen + full_len, 1, &err);
 
        if (skb == NULL) {
                rcu_read_lock();
@@ -1754,7 +1758,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
                return;
        }
 
-       skb_reserve(skb, LL_RESERVED_SPACE(dev));
+       skb_reserve(skb, hlen);
 
        if (ipv6_get_lladdr(dev, &addr_buf, IFA_F_TENTATIVE)) {
                /* <draft-ietf-magma-mld-source-05.txt>:
@@ -1772,7 +1776,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
        hdr = (struct mld_msg *) skb_put(skb, sizeof(struct mld_msg));
        memset(hdr, 0, sizeof(struct mld_msg));
        hdr->mld_type = type;
-       ipv6_addr_copy(&hdr->mld_mca, addr);
+       hdr->mld_mca = *addr;
 
        hdr->mld_cksum = csum_ipv6_magic(saddr, snd_addr, len,
                                         IPPROTO_ICMPV6,
index 43242e6..7e1e0fb 100644 (file)
@@ -195,8 +195,8 @@ static inline int mip6_report_rl_allow(struct timeval *stamp,
                mip6_report_rl.stamp.tv_sec = stamp->tv_sec;
                mip6_report_rl.stamp.tv_usec = stamp->tv_usec;
                mip6_report_rl.iif = iif;
-               ipv6_addr_copy(&mip6_report_rl.src, src);
-               ipv6_addr_copy(&mip6_report_rl.dst, dst);
+               mip6_report_rl.src = *src;
+               mip6_report_rl.dst = *dst;
                allow = 1;
        }
        spin_unlock_bh(&mip6_report_rl.lock);
index 44e5b7f..a476988 100644 (file)
@@ -141,7 +141,7 @@ struct neigh_table nd_tbl = {
                .gc_staletime           = 60 * HZ,
                .reachable_time         = ND_REACHABLE_TIME,
                .delay_probe_time       = 5 * HZ,
-               .queue_len              = 3,
+               .queue_len_bytes        = 64*1024,
                .ucast_probes           = 3,
                .mcast_probes           = 3,
                .anycast_delay          = 1 * HZ,
@@ -446,6 +446,8 @@ struct sk_buff *ndisc_build_skb(struct net_device *dev,
        struct sock *sk = net->ipv6.ndisc_sk;
        struct sk_buff *skb;
        struct icmp6hdr *hdr;
+       int hlen = LL_RESERVED_SPACE(dev);
+       int tlen = dev->needed_tailroom;
        int len;
        int err;
        u8 *opt;
@@ -459,7 +461,7 @@ struct sk_buff *ndisc_build_skb(struct net_device *dev,
 
        skb = sock_alloc_send_skb(sk,
                                  (MAX_HEADER + sizeof(struct ipv6hdr) +
-                                  len + LL_ALLOCATED_SPACE(dev)),
+                                  len + hlen + tlen),
                                  1, &err);
        if (!skb) {
                ND_PRINTK0(KERN_ERR
@@ -468,7 +470,7 @@ struct sk_buff *ndisc_build_skb(struct net_device *dev,
                return NULL;
        }
 
-       skb_reserve(skb, LL_RESERVED_SPACE(dev));
+       skb_reserve(skb, hlen);
        ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len);
 
        skb->transport_header = skb->tail;
@@ -479,7 +481,7 @@ struct sk_buff *ndisc_build_skb(struct net_device *dev,
 
        opt = skb_transport_header(skb) + sizeof(struct icmp6hdr);
        if (target) {
-               ipv6_addr_copy((struct in6_addr *)opt, target);
+               *(struct in6_addr *)opt = *target;
                opt += sizeof(*target);
        }
 
@@ -1533,6 +1535,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
        struct inet6_dev *idev;
        struct flowi6 fl6;
        u8 *opt;
+       int hlen, tlen;
        int rd_len;
        int err;
        u8 ha_buf[MAX_ADDR_LEN], *ha = NULL;
@@ -1590,9 +1593,11 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
        rd_len &= ~0x7;
        len += rd_len;
 
+       hlen = LL_RESERVED_SPACE(dev);
+       tlen = dev->needed_tailroom;
        buff = sock_alloc_send_skb(sk,
                                   (MAX_HEADER + sizeof(struct ipv6hdr) +
-                                   len + LL_ALLOCATED_SPACE(dev)),
+                                   len + hlen + tlen),
                                   1, &err);
        if (buff == NULL) {
                ND_PRINTK0(KERN_ERR
@@ -1601,7 +1606,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
                goto release;
        }
 
-       skb_reserve(buff, LL_RESERVED_SPACE(dev));
+       skb_reserve(buff, hlen);
        ip6_nd_hdr(sk, buff, dev, &saddr_buf, &ipv6_hdr(skb)->saddr,
                   IPPROTO_ICMPV6, len);
 
@@ -1617,9 +1622,9 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
         */
 
        addrp = (struct in6_addr *)(icmph + 1);
-       ipv6_addr_copy(addrp, target);
+       *addrp = *target;
        addrp++;
-       ipv6_addr_copy(addrp, &ipv6_hdr(skb)->daddr);
+       *addrp = ipv6_hdr(skb)->daddr;
 
        opt = (u8*) (addrp + 1);
 
index a5a4c5d..b5a2aa5 100644 (file)
@@ -93,8 +93,8 @@ static void send_reset(struct net *net, struct sk_buff *oldskb)
 
        memset(&fl6, 0, sizeof(fl6));
        fl6.flowi6_proto = IPPROTO_TCP;
-       ipv6_addr_copy(&fl6.saddr, &oip6h->daddr);
-       ipv6_addr_copy(&fl6.daddr, &oip6h->saddr);
+       fl6.saddr = oip6h->daddr;
+       fl6.daddr = oip6h->saddr;
        fl6.fl6_sport = otcph.dest;
        fl6.fl6_dport = otcph.source;
        security_skb_classify_flow(oldskb, flowi6_to_flowi(&fl6));
@@ -129,8 +129,8 @@ static void send_reset(struct net *net, struct sk_buff *oldskb)
        *(__be32 *)ip6h =  htonl(0x60000000 | (tclass << 20));
        ip6h->hop_limit = ip6_dst_hoplimit(dst);
        ip6h->nexthdr = IPPROTO_TCP;
-       ipv6_addr_copy(&ip6h->saddr, &oip6h->daddr);
-       ipv6_addr_copy(&ip6h->daddr, &oip6h->saddr);
+       ip6h->saddr = oip6h->daddr;
+       ip6h->daddr = oip6h->saddr;
 
        tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr));
        /* Truncate to length (no data) */
index 1008ce9..fdeb6d0 100644 (file)
@@ -142,11 +142,7 @@ static const struct snmp_mib snmp6_udplite6_list[] = {
        SNMP_MIB_SENTINEL
 };
 
-/* can be called either with percpu mib (pcpumib != NULL),
- * or shared one (smib != NULL)
- */
-static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void __percpu **pcpumib,
-                                    atomic_long_t *smib)
+static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, atomic_long_t *smib)
 {
        char name[32];
        int i;
@@ -163,14 +159,14 @@ static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void __percpu **pcpum
                snprintf(name, sizeof(name), "Icmp6%s%s",
                        i & 0x100 ? "Out" : "In", p);
                seq_printf(seq, "%-32s\t%lu\n", name,
-                       pcpumib ? snmp_fold_field(pcpumib, i) : atomic_long_read(smib + i));
+                          atomic_long_read(smib + i));
        }
 
        /* print by number (nonzero only) - ICMPMsgStat format */
        for (i = 0; i < ICMP6MSG_MIB_MAX; i++) {
                unsigned long val;
 
-               val = pcpumib ? snmp_fold_field(pcpumib, i) : atomic_long_read(smib + i);
+               val = atomic_long_read(smib + i);
                if (!val)
                        continue;
                snprintf(name, sizeof(name), "Icmp6%sType%u",
@@ -215,8 +211,7 @@ static int snmp6_seq_show(struct seq_file *seq, void *v)
                            snmp6_ipstats_list, offsetof(struct ipstats_mib, syncp));
        snmp6_seq_show_item(seq, (void __percpu **)net->mib.icmpv6_statistics,
                            NULL, snmp6_icmp6_list);
-       snmp6_seq_show_icmpv6msg(seq,
-                           (void __percpu **)net->mib.icmpv6msg_statistics, NULL);
+       snmp6_seq_show_icmpv6msg(seq, net->mib.icmpv6msg_statistics->mibs);
        snmp6_seq_show_item(seq, (void __percpu **)net->mib.udp_stats_in6,
                            NULL, snmp6_udp6_list);
        snmp6_seq_show_item(seq, (void __percpu **)net->mib.udplite_stats_in6,
@@ -246,7 +241,7 @@ static int snmp6_dev_seq_show(struct seq_file *seq, void *v)
                            snmp6_ipstats_list);
        snmp6_seq_show_item(seq, NULL, idev->stats.icmpv6dev->mibs,
                            snmp6_icmp6_list);
-       snmp6_seq_show_icmpv6msg(seq, NULL, idev->stats.icmpv6msgdev->mibs);
+       snmp6_seq_show_icmpv6msg(seq, idev->stats.icmpv6msgdev->mibs);
        return 0;
 }
 
index 331af3b..a4894f4 100644 (file)
@@ -299,9 +299,9 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
        }
 
        inet->inet_rcv_saddr = inet->inet_saddr = v4addr;
-       ipv6_addr_copy(&np->rcv_saddr, &addr->sin6_addr);
+       np->rcv_saddr = addr->sin6_addr;
        if (!(addr_type & IPV6_ADDR_MULTICAST))
-               ipv6_addr_copy(&np->saddr, &addr->sin6_addr);
+               np->saddr = addr->sin6_addr;
        err = 0;
 out_unlock:
        rcu_read_unlock();
@@ -383,7 +383,8 @@ static inline int rawv6_rcv_skb(struct sock *sk, struct sk_buff *skb)
        }
 
        /* Charge it to the socket. */
-       if (ip_queue_rcv_skb(sk, skb) < 0) {
+       skb_dst_drop(skb);
+       if (sock_queue_rcv_skb(sk, skb) < 0) {
                kfree_skb(skb);
                return NET_RX_DROP;
        }
@@ -494,7 +495,7 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk,
        if (sin6) {
                sin6->sin6_family = AF_INET6;
                sin6->sin6_port = 0;
-               ipv6_addr_copy(&sin6->sin6_addr, &ipv6_hdr(skb)->saddr);
+               sin6->sin6_addr = ipv6_hdr(skb)->saddr;
                sin6->sin6_flowinfo = 0;
                sin6->sin6_scope_id = 0;
                if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
@@ -610,6 +611,8 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length,
        struct sk_buff *skb;
        int err;
        struct rt6_info *rt = (struct rt6_info *)*dstp;
+       int hlen = LL_RESERVED_SPACE(rt->dst.dev);
+       int tlen = rt->dst.dev->needed_tailroom;
 
        if (length > rt->dst.dev->mtu) {
                ipv6_local_error(sk, EMSGSIZE, fl6, rt->dst.dev->mtu);
@@ -619,11 +622,11 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length,
                goto out;
 
        skb = sock_alloc_send_skb(sk,
-                                 length + LL_ALLOCATED_SPACE(rt->dst.dev) + 15,
+                                 length + hlen + tlen + 15,
                                  flags & MSG_DONTWAIT, &err);
        if (skb == NULL)
                goto error;
-       skb_reserve(skb, LL_RESERVED_SPACE(rt->dst.dev));
+       skb_reserve(skb, hlen);
 
        skb->priority = sk->sk_priority;
        skb->mark = sk->sk_mark;
@@ -843,11 +846,11 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
                goto out;
 
        if (!ipv6_addr_any(daddr))
-               ipv6_addr_copy(&fl6.daddr, daddr);
+               fl6.daddr = *daddr;
        else
                fl6.daddr.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */
        if (ipv6_addr_any(&fl6.saddr) && !ipv6_addr_any(&np->saddr))
-               ipv6_addr_copy(&fl6.saddr, &np->saddr);
+               fl6.saddr = np->saddr;
 
        final_p = fl6_update_dst(&fl6, opt, &final);
 
index dfb164e..b69fae7 100644 (file)
@@ -153,8 +153,8 @@ void ip6_frag_init(struct inet_frag_queue *q, void *a)
 
        fq->id = arg->id;
        fq->user = arg->user;
-       ipv6_addr_copy(&fq->saddr, arg->src);
-       ipv6_addr_copy(&fq->daddr, arg->dst);
+       fq->saddr = *arg->src;
+       fq->daddr = *arg->dst;
 }
 EXPORT_SYMBOL(ip6_frag_init);
 
index 8473016..2897403 100644 (file)
@@ -729,14 +729,14 @@ static struct rt6_info *rt6_alloc_cow(const struct rt6_info *ort,
                        if (rt->rt6i_dst.plen != 128 &&
                            ipv6_addr_equal(&ort->rt6i_dst.addr, daddr))
                                rt->rt6i_flags |= RTF_ANYCAST;
-                       ipv6_addr_copy(&rt->rt6i_gateway, daddr);
+                       rt->rt6i_gateway = *daddr;
                }
 
                rt->rt6i_flags |= RTF_CACHE;
 
 #ifdef CONFIG_IPV6_SUBTREES
                if (rt->rt6i_src.plen && saddr) {
-                       ipv6_addr_copy(&rt->rt6i_src.addr, saddr);
+                       rt->rt6i_src.addr = *saddr;
                        rt->rt6i_src.plen = 128;
                }
 #endif
@@ -932,7 +932,7 @@ struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_ori
                        in6_dev_hold(rt->rt6i_idev);
                rt->rt6i_expires = 0;
 
-               ipv6_addr_copy(&rt->rt6i_gateway, &ort->rt6i_gateway);
+               rt->rt6i_gateway = ort->rt6i_gateway;
                rt->rt6i_flags = ort->rt6i_flags & ~RTF_EXPIRES;
                rt->rt6i_metric = 0;
 
@@ -1087,7 +1087,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
        rt->dst.output  = ip6_output;
        dst_set_neighbour(&rt->dst, neigh);
        atomic_set(&rt->dst.__refcnt, 1);
-       ipv6_addr_copy(&rt->rt6i_dst.addr, addr);
+       rt->rt6i_dst.addr = *addr;
        rt->rt6i_dst.plen = 128;
        rt->rt6i_idev     = idev;
        dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 255);
@@ -1230,9 +1230,18 @@ int ip6_route_add(struct fib6_config *cfg)
        if (cfg->fc_metric == 0)
                cfg->fc_metric = IP6_RT_PRIO_USER;
 
-       table = fib6_new_table(net, cfg->fc_table);
+       err = -ENOBUFS;
+       if (NULL != cfg->fc_nlinfo.nlh &&
+           !(cfg->fc_nlinfo.nlh->nlmsg_flags&NLM_F_CREATE)) {
+               table = fib6_get_table(net, cfg->fc_table);
+               if (table == NULL) {
+                       printk(KERN_WARNING "IPv6: NLM_F_CREATE should be specified when creating new route\n");
+                       table = fib6_new_table(net, cfg->fc_table);
+               }
+       } else {
+               table = fib6_new_table(net, cfg->fc_table);
+       }
        if (table == NULL) {
-               err = -ENOBUFS;
                goto out;
        }
 
@@ -1315,7 +1324,7 @@ int ip6_route_add(struct fib6_config *cfg)
                int gwa_type;
 
                gw_addr = &cfg->fc_gateway;
-               ipv6_addr_copy(&rt->rt6i_gateway, gw_addr);
+               rt->rt6i_gateway = *gw_addr;
                gwa_type = ipv6_addr_type(gw_addr);
 
                if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) {
@@ -1369,7 +1378,7 @@ int ip6_route_add(struct fib6_config *cfg)
                        err = -EINVAL;
                        goto out;
                }
-               ipv6_addr_copy(&rt->rt6i_prefsrc.addr, &cfg->fc_prefsrc);
+               rt->rt6i_prefsrc.addr = cfg->fc_prefsrc;
                rt->rt6i_prefsrc.plen = 128;
        } else
                rt->rt6i_prefsrc.plen = 0;
@@ -1566,7 +1575,7 @@ static struct rt6_info *ip6_route_redirect(const struct in6_addr *dest,
                },
        };
 
-       ipv6_addr_copy(&rdfl.gateway, gateway);
+       rdfl.gateway = *gateway;
 
        if (rt6_need_strict(dest))
                flags |= RT6_LOOKUP_F_IFACE;
@@ -1622,7 +1631,7 @@ void rt6_redirect(const struct in6_addr *dest, const struct in6_addr *src,
        if (on_link)
                nrt->rt6i_flags &= ~RTF_GATEWAY;
 
-       ipv6_addr_copy(&nrt->rt6i_gateway, (struct in6_addr*)neigh->primary_key);
+       nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
        dst_set_neighbour(&nrt->dst, neigh_clone(neigh));
 
        if (ip6_ins_rt(nrt))
@@ -1768,7 +1777,7 @@ static struct rt6_info *ip6_rt_copy(const struct rt6_info *ort,
                rt->dst.output = ort->dst.output;
                rt->dst.flags |= DST_HOST;
 
-               ipv6_addr_copy(&rt->rt6i_dst.addr, dest);
+               rt->rt6i_dst.addr = *dest;
                rt->rt6i_dst.plen = 128;
                dst_copy_metrics(&rt->dst, &ort->dst);
                rt->dst.error = ort->dst.error;
@@ -1778,7 +1787,7 @@ static struct rt6_info *ip6_rt_copy(const struct rt6_info *ort,
                rt->dst.lastuse = jiffies;
                rt->rt6i_expires = 0;
 
-               ipv6_addr_copy(&rt->rt6i_gateway, &ort->rt6i_gateway);
+               rt->rt6i_gateway = ort->rt6i_gateway;
                rt->rt6i_flags = ort->rt6i_flags & ~RTF_EXPIRES;
                rt->rt6i_metric = 0;
 
@@ -1841,8 +1850,8 @@ static struct rt6_info *rt6_add_route_info(struct net *net,
                .fc_nlinfo.nl_net = net,
        };
 
-       ipv6_addr_copy(&cfg.fc_dst, prefix);
-       ipv6_addr_copy(&cfg.fc_gateway, gwaddr);
+       cfg.fc_dst = *prefix;
+       cfg.fc_gateway = *gwaddr;
 
        /* We should treat it as a default route if prefix length is 0. */
        if (!prefixlen)
@@ -1891,7 +1900,7 @@ struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr,
                .fc_nlinfo.nl_net = dev_net(dev),
        };
 
-       ipv6_addr_copy(&cfg.fc_gateway, gwaddr);
+       cfg.fc_gateway = *gwaddr;
 
        ip6_route_add(&cfg);
 
@@ -1937,9 +1946,9 @@ static void rtmsg_to_fib6_config(struct net *net,
 
        cfg->fc_nlinfo.nl_net = net;
 
-       ipv6_addr_copy(&cfg->fc_dst, &rtmsg->rtmsg_dst);
-       ipv6_addr_copy(&cfg->fc_src, &rtmsg->rtmsg_src);
-       ipv6_addr_copy(&cfg->fc_gateway, &rtmsg->rtmsg_gateway);
+       cfg->fc_dst = rtmsg->rtmsg_dst;
+       cfg->fc_src = rtmsg->rtmsg_src;
+       cfg->fc_gateway = rtmsg->rtmsg_gateway;
 }
 
 int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
@@ -2073,7 +2082,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
        }
        dst_set_neighbour(&rt->dst, neigh);
 
-       ipv6_addr_copy(&rt->rt6i_dst.addr, addr);
+       rt->rt6i_dst.addr = *addr;
        rt->rt6i_dst.plen = 128;
        rt->rt6i_table = fib6_get_table(net, RT6_TABLE_LOCAL);
 
@@ -2091,7 +2100,7 @@ int ip6_route_get_saddr(struct net *net,
        struct inet6_dev *idev = ip6_dst_idev((struct dst_entry*)rt);
        int err = 0;
        if (rt->rt6i_prefsrc.plen)
-               ipv6_addr_copy(saddr, &rt->rt6i_prefsrc.addr);
+               *saddr = rt->rt6i_prefsrc.addr;
        else
                err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
                                         daddr, prefs, saddr);
@@ -2430,7 +2439,7 @@ static int rt6_fill_node(struct net *net,
 
        if (rt->rt6i_prefsrc.plen) {
                struct in6_addr saddr_buf;
-               ipv6_addr_copy(&saddr_buf, &rt->rt6i_prefsrc.addr);
+               saddr_buf = rt->rt6i_prefsrc.addr;
                NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf);
        }
 
@@ -2504,14 +2513,14 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
                if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))
                        goto errout;
 
-               ipv6_addr_copy(&fl6.saddr, nla_data(tb[RTA_SRC]));
+               fl6.saddr = *(struct in6_addr *)nla_data(tb[RTA_SRC]);
        }
 
        if (tb[RTA_DST]) {
                if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr))
                        goto errout;
 
-               ipv6_addr_copy(&fl6.daddr, nla_data(tb[RTA_DST]));
+               fl6.daddr = *(struct in6_addr *)nla_data(tb[RTA_DST]);
        }
 
        if (tb[RTA_IIF])
index a7a1860..50968f2 100644 (file)
@@ -91,7 +91,7 @@ struct pcpu_tstats {
        unsigned long   rx_bytes;
        unsigned long   tx_packets;
        unsigned long   tx_bytes;
-};
+} __attribute__((aligned(4*sizeof(unsigned long))));
 
 static struct net_device_stats *ipip6_get_stats(struct net_device *dev)
 {
@@ -914,7 +914,7 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
                                goto done;
 #ifdef CONFIG_IPV6_SIT_6RD
                } else {
-                       ipv6_addr_copy(&ip6rd.prefix, &t->ip6rd.prefix);
+                       ip6rd.prefix = t->ip6rd.prefix;
                        ip6rd.relay_prefix = t->ip6rd.relay_prefix;
                        ip6rd.prefixlen = t->ip6rd.prefixlen;
                        ip6rd.relay_prefixlen = t->ip6rd.relay_prefixlen;
@@ -1082,7 +1082,7 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
                        if (relay_prefix != ip6rd.relay_prefix)
                                goto done;
 
-                       ipv6_addr_copy(&t->ip6rd.prefix, &prefix);
+                       t->ip6rd.prefix = prefix;
                        t->ip6rd.relay_prefix = relay_prefix;
                        t->ip6rd.prefixlen = ip6rd.prefixlen;
                        t->ip6rd.relay_prefixlen = ip6rd.relay_prefixlen;
index 5a0d664..8e951d8 100644 (file)
@@ -200,8 +200,8 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
        req->mss = mss;
        ireq->rmt_port = th->source;
        ireq->loc_port = th->dest;
-       ipv6_addr_copy(&ireq6->rmt_addr, &ipv6_hdr(skb)->saddr);
-       ipv6_addr_copy(&ireq6->loc_addr, &ipv6_hdr(skb)->daddr);
+       ireq6->rmt_addr = ipv6_hdr(skb)->saddr;
+       ireq6->loc_addr = ipv6_hdr(skb)->daddr;
        if (ipv6_opt_accepted(sk, skb) ||
            np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
            np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
@@ -237,9 +237,9 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
                struct flowi6 fl6;
                memset(&fl6, 0, sizeof(fl6));
                fl6.flowi6_proto = IPPROTO_TCP;
-               ipv6_addr_copy(&fl6.daddr, &ireq6->rmt_addr);
+               fl6.daddr = ireq6->rmt_addr;
                final_p = fl6_update_dst(&fl6, np->opt, &final);
-               ipv6_addr_copy(&fl6.saddr, &ireq6->loc_addr);
+               fl6.saddr = ireq6->loc_addr;
                fl6.flowi6_oif = sk->sk_bound_dev_if;
                fl6.flowi6_mark = sk->sk_mark;
                fl6.fl6_dport = inet_rsk(req)->rmt_port;
index 36131d1..fd98dd0 100644 (file)
@@ -153,7 +153,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
                        flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);
                        if (flowlabel == NULL)
                                return -EINVAL;
-                       ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst);
+                       usin->sin6_addr = flowlabel->dst;
                        fl6_sock_release(flowlabel);
                }
        }
@@ -195,7 +195,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
                tp->write_seq = 0;
        }
 
-       ipv6_addr_copy(&np->daddr, &usin->sin6_addr);
+       np->daddr = usin->sin6_addr;
        np->flow_label = fl6.flowlabel;
 
        /*
@@ -244,9 +244,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
                saddr = &np->rcv_saddr;
 
        fl6.flowi6_proto = IPPROTO_TCP;
-       ipv6_addr_copy(&fl6.daddr, &np->daddr);
-       ipv6_addr_copy(&fl6.saddr,
-                      (saddr ? saddr : &np->saddr));
+       fl6.daddr = np->daddr;
+       fl6.saddr = saddr ? *saddr : np->saddr;
        fl6.flowi6_oif = sk->sk_bound_dev_if;
        fl6.flowi6_mark = sk->sk_mark;
        fl6.fl6_dport = usin->sin6_port;
@@ -264,11 +263,11 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
 
        if (saddr == NULL) {
                saddr = &fl6.saddr;
-               ipv6_addr_copy(&np->rcv_saddr, saddr);
+               np->rcv_saddr = *saddr;
        }
 
        /* set the source address */
-       ipv6_addr_copy(&np->saddr, saddr);
+       np->saddr = *saddr;
        inet->inet_rcv_saddr = LOOPBACK4_IPV6;
 
        sk->sk_gso_type = SKB_GSO_TCPV6;
@@ -398,8 +397,8 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                         */
                        memset(&fl6, 0, sizeof(fl6));
                        fl6.flowi6_proto = IPPROTO_TCP;
-                       ipv6_addr_copy(&fl6.daddr, &np->daddr);
-                       ipv6_addr_copy(&fl6.saddr, &np->saddr);
+                       fl6.daddr = np->daddr;
+                       fl6.saddr = np->saddr;
                        fl6.flowi6_oif = sk->sk_bound_dev_if;
                        fl6.flowi6_mark = sk->sk_mark;
                        fl6.fl6_dport = inet->inet_dport;
@@ -489,8 +488,8 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
 
        memset(&fl6, 0, sizeof(fl6));
        fl6.flowi6_proto = IPPROTO_TCP;
-       ipv6_addr_copy(&fl6.daddr, &treq->rmt_addr);
-       ipv6_addr_copy(&fl6.saddr, &treq->loc_addr);
+       fl6.daddr = treq->rmt_addr;
+       fl6.saddr = treq->loc_addr;
        fl6.flowlabel = 0;
        fl6.flowi6_oif = treq->iif;
        fl6.flowi6_mark = sk->sk_mark;
@@ -512,7 +511,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
        if (skb) {
                __tcp_v6_send_check(skb, &treq->loc_addr, &treq->rmt_addr);
 
-               ipv6_addr_copy(&fl6.daddr, &treq->rmt_addr);
+               fl6.daddr = treq->rmt_addr;
                err = ip6_xmit(sk, skb, &fl6, opt, np->tclass);
                err = net_xmit_eval(err);
        }
@@ -617,8 +616,7 @@ static int tcp_v6_md5_do_add(struct sock *sk, const struct in6_addr *peer,
                        tp->md5sig_info->alloced6++;
                }
 
-               ipv6_addr_copy(&tp->md5sig_info->keys6[tp->md5sig_info->entries6].addr,
-                              peer);
+               tp->md5sig_info->keys6[tp->md5sig_info->entries6].addr = *peer;
                tp->md5sig_info->keys6[tp->md5sig_info->entries6].base.key = newkey;
                tp->md5sig_info->keys6[tp->md5sig_info->entries6].base.keylen = newkeylen;
 
@@ -750,8 +748,8 @@ static int tcp_v6_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp,
 
        bp = &hp->md5_blk.ip6;
        /* 1. TCP pseudo-header (RFC2460) */
-       ipv6_addr_copy(&bp->saddr, saddr);
-       ipv6_addr_copy(&bp->daddr, daddr);
+       bp->saddr = *saddr;
+       bp->daddr = *daddr;
        bp->protocol = cpu_to_be32(IPPROTO_TCP);
        bp->len = cpu_to_be32(nbytes);
 
@@ -1039,8 +1037,8 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,
 #endif
 
        memset(&fl6, 0, sizeof(fl6));
-       ipv6_addr_copy(&fl6.daddr, &ipv6_hdr(skb)->saddr);
-       ipv6_addr_copy(&fl6.saddr, &ipv6_hdr(skb)->daddr);
+       fl6.daddr = ipv6_hdr(skb)->saddr;
+       fl6.saddr = ipv6_hdr(skb)->daddr;
 
        buff->ip_summed = CHECKSUM_PARTIAL;
        buff->csum = 0;
@@ -1250,8 +1248,8 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
        tcp_openreq_init(req, &tmp_opt, skb);
 
        treq = inet6_rsk(req);
-       ipv6_addr_copy(&treq->rmt_addr, &ipv6_hdr(skb)->saddr);
-       ipv6_addr_copy(&treq->loc_addr, &ipv6_hdr(skb)->daddr);
+       treq->rmt_addr = ipv6_hdr(skb)->saddr;
+       treq->loc_addr = ipv6_hdr(skb)->daddr;
        if (!want_cookie || tmp_opt.tstamp_ok)
                TCP_ECN_create_request(req, tcp_hdr(skb));
 
@@ -1380,7 +1378,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
 
                ipv6_addr_set_v4mapped(newinet->inet_saddr, &newnp->saddr);
 
-               ipv6_addr_copy(&newnp->rcv_saddr, &newnp->saddr);
+               newnp->rcv_saddr = newnp->saddr;
 
                inet_csk(newsk)->icsk_af_ops = &ipv6_mapped;
                newsk->sk_backlog_rcv = tcp_v4_do_rcv;
@@ -1444,9 +1442,9 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
 
        memcpy(newnp, np, sizeof(struct ipv6_pinfo));
 
-       ipv6_addr_copy(&newnp->daddr, &treq->rmt_addr);
-       ipv6_addr_copy(&newnp->saddr, &treq->loc_addr);
-       ipv6_addr_copy(&newnp->rcv_saddr, &treq->loc_addr);
+       newnp->daddr = treq->rmt_addr;
+       newnp->saddr = treq->loc_addr;
+       newnp->rcv_saddr = treq->loc_addr;
        newsk->sk_bound_dev_if = treq->iif;
 
        /* Now IPv6 options...
index 846f475..84ec9db 100644 (file)
@@ -417,8 +417,7 @@ try_again:
                        ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr,
                                               &sin6->sin6_addr);
                else {
-                       ipv6_addr_copy(&sin6->sin6_addr,
-                                      &ipv6_hdr(skb)->saddr);
+                       sin6->sin6_addr = ipv6_hdr(skb)->saddr;
                        if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
                                sin6->sin6_scope_id = IP6CB(skb)->iif;
                }
@@ -538,7 +537,9 @@ int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
                        goto drop;
        }
 
-       if ((rc = ip_queue_rcv_skb(sk, skb)) < 0) {
+       skb_dst_drop(skb);
+       rc = sock_queue_rcv_skb(sk, skb);
+       if (rc < 0) {
                /* Note that an ENOMEM error is charged twice */
                if (rc == -ENOMEM)
                        UDP6_INC_STATS_BH(sock_net(sk),
@@ -1113,11 +1114,11 @@ do_udp_sendmsg:
 
        fl6.flowi6_proto = sk->sk_protocol;
        if (!ipv6_addr_any(daddr))
-               ipv6_addr_copy(&fl6.daddr, daddr);
+               fl6.daddr = *daddr;
        else
                fl6.daddr.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */
        if (ipv6_addr_any(&fl6.saddr) && !ipv6_addr_any(&np->saddr))
-               ipv6_addr_copy(&fl6.saddr, &np->saddr);
+               fl6.saddr = np->saddr;
        fl6.fl6_sport = inet->inet_sport;
 
        final_p = fl6_update_dst(&fl6, opt, &final);
@@ -1298,7 +1299,8 @@ static int udp6_ufo_send_check(struct sk_buff *skb)
        return 0;
 }
 
-static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, u32 features)
+static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
+       netdev_features_t features)
 {
        struct sk_buff *segs = ERR_PTR(-EINVAL);
        unsigned int mss;
index 3437d7d..a81ce94 100644 (file)
@@ -72,8 +72,8 @@ static int xfrm6_beet_output(struct xfrm_state *x, struct sk_buff *skb)
                top_iph->nexthdr = IPPROTO_BEETPH;
        }
 
-       ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr);
-       ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr);
+       top_iph->saddr = *(struct in6_addr *)&x->props.saddr;
+       top_iph->daddr = *(struct in6_addr *)&x->id.daddr;
        return 0;
 }
 
@@ -99,8 +99,8 @@ static int xfrm6_beet_input(struct xfrm_state *x, struct sk_buff *skb)
 
        ip6h = ipv6_hdr(skb);
        ip6h->payload_len = htons(skb->len - size);
-       ipv6_addr_copy(&ip6h->daddr, (struct in6_addr *) &x->sel.daddr.a6);
-       ipv6_addr_copy(&ip6h->saddr, (struct in6_addr *) &x->sel.saddr.a6);
+       ip6h->daddr = *(struct in6_addr *)&x->sel.daddr.a6;
+       ip6h->saddr = *(struct in6_addr *)&x->sel.saddr.a6;
        err = 0;
 out:
        return err;
index 4d6edff..261e6e6 100644 (file)
@@ -55,8 +55,8 @@ static int xfrm6_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
                dsfield &= ~INET_ECN_MASK;
        ipv6_change_dsfield(top_iph, 0, dsfield);
        top_iph->hop_limit = ip6_dst_hoplimit(dst->child);
-       ipv6_addr_copy(&top_iph->saddr, (const struct in6_addr *)&x->props.saddr);
-       ipv6_addr_copy(&top_iph->daddr, (const struct in6_addr *)&x->id.daddr);
+       top_iph->saddr = *(struct in6_addr *)&x->props.saddr;
+       top_iph->daddr = *(struct in6_addr *)&x->id.daddr;
        return 0;
 }
 
index faae417..4eeff89 100644 (file)
@@ -49,7 +49,7 @@ static void xfrm6_local_rxpmtu(struct sk_buff *skb, u32 mtu)
        struct sock *sk = skb->sk;
 
        fl6.flowi6_oif = sk->sk_bound_dev_if;
-       ipv6_addr_copy(&fl6.daddr, &ipv6_hdr(skb)->daddr);
+       fl6.daddr = ipv6_hdr(skb)->daddr;
 
        ipv6_local_rxpmtu(sk, &fl6, mtu);
 }
@@ -60,7 +60,7 @@ static void xfrm6_local_error(struct sk_buff *skb, u32 mtu)
        struct sock *sk = skb->sk;
 
        fl6.fl6_dport = inet_sk(sk)->inet_dport;
-       ipv6_addr_copy(&fl6.daddr, &ipv6_hdr(skb)->daddr);
+       fl6.daddr = ipv6_hdr(skb)->daddr;
 
        ipv6_local_error(sk, EMSGSIZE, &fl6, mtu);
 }
index d879f7e..8ea65e0 100644 (file)
@@ -132,8 +132,8 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse)
        memset(fl6, 0, sizeof(struct flowi6));
        fl6->flowi6_mark = skb->mark;
 
-       ipv6_addr_copy(&fl6->daddr, reverse ? &hdr->saddr : &hdr->daddr);
-       ipv6_addr_copy(&fl6->saddr, reverse ? &hdr->daddr : &hdr->saddr);
+       fl6->daddr = reverse ? hdr->saddr : hdr->daddr;
+       fl6->saddr = reverse ? hdr->daddr : hdr->saddr;
 
        while (nh + offset + 1 < skb->data ||
               pskb_may_pull(skb, nh + offset + 1 - skb->data)) {
index f2d72b8..3f2f7c4 100644 (file)
@@ -27,8 +27,8 @@ __xfrm6_init_tempsel(struct xfrm_selector *sel, const struct flowi *fl)
 
        /* Initialize temporary selector matching only
         * to current session. */
-       ipv6_addr_copy((struct in6_addr *)&sel->daddr, &fl6->daddr);
-       ipv6_addr_copy((struct in6_addr *)&sel->saddr, &fl6->saddr);
+       *(struct in6_addr *)&sel->daddr = fl6->daddr;
+       *(struct in6_addr *)&sel->saddr = fl6->saddr;
        sel->dport = xfrm_flowi_dport(fl, &fl6->uli);
        sel->dport_mask = htons(0xffff);
        sel->sport = xfrm_flowi_sport(fl, &fl6->uli);
index 32e3bb0..5c93f29 100644 (file)
@@ -1461,14 +1461,12 @@ struct tsap_cb *irttp_dup(struct tsap_cb *orig, void *instance)
        }
 
        /* Allocate a new instance */
-       new = kmalloc(sizeof(struct tsap_cb), GFP_ATOMIC);
+       new = kmemdup(orig, sizeof(struct tsap_cb), GFP_ATOMIC);
        if (!new) {
                IRDA_DEBUG(0, "%s(), unable to kmalloc\n", __func__);
                spin_unlock_irqrestore(&irttp->tsaps->hb_spinlock, flags);
                return NULL;
        }
-       /* Dup */
-       memcpy(new, orig, sizeof(struct tsap_cb));
        spin_lock_init(&new->lock);
 
        /* We don't need the old instance any more */
index 1e733e9..bfc0bef 100644 (file)
@@ -712,7 +712,7 @@ static unsigned int pfkey_sockaddr_fill(const xfrm_address_t *xaddr, __be16 port
                sin6->sin6_family = AF_INET6;
                sin6->sin6_port = port;
                sin6->sin6_flowinfo = 0;
-               ipv6_addr_copy(&sin6->sin6_addr, (const struct in6_addr *)xaddr->a6);
+               sin6->sin6_addr = *(struct in6_addr *)xaddr->a6;
                sin6->sin6_scope_id = 0;
                return 128;
            }
index bf8d50c..cf0f308 100644 (file)
@@ -756,9 +756,6 @@ static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb,
                goto error;
        }
 
-       /* Point to L2TP header */
-       optr = ptr = skb->data;
-
        /* Trace packet contents, if enabled */
        if (tunnel->debug & L2TP_MSG_DATA) {
                length = min(32u, skb->len);
@@ -769,12 +766,15 @@ static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb,
 
                offset = 0;
                do {
-                       printk(" %02X", ptr[offset]);
+                       printk(" %02X", skb->data[offset]);
                } while (++offset < length);
 
                printk("\n");
        }
 
+       /* Point to L2TP header */
+       optr = ptr = skb->data;
+
        /* Get L2TP header flags */
        hdrflags = ntohs(*(__be16 *) ptr);
 
index 93b2434..476b106 100644 (file)
@@ -177,7 +177,8 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d
        memcpy(mgmt->da, da, ETH_ALEN);
        memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        if (sdata->vif.type == NL80211_IFTYPE_AP ||
-           sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+           sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+           sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
                memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
        else if (sdata->vif.type == NL80211_IFTYPE_STATION)
                memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
index b3f6552..39d72cc 100644 (file)
@@ -78,7 +78,8 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
        memcpy(mgmt->da, da, ETH_ALEN);
        memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        if (sdata->vif.type == NL80211_IFTYPE_AP ||
-           sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+           sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+           sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
                memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
        else if (sdata->vif.type == NL80211_IFTYPE_STATION)
                memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
@@ -372,13 +373,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
               pubsta->addr, tid);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
 
-       /*
-        * The aggregation code is not prepared to handle
-        * anything but STA/AP due to the BSSID handling.
-        * IBSS could work in the code but isn't supported
-        * by drivers or the standard.
-        */
        if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+           sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
            sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
            sdata->vif.type != NL80211_IFTYPE_AP)
                return -EINVAL;
index d06c65f..1063a7e 100644 (file)
@@ -411,7 +411,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
                                BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
                                BIT(NL80211_STA_FLAG_WME) |
                                BIT(NL80211_STA_FLAG_MFP) |
-                               BIT(NL80211_STA_FLAG_AUTHENTICATED);
+                               BIT(NL80211_STA_FLAG_AUTHENTICATED) |
+                               BIT(NL80211_STA_FLAG_TDLS_PEER);
        if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
                sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHORIZED);
        if (test_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE))
@@ -422,6 +423,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
                sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_MFP);
        if (test_sta_flag(sta, WLAN_STA_AUTH))
                sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
+       if (test_sta_flag(sta, WLAN_STA_TDLS_PEER))
+               sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
 }
 
 
@@ -488,6 +491,31 @@ static void ieee80211_config_ap_ssid(struct ieee80211_sub_if_data *sdata,
                (params->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE);
 }
 
+static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
+                                   u8 *resp, size_t resp_len)
+{
+       struct sk_buff *new, *old;
+
+       if (!resp || !resp_len)
+               return -EINVAL;
+
+       old = sdata->u.ap.probe_resp;
+
+       new = dev_alloc_skb(resp_len);
+       if (!new)
+               return -ENOMEM;
+
+       memcpy(skb_put(new, resp_len), resp, resp_len);
+
+       rcu_assign_pointer(sdata->u.ap.probe_resp, new);
+       synchronize_rcu();
+
+       if (old)
+               dev_kfree_skb(old);
+
+       return 0;
+}
+
 /*
  * This handles both adding a beacon and setting new beacon info
  */
@@ -498,6 +526,7 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
        int new_head_len, new_tail_len;
        int size;
        int err = -EINVAL;
+       u32 changed = 0;
 
        old = rtnl_dereference(sdata->u.ap.beacon);
 
@@ -581,11 +610,17 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
 
        kfree(old);
 
+       err = ieee80211_set_probe_resp(sdata, params->probe_resp,
+                                      params->probe_resp_len);
+       if (!err)
+               changed |= BSS_CHANGED_AP_PROBE_RESP;
+
        ieee80211_config_ap_ssid(sdata, params);
+       changed |= BSS_CHANGED_BEACON_ENABLED |
+                  BSS_CHANGED_BEACON |
+                  BSS_CHANGED_SSID;
 
-       ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
-                                               BSS_CHANGED_BEACON |
-                                               BSS_CHANGED_SSID);
+       ieee80211_bss_info_change_notify(sdata, changed);
        return 0;
 }
 
@@ -594,6 +629,8 @@ static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
 {
        struct ieee80211_sub_if_data *sdata;
        struct beacon_data *old;
+       struct ieee80211_sub_if_data *vlan;
+       int ret;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
@@ -601,7 +638,24 @@ static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
        if (old)
                return -EALREADY;
 
-       return ieee80211_config_beacon(sdata, params);
+       ret = ieee80211_config_beacon(sdata, params);
+       if (ret)
+               return ret;
+
+       /*
+        * Apply control port protocol, this allows us to
+        * not encrypt dynamic WEP control frames.
+        */
+       sdata->control_port_protocol = params->crypto.control_port_ethertype;
+       sdata->control_port_no_encrypt = params->crypto.control_port_no_encrypt;
+       list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
+               vlan->control_port_protocol =
+                       params->crypto.control_port_ethertype;
+               vlan->control_port_no_encrypt =
+                       params->crypto.control_port_no_encrypt;
+       }
+
+       return 0;
 }
 
 static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
@@ -847,7 +901,12 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
 
        sta_apply_parameters(local, sta, params);
 
-       rate_control_rate_init(sta);
+       /*
+        * for TDLS, rate control should be initialized only when supported
+        * rates are known.
+        */
+       if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER))
+               rate_control_rate_init(sta);
 
        layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
                sdata->vif.type == NL80211_IFTYPE_AP;
@@ -931,6 +990,9 @@ static int ieee80211_change_station(struct wiphy *wiphy,
 
        sta_apply_parameters(local, sta, params);
 
+       if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) && params->supported_rates)
+               rate_control_rate_init(sta);
+
        rcu_read_unlock();
 
        if (sdata->vif.type == NL80211_IFTYPE_STATION &&
@@ -1394,7 +1456,7 @@ static int ieee80211_set_channel(struct wiphy *wiphy,
            (old_oper_type != local->_oper_channel_type))
                ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
 
-       if ((sdata && sdata->vif.type != NL80211_IFTYPE_MONITOR) &&
+       if (sdata && sdata->vif.type != NL80211_IFTYPE_MONITOR &&
            old_vif_oper_type != sdata->vif.bss_conf.channel_type)
                ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT);
 
@@ -1917,7 +1979,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
                             enum nl80211_channel_type channel_type,
                             bool channel_type_valid, unsigned int wait,
                             const u8 *buf, size_t len, bool no_cck,
-                            u64 *cookie)
+                            bool dont_wait_for_ack, u64 *cookie)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
@@ -1925,10 +1987,15 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
        struct sta_info *sta;
        struct ieee80211_work *wk;
        const struct ieee80211_mgmt *mgmt = (void *)buf;
-       u32 flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX |
-                   IEEE80211_TX_CTL_REQ_TX_STATUS;
+       u32 flags;
        bool is_offchan = false;
 
+       if (dont_wait_for_ack)
+               flags = IEEE80211_TX_CTL_NO_ACK;
+       else
+               flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX |
+                       IEEE80211_TX_CTL_REQ_TX_STATUS;
+
        /* Check that we are on the requested channel for transmission */
        if (chan != local->tmp_channel &&
            chan != local->oper_channel)
@@ -2488,6 +2555,82 @@ static int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
        return 0;
 }
 
+static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
+                                 const u8 *peer, u64 *cookie)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_qos_hdr *nullfunc;
+       struct sk_buff *skb;
+       int size = sizeof(*nullfunc);
+       __le16 fc;
+       bool qos;
+       struct ieee80211_tx_info *info;
+       struct sta_info *sta;
+
+       rcu_read_lock();
+       sta = sta_info_get(sdata, peer);
+       if (sta) {
+               qos = test_sta_flag(sta, WLAN_STA_WME);
+               rcu_read_unlock();
+       } else {
+               rcu_read_unlock();
+               return -ENOLINK;
+       }
+
+       if (qos) {
+               fc = cpu_to_le16(IEEE80211_FTYPE_DATA |
+                                IEEE80211_STYPE_QOS_NULLFUNC |
+                                IEEE80211_FCTL_FROMDS);
+       } else {
+               size -= 2;
+               fc = cpu_to_le16(IEEE80211_FTYPE_DATA |
+                                IEEE80211_STYPE_NULLFUNC |
+                                IEEE80211_FCTL_FROMDS);
+       }
+
+       skb = dev_alloc_skb(local->hw.extra_tx_headroom + size);
+       if (!skb)
+               return -ENOMEM;
+
+       skb->dev = dev;
+
+       skb_reserve(skb, local->hw.extra_tx_headroom);
+
+       nullfunc = (void *) skb_put(skb, size);
+       nullfunc->frame_control = fc;
+       nullfunc->duration_id = 0;
+       memcpy(nullfunc->addr1, sta->sta.addr, ETH_ALEN);
+       memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN);
+       memcpy(nullfunc->addr3, sdata->vif.addr, ETH_ALEN);
+       nullfunc->seq_ctrl = 0;
+
+       info = IEEE80211_SKB_CB(skb);
+
+       info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS |
+                      IEEE80211_TX_INTFL_NL80211_FRAME_TX;
+
+       skb_set_queue_mapping(skb, IEEE80211_AC_VO);
+       skb->priority = 7;
+       if (qos)
+               nullfunc->qos_ctrl = cpu_to_le16(7);
+
+       local_bh_disable();
+       ieee80211_xmit(sdata, skb);
+       local_bh_enable();
+
+       *cookie = (unsigned long) skb;
+       return 0;
+}
+
+static struct ieee80211_channel *
+ieee80211_wiphy_get_channel(struct wiphy *wiphy)
+{
+       struct ieee80211_local *local = wiphy_priv(wiphy);
+
+       return local->oper_channel;
+}
+
 struct cfg80211_ops mac80211_config_ops = {
        .add_virtual_intf = ieee80211_add_iface,
        .del_virtual_intf = ieee80211_del_iface,
@@ -2553,4 +2696,6 @@ struct cfg80211_ops mac80211_config_ops = {
        .set_rekey_data = ieee80211_set_rekey_data,
        .tdls_oper = ieee80211_tdls_oper,
        .tdls_mgmt = ieee80211_tdls_mgmt,
+       .probe_client = ieee80211_probe_client,
+       .get_channel = ieee80211_wiphy_get_channel,
 };
index 883996b..00cefcb 100644 (file)
@@ -190,7 +190,7 @@ static ssize_t uapsd_max_sp_len_write(struct file *file,
                return -EFAULT;
        buf[len] = '\0';
 
-       ret = strict_strtoul(buf, 0, &val);
+       ret = kstrtoul(buf, 0, &val);
 
        if (ret)
                return -EINVAL;
index 5f165d7..b12ed52 100644 (file)
@@ -5,6 +5,11 @@
 #include "ieee80211_i.h"
 #include "driver-trace.h"
 
+static inline void check_sdata_in_driver(struct ieee80211_sub_if_data *sdata)
+{
+       WARN_ON(!(sdata->flags & IEEE80211_SDATA_IN_DRIVER));
+}
+
 static inline void drv_tx(struct ieee80211_local *local, struct sk_buff *skb)
 {
        local->ops->tx(&local->hw, skb);
@@ -69,15 +74,23 @@ static inline int drv_resume(struct ieee80211_local *local)
 #endif
 
 static inline int drv_add_interface(struct ieee80211_local *local,
-                                   struct ieee80211_vif *vif)
+                                   struct ieee80211_sub_if_data *sdata)
 {
        int ret;
 
        might_sleep();
 
-       trace_drv_add_interface(local, vif_to_sdata(vif));
-       ret = local->ops->add_interface(&local->hw, vif);
+       if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+                   sdata->vif.type == NL80211_IFTYPE_MONITOR))
+               return -EINVAL;
+
+       trace_drv_add_interface(local, sdata);
+       ret = local->ops->add_interface(&local->hw, &sdata->vif);
        trace_drv_return_int(local, ret);
+
+       if (ret == 0)
+               sdata->flags |= IEEE80211_SDATA_IN_DRIVER;
+
        return ret;
 }
 
@@ -89,6 +102,8 @@ static inline int drv_change_interface(struct ieee80211_local *local,
 
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_change_interface(local, sdata, type, p2p);
        ret = local->ops->change_interface(&local->hw, &sdata->vif, type, p2p);
        trace_drv_return_int(local, ret);
@@ -96,12 +111,15 @@ static inline int drv_change_interface(struct ieee80211_local *local,
 }
 
 static inline void drv_remove_interface(struct ieee80211_local *local,
-                                       struct ieee80211_vif *vif)
+                                       struct ieee80211_sub_if_data *sdata)
 {
        might_sleep();
 
-       trace_drv_remove_interface(local, vif_to_sdata(vif));
-       local->ops->remove_interface(&local->hw, vif);
+       check_sdata_in_driver(sdata);
+
+       trace_drv_remove_interface(local, sdata);
+       local->ops->remove_interface(&local->hw, &sdata->vif);
+       sdata->flags &= ~IEEE80211_SDATA_IN_DRIVER;
        trace_drv_return_void(local);
 }
 
@@ -124,6 +142,8 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local,
 {
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_bss_info_changed(local, sdata, info, changed);
        if (local->ops->bss_info_changed)
                local->ops->bss_info_changed(&local->hw, &sdata->vif, info, changed);
@@ -139,6 +159,8 @@ static inline int drv_tx_sync(struct ieee80211_local *local,
 
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_tx_sync(local, sdata, bssid, type);
        if (local->ops->tx_sync)
                ret = local->ops->tx_sync(&local->hw, &sdata->vif,
@@ -154,6 +176,8 @@ static inline void drv_finish_tx_sync(struct ieee80211_local *local,
 {
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_finish_tx_sync(local, sdata, bssid, type);
        if (local->ops->finish_tx_sync)
                local->ops->finish_tx_sync(&local->hw, &sdata->vif,
@@ -211,6 +235,8 @@ static inline int drv_set_key(struct ieee80211_local *local,
 
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_set_key(local, cmd, sdata, sta, key);
        ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key);
        trace_drv_return_int(local, ret);
@@ -228,6 +254,8 @@ static inline void drv_update_tkip_key(struct ieee80211_local *local,
        if (sta)
                ista = &sta->sta;
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_update_tkip_key(local, sdata, conf, ista, iv32);
        if (local->ops->update_tkip_key)
                local->ops->update_tkip_key(&local->hw, &sdata->vif, conf,
@@ -243,6 +271,8 @@ static inline int drv_hw_scan(struct ieee80211_local *local,
 
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_hw_scan(local, sdata);
        ret = local->ops->hw_scan(&local->hw, &sdata->vif, req);
        trace_drv_return_int(local, ret);
@@ -254,6 +284,8 @@ static inline void drv_cancel_hw_scan(struct ieee80211_local *local,
 {
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_cancel_hw_scan(local, sdata);
        local->ops->cancel_hw_scan(&local->hw, &sdata->vif);
        trace_drv_return_void(local);
@@ -269,6 +301,8 @@ drv_sched_scan_start(struct ieee80211_local *local,
 
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_sched_scan_start(local, sdata);
        ret = local->ops->sched_scan_start(&local->hw, &sdata->vif,
                                              req, ies);
@@ -281,6 +315,8 @@ static inline void drv_sched_scan_stop(struct ieee80211_local *local,
 {
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_sched_scan_stop(local, sdata);
        local->ops->sched_scan_stop(&local->hw, &sdata->vif);
        trace_drv_return_void(local);
@@ -377,6 +413,8 @@ static inline void drv_sta_notify(struct ieee80211_local *local,
                                  enum sta_notify_cmd cmd,
                                  struct ieee80211_sta *sta)
 {
+       check_sdata_in_driver(sdata);
+
        trace_drv_sta_notify(local, sdata, cmd, sta);
        if (local->ops->sta_notify)
                local->ops->sta_notify(&local->hw, &sdata->vif, cmd, sta);
@@ -391,6 +429,8 @@ static inline int drv_sta_add(struct ieee80211_local *local,
 
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_sta_add(local, sdata, sta);
        if (local->ops->sta_add)
                ret = local->ops->sta_add(&local->hw, &sdata->vif, sta);
@@ -406,6 +446,8 @@ static inline void drv_sta_remove(struct ieee80211_local *local,
 {
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_sta_remove(local, sdata, sta);
        if (local->ops->sta_remove)
                local->ops->sta_remove(&local->hw, &sdata->vif, sta);
@@ -421,6 +463,8 @@ static inline int drv_conf_tx(struct ieee80211_local *local,
 
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_conf_tx(local, sdata, queue, params);
        if (local->ops->conf_tx)
                ret = local->ops->conf_tx(&local->hw, &sdata->vif,
@@ -436,6 +480,8 @@ static inline u64 drv_get_tsf(struct ieee80211_local *local,
 
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_get_tsf(local, sdata);
        if (local->ops->get_tsf)
                ret = local->ops->get_tsf(&local->hw, &sdata->vif);
@@ -449,6 +495,8 @@ static inline void drv_set_tsf(struct ieee80211_local *local,
 {
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_set_tsf(local, sdata, tsf);
        if (local->ops->set_tsf)
                local->ops->set_tsf(&local->hw, &sdata->vif, tsf);
@@ -460,6 +508,8 @@ static inline void drv_reset_tsf(struct ieee80211_local *local,
 {
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_reset_tsf(local, sdata);
        if (local->ops->reset_tsf)
                local->ops->reset_tsf(&local->hw, &sdata->vif);
@@ -489,6 +539,8 @@ static inline int drv_ampdu_action(struct ieee80211_local *local,
 
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_ampdu_action(local, sdata, action, sta, tid, ssn, buf_size);
 
        if (local->ops->ampdu_action)
@@ -644,6 +696,8 @@ static inline int drv_set_bitrate_mask(struct ieee80211_local *local,
 
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_set_bitrate_mask(local, sdata, mask);
        if (local->ops->set_bitrate_mask)
                ret = local->ops->set_bitrate_mask(&local->hw,
@@ -657,6 +711,8 @@ static inline void drv_set_rekey_data(struct ieee80211_local *local,
                                      struct ieee80211_sub_if_data *sdata,
                                      struct cfg80211_gtk_rekey_data *data)
 {
+       check_sdata_in_driver(sdata);
+
        trace_drv_set_rekey_data(local, sdata, data);
        if (local->ops->set_rekey_data)
                local->ops->set_rekey_data(&local->hw, &sdata->vif, data);
index f0fb737..d069750 100644 (file)
@@ -196,7 +196,8 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
        memcpy(mgmt->da, da, ETH_ALEN);
        memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        if (sdata->vif.type == NL80211_IFTYPE_AP ||
-           sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+           sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+           sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
                memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
        else if (sdata->vif.type == NL80211_IFTYPE_STATION)
                memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
index ede9a8b..7d84af7 100644 (file)
@@ -97,6 +97,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
        /* if merging, indicate to driver that we leave the old IBSS */
        if (sdata->vif.bss_conf.ibss_joined) {
                sdata->vif.bss_conf.ibss_joined = false;
+               netif_carrier_off(sdata->dev);
                ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IBSS);
        }
 
@@ -207,6 +208,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
        bss = cfg80211_inform_bss_frame(local->hw.wiphy, local->hw.conf.channel,
                                        mgmt, skb->len, 0, GFP_KERNEL);
        cfg80211_put_bss(bss);
+       netif_carrier_on(sdata->dev);
        cfg80211_ibss_joined(sdata->dev, ifibss->bssid, GFP_KERNEL);
 }
 
@@ -990,6 +992,7 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
        }
 
        sta_info_flush(sdata->local, sdata);
+       netif_carrier_off(sdata->dev);
 
        /* remove beacon */
        kfree(sdata->u.ibss.ie);
index ea10a51..068cc92 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/spinlock.h>
 #include <linux/etherdevice.h>
 #include <linux/leds.h>
+#include <linux/idr.h>
 #include <net/ieee80211_radiotap.h>
 #include <net/cfg80211.h>
 #include <net/mac80211.h>
@@ -184,12 +185,15 @@ enum ieee80211_packet_rx_flags {
  * enum ieee80211_rx_flags - RX data flags
  *
  * @IEEE80211_RX_CMNTR: received on cooked monitor already
+ * @IEEE80211_RX_BEACON_REPORTED: This frame was already reported
+ *     to cfg80211_report_obss_beacon().
  *
  * These flags are used across handling multiple interfaces
  * for a single frame.
  */
 enum ieee80211_rx_flags {
        IEEE80211_RX_CMNTR              = BIT(0),
+       IEEE80211_RX_BEACON_REPORTED    = BIT(1),
 };
 
 struct ieee80211_rx_data {
@@ -228,6 +232,7 @@ struct beacon_data {
 
 struct ieee80211_if_ap {
        struct beacon_data __rcu *beacon;
+       struct sk_buff __rcu *probe_resp;
 
        struct list_head vlans;
 
@@ -543,6 +548,7 @@ struct ieee80211_if_mesh {
  *     associated stations and deliver multicast frames both
  *     back to wireless media and to the local net stack.
  * @IEEE80211_SDATA_DISCONNECT_RESUME: Disconnect after resume.
+ * @IEEE80211_SDATA_IN_DRIVER: indicates interface was added to driver
  */
 enum ieee80211_sub_if_data_flags {
        IEEE80211_SDATA_ALLMULTI                = BIT(0),
@@ -550,6 +556,7 @@ enum ieee80211_sub_if_data_flags {
        IEEE80211_SDATA_OPERATING_GMODE         = BIT(2),
        IEEE80211_SDATA_DONT_BRIDGE_PACKETS     = BIT(3),
        IEEE80211_SDATA_DISCONNECT_RESUME       = BIT(4),
+       IEEE80211_SDATA_IN_DRIVER               = BIT(5),
 };
 
 /**
@@ -722,17 +729,16 @@ enum {
  *     operating channel
  * @SCAN_SET_CHANNEL: Set the next channel to be scanned
  * @SCAN_SEND_PROBE: Send probe requests and wait for probe responses
- * @SCAN_LEAVE_OPER_CHANNEL: Leave the operating channel, notify the AP
- *     about us leaving the channel and stop all associated STA interfaces
- * @SCAN_ENTER_OPER_CHANNEL: Enter the operating channel again, notify the
- *     AP about us being back and restart all associated STA interfaces
+ * @SCAN_SUSPEND: Suspend the scan and go back to operating channel to
+ *     send out data
+ * @SCAN_RESUME: Resume the scan and scan the next channel
  */
 enum mac80211_scan_state {
        SCAN_DECISION,
        SCAN_SET_CHANNEL,
        SCAN_SEND_PROBE,
-       SCAN_LEAVE_OPER_CHANNEL,
-       SCAN_ENTER_OPER_CHANNEL,
+       SCAN_SUSPEND,
+       SCAN_RESUME,
 };
 
 struct ieee80211_local {
@@ -1012,6 +1018,9 @@ struct ieee80211_local {
        u32 hw_roc_cookie;
        bool hw_roc_for_tx;
 
+       struct idr ack_status_frames;
+       spinlock_t ack_status_lock;
+
        /* dummy netdev for use w/ NAPI */
        struct net_device napi_dev;
 
@@ -1334,6 +1343,12 @@ void ieee80211_recalc_smps(struct ieee80211_local *local);
 size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
                          const u8 *ids, int n_ids, size_t offset);
 size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset);
+u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_supported_band *sband,
+                             u16 cap);
+u8 *ieee80211_ie_build_ht_info(u8 *pos,
+                               struct ieee80211_sta_ht_cap *ht_cap,
+                               struct ieee80211_channel *channel,
+                               enum nl80211_channel_type channel_type);
 
 /* internal work items */
 void ieee80211_work_init(struct ieee80211_local *local);
@@ -1362,6 +1377,8 @@ ieee80211_get_channel_mode(struct ieee80211_local *local,
 bool ieee80211_set_channel_type(struct ieee80211_local *local,
                                struct ieee80211_sub_if_data *sdata,
                                enum nl80211_channel_type chantype);
+enum nl80211_channel_type
+ieee80211_ht_info_to_channel_type(struct ieee80211_ht_info *ht_info);
 
 #ifdef CONFIG_MAC80211_NOINLINE
 #define debug_noinline noinline
index 30d7355..12a6d4b 100644 (file)
@@ -188,11 +188,22 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
                if (!is_valid_ether_addr(sdata->u.wds.remote_addr))
                        return -ENOLINK;
                break;
-       case NL80211_IFTYPE_AP_VLAN:
+       case NL80211_IFTYPE_AP_VLAN: {
+               struct ieee80211_sub_if_data *master;
+
                if (!sdata->bss)
                        return -ENOLINK;
+
                list_add(&sdata->u.vlan.list, &sdata->bss->vlans);
+
+               master = container_of(sdata->bss,
+                                     struct ieee80211_sub_if_data, u.ap);
+               sdata->control_port_protocol =
+                       master->control_port_protocol;
+               sdata->control_port_no_encrypt =
+                       master->control_port_no_encrypt;
                break;
+               }
        case NL80211_IFTYPE_AP:
                sdata->bss = &sdata->u.ap;
                break;
@@ -265,7 +276,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
                break;
        default:
                if (coming_up) {
-                       res = drv_add_interface(local, &sdata->vif);
+                       res = drv_add_interface(local, sdata);
                        if (res)
                                goto err_stop;
                }
@@ -282,10 +293,18 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
                changed |= ieee80211_reset_erp_info(sdata);
                ieee80211_bss_info_change_notify(sdata, changed);
 
-               if (sdata->vif.type == NL80211_IFTYPE_STATION)
+               if (sdata->vif.type == NL80211_IFTYPE_STATION ||
+                   sdata->vif.type == NL80211_IFTYPE_ADHOC)
                        netif_carrier_off(dev);
                else
                        netif_carrier_on(dev);
+
+               /*
+                * set default queue parameters so drivers don't
+                * need to initialise the hardware if the hardware
+                * doesn't start up with sane defaults
+                */
+               ieee80211_set_wmm_default(sdata);
        }
 
        set_bit(SDATA_STATE_RUNNING, &sdata->state);
@@ -329,15 +348,8 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
        if (coming_up)
                local->open_count++;
 
-       if (hw_reconf_flags) {
+       if (hw_reconf_flags)
                ieee80211_hw_config(local, hw_reconf_flags);
-               /*
-                * set default queue parameters so drivers don't
-                * need to initialise the hardware if the hardware
-                * doesn't start up with sane defaults
-                */
-               ieee80211_set_wmm_default(sdata);
-       }
 
        ieee80211_recalc_ps(local, -1);
 
@@ -345,7 +357,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
 
        return 0;
  err_del_interface:
-       drv_remove_interface(local, &sdata->vif);
+       drv_remove_interface(local, sdata);
  err_stop:
        if (!local->open_count)
                drv_stop(local);
@@ -450,15 +462,19 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
                struct ieee80211_sub_if_data *vlan, *tmpsdata;
                struct beacon_data *old_beacon =
                        rtnl_dereference(sdata->u.ap.beacon);
+               struct sk_buff *old_probe_resp =
+                       rtnl_dereference(sdata->u.ap.probe_resp);
 
                /* sdata_running will return false, so this will disable */
                ieee80211_bss_info_change_notify(sdata,
                                                 BSS_CHANGED_BEACON_ENABLED);
 
-               /* remove beacon */
+               /* remove beacon and probe response */
                RCU_INIT_POINTER(sdata->u.ap.beacon, NULL);
+               RCU_INIT_POINTER(sdata->u.ap.probe_resp, NULL);
                synchronize_rcu();
                kfree(old_beacon);
+               kfree(old_probe_resp);
 
                /* down all dependent devices, that is VLANs */
                list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
@@ -520,7 +536,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
                ieee80211_free_keys(sdata);
 
                if (going_down)
-                       drv_remove_interface(local, &sdata->vif);
+                       drv_remove_interface(local, sdata);
        }
 
        sdata->bss = NULL;
index fb02ea5..87a8974 100644 (file)
@@ -134,9 +134,13 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
                key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
 
                if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
-                     (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)))
+                     (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) ||
+                     (key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)))
                        sdata->crypto_tx_tailroom_needed_cnt--;
 
+               WARN_ON((key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) &&
+                       (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV));
+
                return 0;
        }
 
@@ -179,7 +183,8 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
        sdata = key->sdata;
 
        if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
-             (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)))
+             (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) ||
+             (key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)))
                increment_tailroom_need_count(sdata);
 
        if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
index d999bf3..e323d4e 100644 (file)
@@ -100,7 +100,7 @@ static void ieee80211_reconfig_filter(struct work_struct *work)
  */
 bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local)
 {
-       struct ieee80211_channel *chan, *scan_chan;
+       struct ieee80211_channel *chan;
        enum nl80211_channel_type channel_type;
 
        /* This logic needs to match logic in ieee80211_hw_config */
@@ -114,7 +114,7 @@ bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local)
                else
                        channel_type = NL80211_CHAN_NO_HT;
        } else if (local->tmp_channel) {
-               chan = scan_chan = local->tmp_channel;
+               chan = local->tmp_channel;
                channel_type = local->tmp_channel_type;
        } else {
                chan = local->oper_channel;
@@ -126,8 +126,8 @@ bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local)
                return false;
 
        /* Check current hardware-config against oper_channel. */
-       if ((local->oper_channel != local->hw.conf.channel) ||
-           (local->_oper_channel_type != local->hw.conf.channel_type))
+       if (local->oper_channel != local->hw.conf.channel ||
+           local->_oper_channel_type != local->hw.conf.channel_type)
                return false;
 
        return true;
@@ -135,7 +135,7 @@ bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local)
 
 int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
 {
-       struct ieee80211_channel *chan, *scan_chan;
+       struct ieee80211_channel *chan;
        int ret = 0;
        int power;
        enum nl80211_channel_type channel_type;
@@ -143,14 +143,12 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
 
        might_sleep();
 
-       scan_chan = local->scan_channel;
-
        /* If this off-channel logic ever changes,  ieee80211_on_oper_channel
         * may need to change as well.
         */
        offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL;
-       if (scan_chan) {
-               chan = scan_chan;
+       if (local->scan_channel) {
+               chan = local->scan_channel;
                /* If scanning on oper channel, use whatever channel-type
                 * is currently in use.
                 */
@@ -159,7 +157,7 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
                else
                        channel_type = NL80211_CHAN_NO_HT;
        } else if (local->tmp_channel) {
-               chan = scan_chan = local->tmp_channel;
+               chan = local->tmp_channel;
                channel_type = local->tmp_channel_type;
        } else {
                chan = local->oper_channel;
@@ -595,7 +593,10 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 
        wiphy->flags |= WIPHY_FLAG_NETNS_OK |
                        WIPHY_FLAG_4ADDR_AP |
-                       WIPHY_FLAG_4ADDR_STATION;
+                       WIPHY_FLAG_4ADDR_STATION |
+                       WIPHY_FLAG_REPORTS_OBSS;
+
+       wiphy->features = NL80211_FEATURE_SK_TX_STATUS;
 
        if (!ops->set_key)
                wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
@@ -670,6 +671,11 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        INIT_WORK(&local->sched_scan_stopped_work,
                  ieee80211_sched_scan_stopped_work);
 
+       spin_lock_init(&local->ack_status_lock);
+       idr_init(&local->ack_status_frames);
+       /* preallocate at least one entry */
+       idr_pre_get(&local->ack_status_frames, GFP_KERNEL);
+
        sta_info_init(local);
 
        for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
@@ -1045,6 +1051,13 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
 }
 EXPORT_SYMBOL(ieee80211_unregister_hw);
 
+static int ieee80211_free_ack_frame(int id, void *p, void *data)
+{
+       WARN_ONCE(1, "Have pending ack frames!\n");
+       kfree_skb(p);
+       return 0;
+}
+
 void ieee80211_free_hw(struct ieee80211_hw *hw)
 {
        struct ieee80211_local *local = hw_to_local(hw);
@@ -1055,6 +1068,10 @@ void ieee80211_free_hw(struct ieee80211_hw *hw)
        if (local->wiphy_ciphers_allocated)
                kfree(local->hw.wiphy->cipher_suites);
 
+       idr_for_each(&local->ack_status_frames,
+                    ieee80211_free_ack_frame, NULL);
+       idr_destroy(&local->ack_status_frames);
+
        wiphy_free(local->hw.wiphy);
 }
 EXPORT_SYMBOL(ieee80211_free_hw);
index a7078fd..b3a125f 100644 (file)
@@ -76,6 +76,7 @@ static void ieee80211_mesh_housekeeping_timer(unsigned long data)
 bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+       struct ieee80211_local *local = sdata->local;
 
        /*
         * As support for each feature is added, check for matching
@@ -87,15 +88,23 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_dat
         *   - MDA enabled
         * - Power management control on fc
         */
-       if (ifmsh->mesh_id_len == ie->mesh_id_len &&
-               memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 &&
-               (ifmsh->mesh_pp_id == ie->mesh_config->meshconf_psel) &&
-               (ifmsh->mesh_pm_id == ie->mesh_config->meshconf_pmetric) &&
-               (ifmsh->mesh_cc_id == ie->mesh_config->meshconf_congest) &&
-               (ifmsh->mesh_sp_id == ie->mesh_config->meshconf_synch) &&
-               (ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth))
-               return true;
-
+       if (!(ifmsh->mesh_id_len == ie->mesh_id_len &&
+            memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 &&
+            (ifmsh->mesh_pp_id == ie->mesh_config->meshconf_psel) &&
+            (ifmsh->mesh_pm_id == ie->mesh_config->meshconf_pmetric) &&
+            (ifmsh->mesh_cc_id == ie->mesh_config->meshconf_congest) &&
+            (ifmsh->mesh_sp_id == ie->mesh_config->meshconf_synch) &&
+            (ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth)))
+               goto mismatch;
+
+       /* disallow peering with mismatched channel types for now */
+       if (ie->ht_info_elem &&
+           (local->_oper_channel_type !=
+            ieee80211_ht_info_to_channel_type(ie->ht_info_elem)))
+               goto mismatch;
+
+       return true;
+mismatch:
        return false;
 }
 
@@ -341,6 +350,49 @@ int mesh_add_ds_params_ie(struct sk_buff *skb,
        return 0;
 }
 
+int mesh_add_ht_cap_ie(struct sk_buff *skb,
+                      struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_supported_band *sband;
+       u8 *pos;
+
+       sband = local->hw.wiphy->bands[local->oper_channel->band];
+       if (!sband->ht_cap.ht_supported ||
+           local->_oper_channel_type == NL80211_CHAN_NO_HT)
+               return 0;
+
+       if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_cap))
+               return -ENOMEM;
+
+       pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_cap));
+       ieee80211_ie_build_ht_cap(pos, sband, sband->ht_cap.cap);
+
+       return 0;
+}
+
+int mesh_add_ht_info_ie(struct sk_buff *skb,
+                       struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_channel *channel = local->oper_channel;
+       enum nl80211_channel_type channel_type = local->_oper_channel_type;
+       struct ieee80211_supported_band *sband =
+                               local->hw.wiphy->bands[channel->band];
+       struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap;
+       u8 *pos;
+
+       if (!ht_cap->ht_supported || channel_type == NL80211_CHAN_NO_HT)
+               return 0;
+
+       if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_info))
+               return -ENOMEM;
+
+       pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_info));
+       ieee80211_ie_build_ht_info(pos, ht_cap, channel, channel_type);
+
+       return 0;
+}
 static void ieee80211_mesh_path_timer(unsigned long data)
 {
        struct ieee80211_sub_if_data *sdata =
index 8c00e2d..622cc96 100644 (file)
@@ -31,6 +31,8 @@
  * @MESH_PATH_FIXED: the mesh path has been manually set and should not be
  *     modified
  * @MESH_PATH_RESOLVED: the mesh path can has been resolved
+ * @MESH_PATH_REQ_QUEUED: there is an unsent path request for this destination
+ * already queued up, waiting for the discovery process to start.
  *
  * MESH_PATH_RESOLVED is used by the mesh path timer to
  * decide when to stop or cancel the mesh path discovery.
@@ -41,6 +43,7 @@ enum mesh_path_flags {
        MESH_PATH_SN_VALID =    BIT(2),
        MESH_PATH_FIXED =       BIT(3),
        MESH_PATH_RESOLVED =    BIT(4),
+       MESH_PATH_REQ_QUEUED =  BIT(5),
 };
 
 /**
@@ -212,6 +215,10 @@ int mesh_add_vendor_ies(struct sk_buff *skb,
                        struct ieee80211_sub_if_data *sdata);
 int mesh_add_ds_params_ie(struct sk_buff *skb,
                          struct ieee80211_sub_if_data *sdata);
+int mesh_add_ht_cap_ie(struct sk_buff *skb,
+                      struct ieee80211_sub_if_data *sdata);
+int mesh_add_ht_info_ie(struct sk_buff *skb,
+                       struct ieee80211_sub_if_data *sdata);
 void mesh_rmc_free(struct ieee80211_sub_if_data *sdata);
 int mesh_rmc_init(struct ieee80211_sub_if_data *sdata);
 void ieee80211s_init(void);
index 174040a..a7afb2d 100644 (file)
@@ -113,20 +113,20 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
                struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_local *local = sdata->local;
-       struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
+       struct sk_buff *skb;
        struct ieee80211_mgmt *mgmt;
-       u8 *pos;
-       int ie_len;
+       u8 *pos, ie_len;
+       int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.mesh_action) +
+                     sizeof(mgmt->u.action.u.mesh_action);
 
+       skb = dev_alloc_skb(local->hw.extra_tx_headroom +
+                           hdr_len +
+                           2 + 37); /* max HWMP IE */
        if (!skb)
                return -1;
        skb_reserve(skb, local->hw.extra_tx_headroom);
-       /* 25 is the size of the common mgmt part (24) plus the size of the
-        * common action part (1)
-        */
-       mgmt = (struct ieee80211_mgmt *)
-               skb_put(skb, 25 + sizeof(mgmt->u.action.u.mesh_action));
-       memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.mesh_action));
+       mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
+       memset(mgmt, 0, hdr_len);
        mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                          IEEE80211_STYPE_ACTION);
 
@@ -240,20 +240,20 @@ int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn,
                       struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_local *local = sdata->local;
-       struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
+       struct sk_buff *skb;
        struct ieee80211_mgmt *mgmt;
-       u8 *pos;
-       int ie_len;
+       u8 *pos, ie_len;
+       int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.mesh_action) +
+                     sizeof(mgmt->u.action.u.mesh_action);
 
+       skb = dev_alloc_skb(local->hw.extra_tx_headroom +
+                           hdr_len +
+                           2 + 15 /* PERR IE */);
        if (!skb)
                return -1;
        skb_reserve(skb, local->tx_headroom + local->hw.extra_tx_headroom);
-       /* 25 is the size of the common mgmt part (24) plus the size of the
-        * common action part (1)
-        */
-       mgmt = (struct ieee80211_mgmt *)
-               skb_put(skb, 25 + sizeof(mgmt->u.action.u.mesh_action));
-       memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.mesh_action));
+       mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
+       memset(mgmt, 0, hdr_len);
        mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                          IEEE80211_STYPE_ACTION);
 
@@ -867,9 +867,19 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)
                return;
        }
 
+       spin_lock_bh(&mpath->state_lock);
+       if (mpath->flags & MESH_PATH_REQ_QUEUED) {
+               spin_unlock_bh(&mpath->state_lock);
+               spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
+               return;
+       }
+
        memcpy(preq_node->dst, mpath->dst, ETH_ALEN);
        preq_node->flags = flags;
 
+       mpath->flags |= MESH_PATH_REQ_QUEUED;
+       spin_unlock_bh(&mpath->state_lock);
+
        list_add_tail(&preq_node->list, &ifmsh->preq_queue.list);
        ++ifmsh->preq_queue_len;
        spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
@@ -921,6 +931,7 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
                goto enddiscovery;
 
        spin_lock_bh(&mpath->state_lock);
+       mpath->flags &= ~MESH_PATH_REQ_QUEUED;
        if (preq_node->flags & PREQ_Q_F_START) {
                if (mpath->flags & MESH_PATH_RESOLVING) {
                        spin_unlock_bh(&mpath->state_lock);
@@ -1028,11 +1039,11 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
                        mesh_queue_preq(mpath, PREQ_Q_F_START);
                }
 
-               if (skb_queue_len(&mpath->frame_queue) >=
-                               MESH_FRAME_QUEUE_LEN)
+               if (skb_queue_len(&mpath->frame_queue) >= MESH_FRAME_QUEUE_LEN)
                        skb_to_free = skb_dequeue(&mpath->frame_queue);
 
                info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
+               ieee80211_set_qos_hdr(sdata, skb);
                skb_queue_tail(&mpath->frame_queue, skb);
                if (skb_to_free)
                        mesh_path_discard_frame(skb_to_free, sdata);
@@ -1061,6 +1072,7 @@ void mesh_path_timer(unsigned long data)
        } else if (mpath->discovery_retries < max_preq_retries(sdata)) {
                ++mpath->discovery_retries;
                mpath->discovery_timeout *= 2;
+               mpath->flags &= ~MESH_PATH_REQ_QUEUED;
                spin_unlock_bh(&mpath->state_lock);
                mesh_queue_preq(mpath, 0);
        } else {
index 7f54c50..4fc23d1 100644 (file)
@@ -213,7 +213,6 @@ void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta)
        struct ieee80211_hdr *hdr;
        struct sk_buff_head tmpq;
        unsigned long flags;
-       struct ieee80211_sub_if_data *sdata = mpath->sdata;
 
        rcu_assign_pointer(mpath->next_hop, sta);
 
@@ -224,8 +223,6 @@ void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta)
        while ((skb = __skb_dequeue(&mpath->frame_queue)) != NULL) {
                hdr = (struct ieee80211_hdr *) skb->data;
                memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN);
-               skb_set_queue_mapping(skb, ieee80211_select_queue(sdata, skb));
-               ieee80211_set_qos_hdr(sdata, skb);
                __skb_queue_tail(&tmpq, skb);
        }
 
index 7e57f5d..0140e88 100644 (file)
@@ -80,11 +80,15 @@ static inline void mesh_plink_fsm_restart(struct sta_info *sta)
  *       on it in the lifecycle management section!
  */
 static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
-                                        u8 *hw_addr, u32 rates)
+                                        u8 *hw_addr, u32 rates,
+                                        struct ieee802_11_elems *elems)
 {
        struct ieee80211_local *local = sdata->local;
+       struct ieee80211_supported_band *sband;
        struct sta_info *sta;
 
+       sband = local->hw.wiphy->bands[local->oper_channel->band];
+
        if (local->num_sta >= MESH_MAX_PLINKS)
                return NULL;
 
@@ -96,6 +100,9 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
        set_sta_flag(sta, WLAN_STA_AUTHORIZED);
        set_sta_flag(sta, WLAN_STA_WME);
        sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
+       if (elems->ht_cap_elem)
+               ieee80211_ht_cap_ie_to_sta_ht_cap(sband, elems->ht_cap_elem,
+                                                 &sta->sta.ht_cap);
        rate_control_rate_init(sta);
 
        return sta;
@@ -153,23 +160,31 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
                enum ieee80211_self_protected_actioncode action,
                u8 *da, __le16 llid, __le16 plid, __le16 reason) {
        struct ieee80211_local *local = sdata->local;
-       struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400 +
-                       sdata->u.mesh.ie_len);
+       struct sk_buff *skb;
        struct ieee80211_mgmt *mgmt;
        bool include_plid = false;
-       int ie_len = 4;
        u16 peering_proto = 0;
-       u8 *pos;
-
+       u8 *pos, ie_len = 4;
+       int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.self_prot) +
+                     sizeof(mgmt->u.action.u.self_prot);
+
+       skb = dev_alloc_skb(local->hw.extra_tx_headroom +
+                           hdr_len +
+                           2 + /* capability info */
+                           2 + /* AID */
+                           2 + 8 + /* supported rates */
+                           2 + (IEEE80211_MAX_SUPP_RATES - 8) +
+                           2 + sdata->u.mesh.mesh_id_len +
+                           2 + sizeof(struct ieee80211_meshconf_ie) +
+                           2 + sizeof(struct ieee80211_ht_cap) +
+                           2 + sizeof(struct ieee80211_ht_info) +
+                           2 + 8 + /* peering IE */
+                           sdata->u.mesh.ie_len);
        if (!skb)
                return -1;
        skb_reserve(skb, local->hw.extra_tx_headroom);
-       /* 25 is the size of the common mgmt part (24) plus the size of the
-        * common action part (1)
-        */
-       mgmt = (struct ieee80211_mgmt *)
-               skb_put(skb, 25 + sizeof(mgmt->u.action.u.self_prot));
-       memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.self_prot));
+       mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
+       memset(mgmt, 0, hdr_len);
        mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                          IEEE80211_STYPE_ACTION);
        memcpy(mgmt->da, da, ETH_ALEN);
@@ -235,6 +250,13 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
                memcpy(pos, &reason, 2);
                pos += 2;
        }
+
+       if (action != WLAN_SP_MESH_PEERING_CLOSE) {
+               if (mesh_add_ht_cap_ie(skb, sdata) ||
+                   mesh_add_ht_info_ie(skb, sdata))
+                       return -1;
+       }
+
        if (mesh_add_vendor_ies(skb, sdata))
                return -1;
 
@@ -261,7 +283,7 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates,
                                        elems->ie_start, elems->total_len,
                                        GFP_KERNEL);
                else
-                       sta = mesh_plink_alloc(sdata, hw_addr, rates);
+                       sta = mesh_plink_alloc(sdata, hw_addr, rates, elems);
                if (!sta)
                        return;
                if (sta_info_insert_rcu(sta)) {
@@ -552,7 +574,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
                }
 
                rates = ieee80211_sta_get_rates(local, &elems, rx_status->band);
-               sta = mesh_plink_alloc(sdata, mgmt->sa, rates);
+               sta = mesh_plink_alloc(sdata, mgmt->sa, rates, &elems);
                if (!sta) {
                        mpl_dbg("Mesh plink error: plink table full\n");
                        return;
index 72c8bea..f9ec15b 100644 (file)
@@ -1468,6 +1468,47 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
        return RX_MGMT_CFG80211_DISASSOC;
 }
 
+static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
+                               u8 *supp_rates, unsigned int supp_rates_len,
+                               u32 *rates, u32 *basic_rates,
+                               bool *have_higher_than_11mbit,
+                               int *min_rate, int *min_rate_index)
+{
+       int i, j;
+
+       for (i = 0; i < supp_rates_len; i++) {
+               int rate = (supp_rates[i] & 0x7f) * 5;
+               bool is_basic = !!(supp_rates[i] & 0x80);
+
+               if (rate > 110)
+                       *have_higher_than_11mbit = true;
+
+               /*
+                * BSS_MEMBERSHIP_SELECTOR_HT_PHY is defined in 802.11n-2009
+                * 7.3.2.2 as a magic value instead of a rate. Hence, skip it.
+                *
+                * Note: Even through the membership selector and the basic
+                *       rate flag share the same bit, they are not exactly
+                *       the same.
+                */
+               if (!!(supp_rates[i] & 0x80) &&
+                   (supp_rates[i] & 0x7f) == BSS_MEMBERSHIP_SELECTOR_HT_PHY)
+                       continue;
+
+               for (j = 0; j < sband->n_bitrates; j++) {
+                       if (sband->bitrates[j].bitrate == rate) {
+                               *rates |= BIT(j);
+                               if (is_basic)
+                                       *basic_rates |= BIT(j);
+                               if (rate < *min_rate) {
+                                       *min_rate = rate;
+                                       *min_rate_index = j;
+                               }
+                               break;
+                       }
+               }
+       }
+}
 
 static bool ieee80211_assoc_success(struct ieee80211_work *wk,
                                    struct ieee80211_mgmt *mgmt, size_t len)
@@ -1484,9 +1525,10 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
        struct ieee802_11_elems elems;
        struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
        u32 changed = 0;
-       int i, j, err;
+       int err;
        bool have_higher_than_11mbit = false;
        u16 ap_ht_cap_flags;
+       int min_rate = INT_MAX, min_rate_index = -1;
 
        /* AssocResp and ReassocResp have identical structure */
 
@@ -1541,38 +1583,23 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
        basic_rates = 0;
        sband = local->hw.wiphy->bands[wk->chan->band];
 
-       for (i = 0; i < elems.supp_rates_len; i++) {
-               int rate = (elems.supp_rates[i] & 0x7f) * 5;
-               bool is_basic = !!(elems.supp_rates[i] & 0x80);
-
-               if (rate > 110)
-                       have_higher_than_11mbit = true;
-
-               for (j = 0; j < sband->n_bitrates; j++) {
-                       if (sband->bitrates[j].bitrate == rate) {
-                               rates |= BIT(j);
-                               if (is_basic)
-                                       basic_rates |= BIT(j);
-                               break;
-                       }
-               }
-       }
-
-       for (i = 0; i < elems.ext_supp_rates_len; i++) {
-               int rate = (elems.ext_supp_rates[i] & 0x7f) * 5;
-               bool is_basic = !!(elems.ext_supp_rates[i] & 0x80);
+       ieee80211_get_rates(sband, elems.supp_rates, elems.supp_rates_len,
+                           &rates, &basic_rates, &have_higher_than_11mbit,
+                           &min_rate, &min_rate_index);
 
-               if (rate > 110)
-                       have_higher_than_11mbit = true;
+       ieee80211_get_rates(sband, elems.ext_supp_rates,
+                           elems.ext_supp_rates_len, &rates, &basic_rates,
+                           &have_higher_than_11mbit,
+                           &min_rate, &min_rate_index);
 
-               for (j = 0; j < sband->n_bitrates; j++) {
-                       if (sband->bitrates[j].bitrate == rate) {
-                               rates |= BIT(j);
-                               if (is_basic)
-                                       basic_rates |= BIT(j);
-                               break;
-                       }
-               }
+       /*
+        * some buggy APs don't advertise basic_rates. use the lowest
+        * supported rate instead.
+        */
+       if (unlikely(!basic_rates) && min_rate_index >= 0) {
+               printk(KERN_DEBUG "%s: No basic rates in AssocResp. "
+                      "Using min supported rate instead.\n", sdata->name);
+               basic_rates = BIT(min_rate_index);
        }
 
        sta->sta.supp_rates[wk->chan->band] = rates;
@@ -2269,6 +2296,7 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata)
 
        cancel_work_sync(&ifmgd->request_smps_work);
 
+       cancel_work_sync(&ifmgd->monitor_work);
        cancel_work_sync(&ifmgd->beacon_connection_loss_work);
        if (del_timer_sync(&ifmgd->timer))
                set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running);
@@ -2277,7 +2305,6 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata)
        if (del_timer_sync(&ifmgd->chswitch_timer))
                set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running);
 
-       cancel_work_sync(&ifmgd->monitor_work);
        /* these will just be re-established on connection */
        del_timer_sync(&ifmgd->conn_mon_timer);
        del_timer_sync(&ifmgd->bcn_mon_timer);
index 9ee7164..596efaf 100644 (file)
@@ -125,7 +125,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
                ieee80211_bss_info_change_notify(sdata,
                        BSS_CHANGED_BEACON_ENABLED);
 
-               drv_remove_interface(local, &sdata->vif);
+               drv_remove_interface(local, sdata);
        }
 
        /* stop hardware - this must stop RX */
index 58a8955..b39dda5 100644 (file)
@@ -334,8 +334,8 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
 
 
 static void
-calc_rate_durations(struct minstrel_sta_info *mi, struct ieee80211_local *local,
-                    struct minstrel_rate *d, struct ieee80211_rate *rate)
+calc_rate_durations(struct ieee80211_local *local, struct minstrel_rate *d,
+                   struct ieee80211_rate *rate)
 {
        int erp = !!(rate->flags & IEEE80211_RATE_ERP_G);
 
@@ -402,8 +402,7 @@ minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband,
 
                mr->rix = i;
                mr->bitrate = sband->bitrates[i].bitrate / 5;
-               calc_rate_durations(mi, local, mr,
-                               &sband->bitrates[i]);
+               calc_rate_durations(local, mr, &sband->bitrates[i]);
 
                /* calculate maximum number of retransmissions before
                 * fallback (based on maximum segment size) */
index bb53726..d1a8869 100644 (file)
@@ -141,8 +141,9 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
        pos++;
 
        /* IEEE80211_RADIOTAP_RATE */
-       if (status->flag & RX_FLAG_HT) {
+       if (!rate || status->flag & RX_FLAG_HT) {
                /*
+                * Without rate information don't add it. If we have,
                 * MCS information is a separate field in radiotap,
                 * added below. The byte here is needed as padding
                 * for the channel though, so initialise it to 0.
@@ -163,12 +164,14 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
        else if (status->flag & RX_FLAG_HT)
                put_unaligned_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ,
                                   pos);
-       else if (rate->flags & IEEE80211_RATE_ERP_G)
+       else if (rate && rate->flags & IEEE80211_RATE_ERP_G)
                put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ,
                                   pos);
-       else
+       else if (rate)
                put_unaligned_le16(IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ,
                                   pos);
+       else
+               put_unaligned_le16(IEEE80211_CHAN_2GHZ, pos);
        pos += 2;
 
        /* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */
@@ -745,10 +748,11 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx)
        struct ieee80211_local *local = rx->local;
        struct ieee80211_hw *hw = &local->hw;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
        struct sta_info *sta = rx->sta;
        struct tid_ampdu_rx *tid_agg_rx;
        u16 sc;
-       int tid;
+       u8 tid, ack_policy;
 
        if (!ieee80211_is_data_qos(hdr->frame_control))
                goto dont_reorder;
@@ -761,6 +765,8 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx)
        if (!sta)
                goto dont_reorder;
 
+       ack_policy = *ieee80211_get_qos_ctl(hdr) &
+                    IEEE80211_QOS_CTL_ACK_POLICY_MASK;
        tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
 
        tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
@@ -771,6 +777,15 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx)
        if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC)))
                goto dont_reorder;
 
+       /* not part of a BA session */
+       if (ack_policy != IEEE80211_QOS_CTL_ACK_POLICY_BLOCKACK &&
+           ack_policy != IEEE80211_QOS_CTL_ACK_POLICY_NORMAL)
+               goto dont_reorder;
+
+       /* not actually part of this BA session */
+       if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
+               goto dont_reorder;
+
        /* new, potentially un-ordered, ampdu frame - process it */
 
        /* reset session timer */
@@ -855,6 +870,13 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
                            rx->sdata->control_port_protocol)
                                return RX_CONTINUE;
                }
+
+               if (rx->sdata->vif.type == NL80211_IFTYPE_AP &&
+                   cfg80211_rx_spurious_frame(rx->sdata->dev,
+                                              hdr->addr2,
+                                              GFP_ATOMIC))
+                       return RX_DROP_UNUSABLE;
+
                return RX_DROP_MONITOR;
        }
 
@@ -1324,15 +1346,20 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
 
                /*
                 * If we receive a 4-addr nullfunc frame from a STA
-                * that was not moved to a 4-addr STA vlan yet, drop
-                * the frame to the monitor interface, to make sure
-                * that hostapd sees it
+                * that was not moved to a 4-addr STA vlan yet send
+                * the event to userspace and for older hostapd drop
+                * the frame to the monitor interface.
                 */
                if (ieee80211_has_a4(hdr->frame_control) &&
                    (rx->sdata->vif.type == NL80211_IFTYPE_AP ||
                     (rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
-                     !rx->sdata->u.vlan.sta)))
+                     !rx->sdata->u.vlan.sta))) {
+                       if (!test_and_set_sta_flag(sta, WLAN_STA_4ADDR_EVENT))
+                               cfg80211_rx_unexpected_4addr_frame(
+                                       rx->sdata->dev, sta->sta.addr,
+                                       GFP_ATOMIC);
                        return RX_DROP_MONITOR;
+               }
                /*
                 * Update counter and free packet here to avoid
                 * counting this as a dropped packed.
@@ -1930,6 +1957,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
            compare_ether_addr(sdata->vif.addr, hdr->addr3) == 0)
                return RX_CONTINUE;
 
+       skb_set_queue_mapping(skb, ieee80211_select_queue(sdata, skb));
        mesh_hdr->ttl--;
 
        if (status->rx_flags & IEEE80211_RX_RA_MATCH) {
@@ -1954,12 +1982,10 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
                        memset(info, 0, sizeof(*info));
                        info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
                        info->control.vif = &rx->sdata->vif;
+                       info->control.jiffies = jiffies;
                        if (is_multicast_ether_addr(fwd_hdr->addr1)) {
                                IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
                                                                fwded_mcast);
-                               skb_set_queue_mapping(fwd_skb,
-                                       ieee80211_select_queue(sdata, fwd_skb));
-                               ieee80211_set_qos_hdr(sdata, fwd_skb);
                        } else {
                                int err;
                                /*
@@ -2011,12 +2037,17 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
                return RX_DROP_MONITOR;
 
        /*
-        * Allow the cooked monitor interface of an AP to see 4-addr frames so
-        * that a 4-addr station can be detected and moved into a separate VLAN
+        * Send unexpected-4addr-frame event to hostapd. For older versions,
+        * also drop the frame to cooked monitor interfaces.
         */
        if (ieee80211_has_a4(hdr->frame_control) &&
-           sdata->vif.type == NL80211_IFTYPE_AP)
+           sdata->vif.type == NL80211_IFTYPE_AP) {
+               if (rx->sta &&
+                   !test_and_set_sta_flag(rx->sta, WLAN_STA_4ADDR_EVENT))
+                       cfg80211_rx_unexpected_4addr_frame(
+                               rx->sdata->dev, rx->sta->sta.addr, GFP_ATOMIC);
                return RX_DROP_MONITOR;
+       }
 
        err = __ieee80211_data_to_8023(rx, &port_control);
        if (unlikely(err))
@@ -2171,6 +2202,18 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
        if (!ieee80211_is_mgmt(mgmt->frame_control))
                return RX_DROP_MONITOR;
 
+       if (rx->sdata->vif.type == NL80211_IFTYPE_AP &&
+           ieee80211_is_beacon(mgmt->frame_control) &&
+           !(rx->flags & IEEE80211_RX_BEACON_REPORTED)) {
+               struct ieee80211_rx_status *status;
+
+               status = IEEE80211_SKB_RXCB(rx->skb);
+               cfg80211_report_obss_beacon(rx->local->hw.wiphy,
+                                           rx->skb->data, rx->skb->len,
+                                           status->freq, GFP_ATOMIC);
+               rx->flags |= IEEE80211_RX_BEACON_REPORTED;
+       }
+
        if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
                return RX_DROP_MONITOR;
 
@@ -2204,13 +2247,8 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
 
        switch (mgmt->u.action.category) {
        case WLAN_CATEGORY_BACK:
-               /*
-                * The aggregation code is not prepared to handle
-                * anything but STA/AP due to the BSSID handling;
-                * IBSS could work in the code but isn't supported
-                * by drivers or the standard.
-                */
                if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+                   sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
                    sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
                    sdata->vif.type != NL80211_IFTYPE_AP)
                        break;
@@ -2490,6 +2528,10 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
                goto out_free_skb;
        rx->flags |= IEEE80211_RX_CMNTR;
 
+       /* If there are no cooked monitor interfaces, just free the SKB */
+       if (!local->cooked_mntrs)
+               goto out_free_skb;
+
        if (skb_headroom(skb) < sizeof(*rthdr) &&
            pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC))
                goto out_free_skb;
index 105436d..8186303 100644 (file)
@@ -213,12 +213,7 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
        if (bss)
                ieee80211_rx_bss_put(sdata->local, bss);
 
-       /* If we are on-operating-channel, and this packet is for the
-        * current channel, pass the pkt on up the stack so that
-        * the rest of the stack can make use of it.
-        */
-       if (ieee80211_cfg_on_oper_channel(sdata->local)
-           && (channel == sdata->local->oper_channel))
+       if (channel == sdata->local->oper_channel)
                return RX_CONTINUE;
 
        dev_kfree_skb(skb);
@@ -264,8 +259,6 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
                                       bool was_hw_scan)
 {
        struct ieee80211_local *local = hw_to_local(hw);
-       bool on_oper_chan;
-       bool enable_beacons = false;
 
        lockdep_assert_held(&local->mtx);
 
@@ -298,25 +291,13 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
        local->scanning = 0;
        local->scan_channel = NULL;
 
-       on_oper_chan = ieee80211_cfg_on_oper_channel(local);
-
-       if (was_hw_scan || !on_oper_chan)
-               ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
-       else
-               /* Set power back to normal operating levels. */
-               ieee80211_hw_config(local, 0);
+       /* Set power back to normal operating levels. */
+       ieee80211_hw_config(local, 0);
 
        if (!was_hw_scan) {
-               bool on_oper_chan2;
                ieee80211_configure_filter(local);
                drv_sw_scan_complete(local);
-               on_oper_chan2 = ieee80211_cfg_on_oper_channel(local);
-               /* We should always be on-channel at this point. */
-               WARN_ON(!on_oper_chan2);
-               if (on_oper_chan2 && (on_oper_chan != on_oper_chan2))
-                       enable_beacons = true;
-
-               ieee80211_offchannel_return(local, enable_beacons, true);
+               ieee80211_offchannel_return(local, true, true);
        }
 
        ieee80211_recalc_idle(local);
@@ -361,11 +342,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
        local->next_scan_state = SCAN_DECISION;
        local->scan_channel_idx = 0;
 
-       /* We always want to use off-channel PS, even if we
-        * are not really leaving oper-channel.  Don't
-        * tell the AP though, as long as we are on-channel.
-        */
-       ieee80211_offchannel_enable_all_ps(local, false);
+       ieee80211_offchannel_stop_vifs(local, true);
 
        ieee80211_configure_filter(local);
 
@@ -373,8 +350,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
        ieee80211_hw_config(local, 0);
 
        ieee80211_queue_delayed_work(&local->hw,
-                                    &local->scan_work,
-                                    IEEE80211_CHANNEL_TIME);
+                                    &local->scan_work, 0);
 
        return 0;
 }
@@ -510,96 +486,39 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local,
 
        next_chan = local->scan_req->channels[local->scan_channel_idx];
 
-       if (ieee80211_cfg_on_oper_channel(local)) {
-               /* We're currently on operating channel. */
-               if (next_chan == local->oper_channel)
-                       /* We don't need to move off of operating channel. */
-                       local->next_scan_state = SCAN_SET_CHANNEL;
-               else
-                       /*
-                        * We do need to leave operating channel, as next
-                        * scan is somewhere else.
-                        */
-                       local->next_scan_state = SCAN_LEAVE_OPER_CHANNEL;
-       } else {
-               /*
-                * we're currently scanning a different channel, let's
-                * see if we can scan another channel without interfering
-                * with the current traffic situation.
-                *
-                * Since we don't know if the AP has pending frames for us
-                * we can only check for our tx queues and use the current
-                * pm_qos requirements for rx. Hence, if no tx traffic occurs
-                * at all we will scan as many channels in a row as the pm_qos
-                * latency allows us to. Additionally we also check for the
-                * currently negotiated listen interval to prevent losing
-                * frames unnecessarily.
-                *
-                * Otherwise switch back to the operating channel.
-                */
-
-               bad_latency = time_after(jiffies +
-                               ieee80211_scan_get_channel_time(next_chan),
-                               local->leave_oper_channel_time +
-                               usecs_to_jiffies(pm_qos_request(PM_QOS_NETWORK_LATENCY)));
-
-               listen_int_exceeded = time_after(jiffies +
-                               ieee80211_scan_get_channel_time(next_chan),
-                               local->leave_oper_channel_time +
-                               usecs_to_jiffies(min_beacon_int * 1024) *
-                               local->hw.conf.listen_interval);
-
-               if (associated && ( !tx_empty || bad_latency ||
-                   listen_int_exceeded))
-                       local->next_scan_state = SCAN_ENTER_OPER_CHANNEL;
-               else
-                       local->next_scan_state = SCAN_SET_CHANNEL;
-       }
-
-       *next_delay = 0;
-}
-
-static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local,
-                                                   unsigned long *next_delay)
-{
-       /* PS will already be in off-channel mode,
-        * we do that once at the beginning of scanning.
-        */
-       ieee80211_offchannel_stop_vifs(local, false);
-
        /*
-        * What if the nullfunc frames didn't arrive?
+        * we're currently scanning a different channel, let's
+        * see if we can scan another channel without interfering
+        * with the current traffic situation.
+        *
+        * Since we don't know if the AP has pending frames for us
+        * we can only check for our tx queues and use the current
+        * pm_qos requirements for rx. Hence, if no tx traffic occurs
+        * at all we will scan as many channels in a row as the pm_qos
+        * latency allows us to. Additionally we also check for the
+        * currently negotiated listen interval to prevent losing
+        * frames unnecessarily.
+        *
+        * Otherwise switch back to the operating channel.
         */
-       drv_flush(local, false);
-       if (local->ops->flush)
-               *next_delay = 0;
-       else
-               *next_delay = HZ / 10;
 
-       /* remember when we left the operating channel */
-       local->leave_oper_channel_time = jiffies;
+       bad_latency = time_after(jiffies +
+                       ieee80211_scan_get_channel_time(next_chan),
+                       local->leave_oper_channel_time +
+                       usecs_to_jiffies(pm_qos_request(PM_QOS_NETWORK_LATENCY)));
 
-       /* advance to the next channel to be scanned */
-       local->next_scan_state = SCAN_SET_CHANNEL;
-}
-
-static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *local,
-                                                   unsigned long *next_delay)
-{
-       /* switch back to the operating channel */
-       local->scan_channel = NULL;
-       if (!ieee80211_cfg_on_oper_channel(local))
-               ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+       listen_int_exceeded = time_after(jiffies +
+                       ieee80211_scan_get_channel_time(next_chan),
+                       local->leave_oper_channel_time +
+                       usecs_to_jiffies(min_beacon_int * 1024) *
+                       local->hw.conf.listen_interval);
 
-       /*
-        * Re-enable vifs and beaconing.  Leave PS
-        * in off-channel state..will put that back
-        * on-channel at the end of scanning.
-        */
-       ieee80211_offchannel_return(local, true, false);
+       if (associated && (!tx_empty || bad_latency || listen_int_exceeded))
+               local->next_scan_state = SCAN_SUSPEND;
+       else
+               local->next_scan_state = SCAN_SET_CHANNEL;
 
-       *next_delay = HZ / 5;
-       local->next_scan_state = SCAN_DECISION;
+       *next_delay = 0;
 }
 
 static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
@@ -613,10 +532,8 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
 
        local->scan_channel = chan;
 
-       /* Only call hw-config if we really need to change channels. */
-       if (chan != local->hw.conf.channel)
-               if (ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL))
-                       skip = 1;
+       if (ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL))
+               skip = 1;
 
        /* advance state machine to next channel/band */
        local->scan_channel_idx++;
@@ -673,6 +590,44 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
        local->next_scan_state = SCAN_DECISION;
 }
 
+static void ieee80211_scan_state_suspend(struct ieee80211_local *local,
+                                        unsigned long *next_delay)
+{
+       /* switch back to the operating channel */
+       local->scan_channel = NULL;
+       ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+
+       /*
+        * Re-enable vifs and beaconing.  Leave PS
+        * in off-channel state..will put that back
+        * on-channel at the end of scanning.
+        */
+       ieee80211_offchannel_return(local, true, false);
+
+       *next_delay = HZ / 5;
+       /* afterwards, resume scan & go to next channel */
+       local->next_scan_state = SCAN_RESUME;
+}
+
+static void ieee80211_scan_state_resume(struct ieee80211_local *local,
+                                       unsigned long *next_delay)
+{
+       /* PS already is in off-channel mode */
+       ieee80211_offchannel_stop_vifs(local, false);
+
+       if (local->ops->flush) {
+               drv_flush(local, false);
+               *next_delay = 0;
+       } else
+               *next_delay = HZ / 10;
+
+       /* remember when we left the operating channel */
+       local->leave_oper_channel_time = jiffies;
+
+       /* advance to the next channel to be scanned */
+       local->next_scan_state = SCAN_DECISION;
+}
+
 void ieee80211_scan_work(struct work_struct *work)
 {
        struct ieee80211_local *local =
@@ -743,11 +698,11 @@ void ieee80211_scan_work(struct work_struct *work)
                case SCAN_SEND_PROBE:
                        ieee80211_scan_state_send_probe(local, &next_delay);
                        break;
-               case SCAN_LEAVE_OPER_CHANNEL:
-                       ieee80211_scan_state_leave_oper_channel(local, &next_delay);
+               case SCAN_SUSPEND:
+                       ieee80211_scan_state_suspend(local, &next_delay);
                        break;
-               case SCAN_ENTER_OPER_CHANNEL:
-                       ieee80211_scan_state_enter_oper_channel(local, &next_delay);
+               case SCAN_RESUME:
+                       ieee80211_scan_state_resume(local, &next_delay);
                        break;
                }
        } while (next_delay == 0);
index ce962d2..8eaa746 100644 (file)
@@ -1354,12 +1354,12 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
                         * Use MoreData flag to indicate whether there are
                         * more buffered frames for this STA
                         */
-                       if (!more_data)
-                               hdr->frame_control &=
-                                       cpu_to_le16(~IEEE80211_FCTL_MOREDATA);
-                       else
+                       if (more_data || !skb_queue_empty(&frames))
                                hdr->frame_control |=
                                        cpu_to_le16(IEEE80211_FCTL_MOREDATA);
+                       else
+                               hdr->frame_control &=
+                                       cpu_to_le16(~IEEE80211_FCTL_MOREDATA);
 
                        if (ieee80211_is_data_qos(hdr->frame_control) ||
                            ieee80211_is_qos_nullfunc(hdr->frame_control))
index 8c8ce05..c5923ab 100644 (file)
@@ -52,6 +52,7 @@
  *     unblocks the station.
  * @WLAN_STA_SP: Station is in a service period, so don't try to
  *     reply to other uAPSD trigger frames or PS-Poll.
+ * @WLAN_STA_4ADDR_EVENT: 4-addr event was already sent for this frame.
  */
 enum ieee80211_sta_info_flags {
        WLAN_STA_AUTH,
@@ -71,6 +72,7 @@ enum ieee80211_sta_info_flags {
        WLAN_STA_TDLS_PEER_AUTH,
        WLAN_STA_UAPSD,
        WLAN_STA_SP,
+       WLAN_STA_4ADDR_EVENT,
 };
 
 #define STA_TID_NUM 16
@@ -390,6 +392,12 @@ static inline int test_and_clear_sta_flag(struct sta_info *sta,
        return test_and_clear_bit(flag, &sta->_flags);
 }
 
+static inline int test_and_set_sta_flag(struct sta_info *sta,
+                                       enum ieee80211_sta_info_flags flag)
+{
+       return test_and_set_bit(flag, &sta->_flags);
+}
+
 void ieee80211_assign_tid_tx(struct sta_info *sta, int tid,
                             struct tid_ampdu_tx *tid_tx);
 
index 80de436..a9da6ee 100644 (file)
@@ -517,27 +517,54 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
        }
 
        if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) {
-               struct ieee80211_work *wk;
                u64 cookie = (unsigned long)skb;
 
-               rcu_read_lock();
-               list_for_each_entry_rcu(wk, &local->work_list, list) {
-                       if (wk->type != IEEE80211_WORK_OFFCHANNEL_TX)
-                               continue;
-                       if (wk->offchan_tx.frame != skb)
-                               continue;
-                       wk->offchan_tx.status = true;
-                       break;
-               }
-               rcu_read_unlock();
-               if (local->hw_roc_skb_for_status == skb) {
-                       cookie = local->hw_roc_cookie ^ 2;
-                       local->hw_roc_skb_for_status = NULL;
+               if (ieee80211_is_nullfunc(hdr->frame_control) ||
+                   ieee80211_is_qos_nullfunc(hdr->frame_control)) {
+                       bool acked = info->flags & IEEE80211_TX_STAT_ACK;
+                       cfg80211_probe_status(skb->dev, hdr->addr1,
+                                             cookie, acked, GFP_ATOMIC);
+               } else {
+                       struct ieee80211_work *wk;
+
+                       rcu_read_lock();
+                       list_for_each_entry_rcu(wk, &local->work_list, list) {
+                               if (wk->type != IEEE80211_WORK_OFFCHANNEL_TX)
+                                       continue;
+                               if (wk->offchan_tx.frame != skb)
+                                       continue;
+                               wk->offchan_tx.status = true;
+                               break;
+                       }
+                       rcu_read_unlock();
+                       if (local->hw_roc_skb_for_status == skb) {
+                               cookie = local->hw_roc_cookie ^ 2;
+                               local->hw_roc_skb_for_status = NULL;
+                       }
+
+                       cfg80211_mgmt_tx_status(
+                               skb->dev, cookie, skb->data, skb->len,
+                               !!(info->flags & IEEE80211_TX_STAT_ACK),
+                               GFP_ATOMIC);
                }
+       }
 
-               cfg80211_mgmt_tx_status(
-                       skb->dev, cookie, skb->data, skb->len,
-                       !!(info->flags & IEEE80211_TX_STAT_ACK), GFP_ATOMIC);
+       if (unlikely(info->ack_frame_id)) {
+               struct sk_buff *ack_skb;
+               unsigned long flags;
+
+               spin_lock_irqsave(&local->ack_status_lock, flags);
+               ack_skb = idr_find(&local->ack_status_frames,
+                                  info->ack_frame_id);
+               if (ack_skb)
+                       idr_remove(&local->ack_status_frames,
+                                  info->ack_frame_id);
+               spin_unlock_irqrestore(&local->ack_status_lock, flags);
+
+               /* consumes ack_skb */
+               if (ack_skb)
+                       skb_complete_wifi_ack(ack_skb,
+                               info->flags & IEEE80211_TX_STAT_ACK);
        }
 
        /* this was a transmitted frame, but now we want to reuse it */
@@ -610,3 +637,29 @@ void ieee80211_report_low_ack(struct ieee80211_sta *pubsta, u32 num_packets)
                                    num_packets, GFP_ATOMIC);
 }
 EXPORT_SYMBOL(ieee80211_report_low_ack);
+
+void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+       if (unlikely(info->ack_frame_id)) {
+               struct sk_buff *ack_skb;
+               unsigned long flags;
+
+               spin_lock_irqsave(&local->ack_status_lock, flags);
+               ack_skb = idr_find(&local->ack_status_frames,
+                                  info->ack_frame_id);
+               if (ack_skb)
+                       idr_remove(&local->ack_status_frames,
+                                  info->ack_frame_id);
+               spin_unlock_irqrestore(&local->ack_status_lock, flags);
+
+               /* consumes ack_skb */
+               if (ack_skb)
+                       dev_kfree_skb_any(ack_skb);
+       }
+
+       dev_kfree_skb_any(skb);
+}
+EXPORT_SYMBOL(ieee80211_free_txskb);
index 1f8b120..f044963 100644 (file)
@@ -1685,8 +1685,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
        int nh_pos, h_pos;
        struct sta_info *sta = NULL;
        bool wme_sta = false, authorized = false, tdls_auth = false;
-       struct sk_buff *tmp_skb;
        bool tdls_direct = false;
+       bool multicast;
+       u32 info_flags = 0;
+       u16 info_id = 0;
 
        if (unlikely(skb->len < ETH_HLEN)) {
                ret = NETDEV_TX_OK;
@@ -1873,7 +1875,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
         * if it is a multicast address (which can only happen
         * in AP mode)
         */
-       if (!is_multicast_ether_addr(hdr.addr1)) {
+       multicast = is_multicast_ether_addr(hdr.addr1);
+       if (!multicast) {
                rcu_read_lock();
                sta = sta_info_get(sdata, hdr.addr1);
                if (sta) {
@@ -1914,11 +1917,54 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                goto fail;
        }
 
+       if (unlikely(!multicast && skb->sk &&
+                    skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS)) {
+               struct sk_buff *orig_skb = skb;
+
+               skb = skb_clone(skb, GFP_ATOMIC);
+               if (skb) {
+                       unsigned long flags;
+                       int id, r;
+
+                       spin_lock_irqsave(&local->ack_status_lock, flags);
+                       r = idr_get_new_above(&local->ack_status_frames,
+                                             orig_skb, 1, &id);
+                       if (r == -EAGAIN) {
+                               idr_pre_get(&local->ack_status_frames,
+                                           GFP_ATOMIC);
+                               r = idr_get_new_above(&local->ack_status_frames,
+                                                     orig_skb, 1, &id);
+                       }
+                       if (WARN_ON(!id) || id > 0xffff) {
+                               idr_remove(&local->ack_status_frames, id);
+                               r = -ERANGE;
+                       }
+                       spin_unlock_irqrestore(&local->ack_status_lock, flags);
+
+                       if (!r) {
+                               info_id = id;
+                               info_flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
+                       } else if (skb_shared(skb)) {
+                               kfree_skb(orig_skb);
+                       } else {
+                               kfree_skb(skb);
+                               skb = orig_skb;
+                       }
+               } else {
+                       /* couldn't clone -- lose tx status ... */
+                       skb = orig_skb;
+               }
+       }
+
        /*
         * If the skb is shared we need to obtain our own copy.
         */
        if (skb_shared(skb)) {
-               tmp_skb = skb;
+               struct sk_buff *tmp_skb = skb;
+
+               /* can't happen -- skb is a clone if info_id != 0 */
+               WARN_ON(info_id);
+
                skb = skb_clone(skb, GFP_ATOMIC);
                kfree_skb(tmp_skb);
 
@@ -2019,6 +2065,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
        memset(info, 0, sizeof(*info));
 
        dev->trans_start = jiffies;
+
+       info->flags = info_flags;
+       info->ack_frame_id = info_id;
+
        ieee80211_xmit(sdata, skb);
 
        return NETDEV_TX_OK;
@@ -2279,22 +2329,31 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
        } else if (ieee80211_vif_is_mesh(&sdata->vif)) {
                struct ieee80211_mgmt *mgmt;
                u8 *pos;
+               int hdr_len = offsetof(struct ieee80211_mgmt, u.beacon) +
+                             sizeof(mgmt->u.beacon);
 
 #ifdef CONFIG_MAC80211_MESH
                if (!sdata->u.mesh.mesh_id_len)
                        goto out;
 #endif
 
-               /* headroom, head length, tail length and maximum TIM length */
-               skb = dev_alloc_skb(local->tx_headroom + 400 +
-                               sdata->u.mesh.ie_len);
+               skb = dev_alloc_skb(local->tx_headroom +
+                                   hdr_len +
+                                   2 + /* NULL SSID */
+                                   2 + 8 + /* supported rates */
+                                   2 + 3 + /* DS params */
+                                   2 + (IEEE80211_MAX_SUPP_RATES - 8) +
+                                   2 + sizeof(struct ieee80211_ht_cap) +
+                                   2 + sizeof(struct ieee80211_ht_info) +
+                                   2 + sdata->u.mesh.mesh_id_len +
+                                   2 + sizeof(struct ieee80211_meshconf_ie) +
+                                   sdata->u.mesh.ie_len);
                if (!skb)
                        goto out;
 
                skb_reserve(skb, local->hw.extra_tx_headroom);
-               mgmt = (struct ieee80211_mgmt *)
-                       skb_put(skb, 24 + sizeof(mgmt->u.beacon));
-               memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
+               mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
+               memset(mgmt, 0, hdr_len);
                mgmt->frame_control =
                    cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON);
                memset(mgmt->da, 0xff, ETH_ALEN);
@@ -2313,6 +2372,8 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
                    mesh_add_ds_params_ie(skb, sdata) ||
                    ieee80211_add_ext_srates_ie(&sdata->vif, skb) ||
                    mesh_add_rsn_ie(skb, sdata) ||
+                   mesh_add_ht_cap_ie(skb, sdata) ||
+                   mesh_add_ht_info_ie(skb, sdata) ||
                    mesh_add_meshid_ie(skb, sdata) ||
                    mesh_add_meshconf_ie(skb, sdata) ||
                    mesh_add_vendor_ies(skb, sdata)) {
@@ -2355,6 +2416,37 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
 }
 EXPORT_SYMBOL(ieee80211_beacon_get_tim);
 
+struct sk_buff *ieee80211_proberesp_get(struct ieee80211_hw *hw,
+                                       struct ieee80211_vif *vif)
+{
+       struct ieee80211_if_ap *ap = NULL;
+       struct sk_buff *presp = NULL, *skb = NULL;
+       struct ieee80211_hdr *hdr;
+       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+
+       if (sdata->vif.type != NL80211_IFTYPE_AP)
+               return NULL;
+
+       rcu_read_lock();
+
+       ap = &sdata->u.ap;
+       presp = rcu_dereference(ap->probe_resp);
+       if (!presp)
+               goto out;
+
+       skb = skb_copy(presp, GFP_ATOMIC);
+       if (!skb)
+               goto out;
+
+       hdr = (struct ieee80211_hdr *) skb->data;
+       memset(hdr->addr1, 0, sizeof(hdr->addr1));
+
+out:
+       rcu_read_unlock();
+       return skb;
+}
+EXPORT_SYMBOL(ieee80211_proberesp_get);
+
 struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw,
                                     struct ieee80211_vif *vif)
 {
index 51e256c..3a00814 100644 (file)
@@ -812,23 +812,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
                offset = noffset;
        }
 
-       if (sband->ht_cap.ht_supported) {
-               u16 cap = sband->ht_cap.cap;
-               __le16 tmp;
-
-               *pos++ = WLAN_EID_HT_CAPABILITY;
-               *pos++ = sizeof(struct ieee80211_ht_cap);
-               memset(pos, 0, sizeof(struct ieee80211_ht_cap));
-               tmp = cpu_to_le16(cap);
-               memcpy(pos, &tmp, sizeof(u16));
-               pos += sizeof(u16);
-               *pos++ = sband->ht_cap.ampdu_factor |
-                        (sband->ht_cap.ampdu_density <<
-                               IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
-               memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
-               pos += sizeof(sband->ht_cap.mcs);
-               pos += 2 + 4 + 1; /* ext info, BF cap, antsel */
-       }
+       if (sband->ht_cap.ht_supported)
+               pos = ieee80211_ie_build_ht_cap(pos, sband, sband->ht_cap.cap);
 
        /*
         * If adding more here, adjust code in main.c
@@ -881,6 +866,8 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
        skb = ieee80211_probereq_get(&local->hw, &sdata->vif,
                                     ssid, ssid_len,
                                     buf, buf_len);
+       if (!skb)
+               goto out;
 
        if (dst) {
                mgmt = (struct ieee80211_mgmt *) skb->data;
@@ -889,6 +876,8 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
        }
 
        IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+
+ out:
        kfree(buf);
 
        return skb;
@@ -1022,7 +1011,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
                    sdata->vif.type != NL80211_IFTYPE_MONITOR &&
                    ieee80211_sdata_running(sdata))
-                       res = drv_add_interface(local, &sdata->vif);
+                       res = drv_add_interface(local, sdata);
        }
 
        /* add STAs back */
@@ -1073,7 +1062,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                          BSS_CHANGED_BEACON_INT |
                          BSS_CHANGED_BSSID |
                          BSS_CHANGED_CQM |
-                         BSS_CHANGED_QOS;
+                         BSS_CHANGED_QOS |
+                         BSS_CHANGED_IDLE;
 
                switch (sdata->vif.type) {
                case NL80211_IFTYPE_STATION:
@@ -1086,7 +1076,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                        changed |= BSS_CHANGED_IBSS;
                        /* fall through */
                case NL80211_IFTYPE_AP:
-                       changed |= BSS_CHANGED_SSID;
+                       changed |= BSS_CHANGED_SSID |
+                                  BSS_CHANGED_AP_PROBE_RESP;
                        /* fall through */
                case NL80211_IFTYPE_MESH_POINT:
                        changed |= BSS_CHANGED_BEACON |
@@ -1108,6 +1099,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                }
        }
 
+       ieee80211_recalc_ps(local, -1);
+
        /*
         * Clear the WLAN_STA_BLOCK_BA flag so new aggregation
         * sessions can be established after a resume.
@@ -1363,6 +1356,103 @@ void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif)
 }
 EXPORT_SYMBOL(ieee80211_disable_rssi_reports);
 
+u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_supported_band *sband,
+                             u16 cap)
+{
+       __le16 tmp;
+
+       *pos++ = WLAN_EID_HT_CAPABILITY;
+       *pos++ = sizeof(struct ieee80211_ht_cap);
+       memset(pos, 0, sizeof(struct ieee80211_ht_cap));
+
+       /* capability flags */
+       tmp = cpu_to_le16(cap);
+       memcpy(pos, &tmp, sizeof(u16));
+       pos += sizeof(u16);
+
+       /* AMPDU parameters */
+       *pos++ = sband->ht_cap.ampdu_factor |
+                (sband->ht_cap.ampdu_density <<
+                       IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
+
+       /* MCS set */
+       memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
+       pos += sizeof(sband->ht_cap.mcs);
+
+       /* extended capabilities */
+       pos += sizeof(__le16);
+
+       /* BF capabilities */
+       pos += sizeof(__le32);
+
+       /* antenna selection */
+       pos += sizeof(u8);
+
+       return pos;
+}
+
+u8 *ieee80211_ie_build_ht_info(u8 *pos,
+                              struct ieee80211_sta_ht_cap *ht_cap,
+                              struct ieee80211_channel *channel,
+                              enum nl80211_channel_type channel_type)
+{
+       struct ieee80211_ht_info *ht_info;
+       /* Build HT Information */
+       *pos++ = WLAN_EID_HT_INFORMATION;
+       *pos++ = sizeof(struct ieee80211_ht_info);
+       ht_info = (struct ieee80211_ht_info *)pos;
+       ht_info->control_chan =
+                       ieee80211_frequency_to_channel(channel->center_freq);
+       switch (channel_type) {
+       case NL80211_CHAN_HT40MINUS:
+               ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+               break;
+       case NL80211_CHAN_HT40PLUS:
+               ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+               break;
+       case NL80211_CHAN_HT20:
+       default:
+               ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE;
+               break;
+       }
+       if (ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
+               ht_info->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;
+       ht_info->operation_mode = 0x0000;
+       ht_info->stbc_param = 0x0000;
+
+       /* It seems that Basic MCS set and Supported MCS set
+          are identical for the first 10 bytes */
+       memset(&ht_info->basic_set, 0, 16);
+       memcpy(&ht_info->basic_set, &ht_cap->mcs, 10);
+
+       return pos + sizeof(struct ieee80211_ht_info);
+}
+
+enum nl80211_channel_type
+ieee80211_ht_info_to_channel_type(struct ieee80211_ht_info *ht_info)
+{
+       enum nl80211_channel_type channel_type;
+
+       if (!ht_info)
+               return NL80211_CHAN_NO_HT;
+
+       switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
+       case IEEE80211_HT_PARAM_CHA_SEC_NONE:
+               channel_type = NL80211_CHAN_HT20;
+               break;
+       case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
+               channel_type = NL80211_CHAN_HT40PLUS;
+               break;
+       case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
+               channel_type = NL80211_CHAN_HT40MINUS;
+               break;
+       default:
+               channel_type = NL80211_CHAN_NO_HT;
+       }
+
+       return channel_type;
+}
+
 int ieee80211_add_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb)
 {
        struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
index fd52e69..4332711 100644 (file)
@@ -83,7 +83,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
                break;
 #ifdef CONFIG_MAC80211_MESH
        case NL80211_IFTYPE_MESH_POINT:
-               ra = skb->data;
+               qos = true;
                break;
 #endif
        case NL80211_IFTYPE_STATION:
@@ -143,11 +143,15 @@ void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata,
        /* Fill in the QoS header if there is one. */
        if (ieee80211_is_data_qos(hdr->frame_control)) {
                u8 *p = ieee80211_get_qos_ctl(hdr);
-               u8 ack_policy = 0, tid;
+               u8 ack_policy, tid;
 
                tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
 
-               if (unlikely(sdata->local->wifi_wme_noack_test))
+               /* preserve EOSP bit */
+               ack_policy = *p & IEEE80211_QOS_CTL_EOSP;
+
+               if (unlikely(sdata->local->wifi_wme_noack_test) ||
+                   is_multicast_ether_addr(hdr->addr1))
                        ack_policy |= IEEE80211_QOS_CTL_ACK_POLICY_NOACK;
                /* qos header is 2 bytes */
                *p++ = ack_policy | tid;
index 6c53b6d..3dd5a89 100644 (file)
@@ -103,7 +103,6 @@ static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie,
        u8 *pos;
        u32 flags = channel->flags;
        u16 cap = sband->ht_cap.cap;
-       __le16 tmp;
 
        if (!sband->ht_cap.ht_supported)
                return;
@@ -154,34 +153,8 @@ static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie,
        }
 
        /* reserve and fill IE */
-
        pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);
-       *pos++ = WLAN_EID_HT_CAPABILITY;
-       *pos++ = sizeof(struct ieee80211_ht_cap);
-       memset(pos, 0, sizeof(struct ieee80211_ht_cap));
-
-       /* capability flags */
-       tmp = cpu_to_le16(cap);
-       memcpy(pos, &tmp, sizeof(u16));
-       pos += sizeof(u16);
-
-       /* AMPDU parameters */
-       *pos++ = sband->ht_cap.ampdu_factor |
-                (sband->ht_cap.ampdu_density <<
-                       IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
-
-       /* MCS set */
-       memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
-       pos += sizeof(sband->ht_cap.mcs);
-
-       /* extended capabilities */
-       pos += sizeof(__le16);
-
-       /* BF capabilities */
-       pos += sizeof(__le32);
-
-       /* antenna selection */
-       pos += sizeof(u8);
+       ieee80211_ie_build_ht_cap(pos, sband, cap);
 }
 
 static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
@@ -969,10 +942,9 @@ static void ieee80211_work_work(struct work_struct *work)
                }
 
                if (!started && !local->tmp_channel) {
-                       bool on_oper_chan;
-                       bool tmp_chan_changed = false;
-                       bool on_oper_chan2;
+                       bool on_oper_chan, on_oper_chan2;
                        enum nl80211_channel_type wk_ct;
+
                        on_oper_chan = ieee80211_cfg_on_oper_channel(local);
 
                        /* Work with existing channel type if possible. */
@@ -981,11 +953,6 @@ static void ieee80211_work_work(struct work_struct *work)
                                wk_ct = ieee80211_calc_ct(wk->chan_type,
                                                local->hw.conf.channel_type);
 
-                       if (local->tmp_channel)
-                               if ((local->tmp_channel != wk->chan) ||
-                                   (local->tmp_channel_type != wk_ct))
-                                       tmp_chan_changed = true;
-
                        local->tmp_channel = wk->chan;
                        local->tmp_channel_type = wk_ct;
                        /*
@@ -1008,12 +975,7 @@ static void ieee80211_work_work(struct work_struct *work)
                                                                    true,
                                                                    false);
                                }
-                       } else if (tmp_chan_changed)
-                               /* Still off-channel, but on some other
-                                * channel, so update hardware.
-                                * PS should already be off-channel.
-                                */
-                               ieee80211_hw_config(local, 0);
+                       }
 
                        started = true;
                        wk->timeout = jiffies;
index f614ce7..106e15a 100644 (file)
@@ -390,7 +390,8 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
        u8 scratch[6 * AES_BLOCK_SIZE];
 
        if (info->control.hw_key &&
-           !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
+           !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) &&
+           !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) {
                /*
                 * hwaccel has no need for preallocated room for CCMP
                 * header or MIC fields
@@ -412,6 +413,12 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
 
        pos = skb_push(skb, CCMP_HDR_LEN);
        memmove(pos, pos + CCMP_HDR_LEN, hdrlen);
+
+       /* the HW only needs room for the IV, but not the actual IV */
+       if (info->control.hw_key &&
+           (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE))
+               return 0;
+
        hdr = (struct ieee80211_hdr *) pos;
        pos += hdrlen;
 
index afca6c7..4aa0f4b 100644 (file)
@@ -54,6 +54,12 @@ EXPORT_SYMBOL_GPL(nf_unregister_afinfo);
 
 struct list_head nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS] __read_mostly;
 EXPORT_SYMBOL(nf_hooks);
+
+#if defined(CONFIG_JUMP_LABEL)
+struct jump_label_key nf_hooks_needed[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
+EXPORT_SYMBOL(nf_hooks_needed);
+#endif
+
 static DEFINE_MUTEX(nf_hook_mutex);
 
 int nf_register_hook(struct nf_hook_ops *reg)
@@ -70,6 +76,9 @@ int nf_register_hook(struct nf_hook_ops *reg)
        }
        list_add_rcu(&reg->list, elem->list.prev);
        mutex_unlock(&nf_hook_mutex);
+#if defined(CONFIG_JUMP_LABEL)
+       jump_label_inc(&nf_hooks_needed[reg->pf][reg->hooknum]);
+#endif
        return 0;
 }
 EXPORT_SYMBOL(nf_register_hook);
@@ -79,7 +88,9 @@ void nf_unregister_hook(struct nf_hook_ops *reg)
        mutex_lock(&nf_hook_mutex);
        list_del_rcu(&reg->list);
        mutex_unlock(&nf_hook_mutex);
-
+#if defined(CONFIG_JUMP_LABEL)
+       jump_label_dec(&nf_hooks_needed[reg->pf][reg->hooknum]);
+#endif
        synchronize_net();
 }
 EXPORT_SYMBOL(nf_unregister_hook);
index f2d576e..4015fca 100644 (file)
@@ -241,7 +241,7 @@ hash_ip6_data_isnull(const struct hash_ip6_elem *elem)
 static inline void
 hash_ip6_data_copy(struct hash_ip6_elem *dst, const struct hash_ip6_elem *src)
 {
-       ipv6_addr_copy(&dst->ip.in6, &src->ip.in6);
+       dst->ip.in6 = src->ip.in6;
 }
 
 static inline void
index 60d0165..2898819 100644 (file)
@@ -267,7 +267,7 @@ static inline void
 hash_net6_data_copy(struct hash_net6_elem *dst,
                    const struct hash_net6_elem *src)
 {
-       ipv6_addr_copy(&dst->ip.in6, &src->ip.in6);
+       dst->ip.in6 = src->ip.in6;
        dst->cidr = src->cidr;
 }
 
index 093cc32..611c335 100644 (file)
@@ -983,7 +983,7 @@ static int ip_vs_out_icmp_v6(struct sk_buff *skb, int *related,
        if (!cp)
                return NF_ACCEPT;
 
-       ipv6_addr_copy(&snet.in6, &iph->saddr);
+       snet.in6 = iph->saddr;
        return handle_response_icmp(AF_INET6, skb, &snet, cih->nexthdr, cp,
                                    pp, offset, sizeof(struct ipv6hdr));
 }
index 3cdd479..bcf5563 100644 (file)
@@ -603,9 +603,9 @@ sloop:
 #ifdef CONFIG_IP_VS_IPV6
        if (cp->af == AF_INET6) {
                p += sizeof(struct ip_vs_sync_v6);
-               ipv6_addr_copy(&s->v6.caddr, &cp->caddr.in6);
-               ipv6_addr_copy(&s->v6.vaddr, &cp->vaddr.in6);
-               ipv6_addr_copy(&s->v6.daddr, &cp->daddr.in6);
+               s->v6.caddr = cp->caddr.in6;
+               s->v6.vaddr = cp->vaddr.in6;
+               s->v6.daddr = cp->daddr.in6;
        } else
 #endif
        {
index aa2d720..38a576d 100644 (file)
@@ -235,7 +235,7 @@ __ip_vs_route_output_v6(struct net *net, struct in6_addr *daddr,
                        goto out_err;
                }
        }
-       ipv6_addr_copy(ret_saddr, &fl6.saddr);
+       *ret_saddr = fl6.saddr;
        return dst;
 
 out_err:
@@ -279,7 +279,7 @@ __ip_vs_get_out_rt_v6(struct sk_buff *skb, struct ip_vs_dest *dest,
                                  atomic_read(&rt->dst.__refcnt));
                }
                if (ret_saddr)
-                       ipv6_addr_copy(ret_saddr, &dest->dst_saddr.in6);
+                       *ret_saddr = dest->dst_saddr.in6;
                spin_unlock(&dest->dst_lock);
        } else {
                dst = __ip_vs_route_output_v6(net, daddr, ret_saddr, do_xfrm);
@@ -705,7 +705,7 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
        /* mangle the packet */
        if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp))
                goto tx_error;
-       ipv6_addr_copy(&ipv6_hdr(skb)->daddr, &cp->daddr.in6);
+       ipv6_hdr(skb)->daddr = cp->daddr.in6;
 
        if (!local || !skb->dev) {
                /* drop the old route when skb is not shared */
@@ -967,8 +967,8 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
        be16_add_cpu(&iph->payload_len, sizeof(*old_iph));
        iph->priority           =       old_iph->priority;
        memset(&iph->flow_lbl, 0, sizeof(iph->flow_lbl));
-       ipv6_addr_copy(&iph->daddr, &cp->daddr.in6);
-       ipv6_addr_copy(&iph->saddr, &saddr);
+       iph->daddr = cp->daddr.in6;
+       iph->saddr = saddr;
        iph->hop_limit          =       old_iph->hop_limit;
 
        /* Another hack: avoid icmp_send in ip_fragment */
index f03c2d4..f9368f3 100644 (file)
@@ -750,10 +750,10 @@ static int callforward_do_filter(const union nf_inet_addr *src,
                struct rt6_info *rt1, *rt2;
 
                memset(&fl1, 0, sizeof(fl1));
-               ipv6_addr_copy(&fl1.daddr, &src->in6);
+               fl1.daddr = src->in6;
 
                memset(&fl2, 0, sizeof(fl2));
-               ipv6_addr_copy(&fl2.daddr, &dst->in6);
+               fl2.daddr = dst->in6;
                if (!afinfo->route(&init_net, (struct dst_entry **)&rt1,
                                   flowi6_to_flowi(&fl1), false)) {
                        if (!afinfo->route(&init_net, (struct dst_entry **)&rt2,
index 9e63b43..3ecade3 100644 (file)
@@ -161,7 +161,7 @@ static u_int32_t tcpmss_reverse_mtu(const struct sk_buff *skb,
                struct flowi6 *fl6 = &fl.u.ip6;
 
                memset(fl6, 0, sizeof(*fl6));
-               ipv6_addr_copy(&fl6->daddr, &ipv6_hdr(skb)->saddr);
+               fl6->daddr = ipv6_hdr(skb)->saddr;
        }
        rcu_read_lock();
        ai = nf_get_afinfo(family);
index b77d383..c047de2 100644 (file)
@@ -42,7 +42,7 @@ static u32 match_lookup_rt6(struct net *net, const struct net_device *dev,
        int route_err;
 
        memset(&flow, 0, sizeof(flow));
-       ipv6_addr_copy(&flow.daddr, addr);
+       flow.daddr = *addr;
        if (dev)
                flow.flowi6_oif = dev->ifindex;
 
index 9c24de1..8ed67dc 100644 (file)
@@ -155,12 +155,12 @@ int netlbl_cfg_unlbl_map_add(const char *domain,
                        if (map6 == NULL)
                                goto cfg_unlbl_map_add_failure;
                        map6->type = NETLBL_NLTYPE_UNLABELED;
-                       ipv6_addr_copy(&map6->list.addr, addr6);
+                       map6->list.addr = *addr6;
                        map6->list.addr.s6_addr32[0] &= mask6->s6_addr32[0];
                        map6->list.addr.s6_addr32[1] &= mask6->s6_addr32[1];
                        map6->list.addr.s6_addr32[2] &= mask6->s6_addr32[2];
                        map6->list.addr.s6_addr32[3] &= mask6->s6_addr32[3];
-                       ipv6_addr_copy(&map6->list.mask, mask6);
+                       map6->list.mask = *mask6;
                        map6->list.valid = 1;
                        ret_val = netlbl_af4list_add(&map4->list,
                                                     &addrmap->list4);
index bfa5558..9879300 100644 (file)
@@ -216,12 +216,12 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
                        ret_val = -ENOMEM;
                        goto add_failure;
                }
-               ipv6_addr_copy(&map->list.addr, addr);
+               map->list.addr = *addr;
                map->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
                map->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
                map->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
                map->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
-               ipv6_addr_copy(&map->list.mask, mask);
+               map->list.mask = *mask;
                map->list.valid = 1;
                map->type = entry->type;
 
index e251c2c..049ccd2 100644 (file)
@@ -300,12 +300,12 @@ static int netlbl_unlhsh_add_addr6(struct netlbl_unlhsh_iface *iface,
        if (entry == NULL)
                return -ENOMEM;
 
-       ipv6_addr_copy(&entry->list.addr, addr);
+       entry->list.addr = *addr;
        entry->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
        entry->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
        entry->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
        entry->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
-       ipv6_addr_copy(&entry->list.mask, mask);
+       entry->list.mask = *mask;
        entry->list.valid = 1;
        entry->secid = secid;
 
index 3925c65..fe5ca89 100644 (file)
@@ -126,7 +126,10 @@ static inline int nci_request(struct nci_dev *ndev,
 
 static void nci_reset_req(struct nci_dev *ndev, unsigned long opt)
 {
-       nci_send_cmd(ndev, NCI_OP_CORE_RESET_CMD, 0, NULL);
+       struct nci_core_reset_cmd cmd;
+
+       cmd.reset_type = NCI_RESET_TYPE_RESET_CONFIG;
+       nci_send_cmd(ndev, NCI_OP_CORE_RESET_CMD, 1, &cmd);
 }
 
 static void nci_init_req(struct nci_dev *ndev, unsigned long opt)
@@ -136,17 +139,11 @@ static void nci_init_req(struct nci_dev *ndev, unsigned long opt)
 
 static void nci_init_complete_req(struct nci_dev *ndev, unsigned long opt)
 {
-       struct nci_core_conn_create_cmd conn_cmd;
        struct nci_rf_disc_map_cmd cmd;
        struct disc_map_config *cfg = cmd.mapping_configs;
        __u8 *num = &cmd.num_mapping_configs;
        int i;
 
-       /* create static rf connection */
-       conn_cmd.target_handle = 0;
-       conn_cmd.num_target_specific_params = 0;
-       nci_send_cmd(ndev, NCI_OP_CORE_CONN_CREATE_CMD, 2, &conn_cmd);
-
        /* set rf mapping configurations */
        *num = 0;
 
@@ -470,7 +467,7 @@ static int nci_data_exchange(struct nfc_dev *nfc_dev, __u32 target_idx,
        ndev->data_exchange_cb = cb;
        ndev->data_exchange_cb_context = cb_context;
 
-       rc = nci_send_data(ndev, ndev->conn_id, skb);
+       rc = nci_send_data(ndev, NCI_STATIC_RF_CONN_ID, skb);
        if (rc)
                clear_bit(NCI_DATA_EXCHANGE, &ndev->flags);
 
@@ -726,7 +723,10 @@ static void nci_tx_work(struct work_struct *work)
                if (!skb)
                        return;
 
-               atomic_dec(&ndev->credits_cnt);
+               /* Check if data flow control is used */
+               if (atomic_read(&ndev->credits_cnt) !=
+                               NCI_DATA_FLOW_CONTROL_NOT_USED)
+                       atomic_dec(&ndev->credits_cnt);
 
                nfc_dbg("NCI TX: MT=data, PBF=%d, conn_id=%d, plen=%d",
                                nci_pbf(skb->data),
index e5ed90f..511fb96 100644 (file)
@@ -95,7 +95,8 @@ static int nci_queue_tx_data_frags(struct nci_dev *ndev,
        __skb_queue_head_init(&frags_q);
 
        while (total_len) {
-               frag_len = min_t(int, total_len, ndev->max_pkt_payload_size);
+               frag_len =
+                       min_t(int, total_len, ndev->max_data_pkt_payload_size);
 
                skb_frag = nci_skb_alloc(ndev,
                                        (NCI_DATA_HDR_SIZE + frag_len),
@@ -151,7 +152,7 @@ int nci_send_data(struct nci_dev *ndev, __u8 conn_id, struct sk_buff *skb)
        nfc_dbg("entry, conn_id 0x%x, plen %d", conn_id, skb->len);
 
        /* check if the packet need to be fragmented */
-       if (skb->len <= ndev->max_pkt_payload_size) {
+       if (skb->len <= ndev->max_data_pkt_payload_size) {
                /* no need to fragment packet */
                nci_push_data_hdr(ndev, conn_id, skb, NCI_PBF_LAST);
 
index b19dc2f..e99adcf 100644 (file)
@@ -42,12 +42,9 @@ int nci_to_errno(__u8 code)
        case NCI_STATUS_REJECTED:
                return -EBUSY;
 
-       case NCI_STATUS_MESSAGE_CORRUPTED:
+       case NCI_STATUS_RF_FRAME_CORRUPTED:
                return -EBADMSG;
 
-       case NCI_STATUS_BUFFER_FULL:
-               return -ENOBUFS;
-
        case NCI_STATUS_NOT_INITIALIZED:
                return -EHOSTDOWN;
 
@@ -80,9 +77,6 @@ int nci_to_errno(__u8 code)
        case NCI_STATUS_NFCEE_TIMEOUT_ERROR:
                return -ETIMEDOUT;
 
-       case NCI_STATUS_RF_LINK_LOSS_ERROR:
-               return -ENOLINK;
-
        case NCI_STATUS_MAX_ACTIVE_NFCEE_INTERFACES_REACHED:
                return -EDQUOT;
 
index 96633f5..c1bf541 100644 (file)
@@ -54,7 +54,7 @@ static void nci_core_conn_credits_ntf_packet(struct nci_dev *ndev,
                        ntf->conn_entries[i].conn_id,
                        ntf->conn_entries[i].credits);
 
-               if (ntf->conn_entries[i].conn_id == ndev->conn_id) {
+               if (ntf->conn_entries[i].conn_id == NCI_STATIC_RF_CONN_ID) {
                        /* found static rf connection */
                        atomic_add(ntf->conn_entries[i].credits,
                                &ndev->credits_cnt);
@@ -66,22 +66,12 @@ static void nci_core_conn_credits_ntf_packet(struct nci_dev *ndev,
                queue_work(ndev->tx_wq, &ndev->tx_work);
 }
 
-static void nci_rf_field_info_ntf_packet(struct nci_dev *ndev,
-                                       struct sk_buff *skb)
-{
-       struct nci_rf_field_info_ntf *ntf = (void *) skb->data;
-
-       nfc_dbg("entry, rf_field_status %d", ntf->rf_field_status);
-}
-
-static int nci_rf_activate_nfca_passive_poll(struct nci_dev *ndev,
-                       struct nci_rf_activate_ntf *ntf, __u8 *data)
+static __u8 *nci_extract_rf_params_nfca_passive_poll(struct nci_dev *ndev,
+                       struct nci_rf_intf_activated_ntf *ntf, __u8 *data)
 {
        struct rf_tech_specific_params_nfca_poll *nfca_poll;
-       struct activation_params_nfca_poll_iso_dep *nfca_poll_iso_dep;
 
        nfca_poll = &ntf->rf_tech_specific_params.nfca_poll;
-       nfca_poll_iso_dep = &ntf->activation_params.nfca_poll_iso_dep;
 
        nfca_poll->sens_res = __le16_to_cpu(*((__u16 *)data));
        data += 2;
@@ -100,32 +90,32 @@ static int nci_rf_activate_nfca_passive_poll(struct nci_dev *ndev,
        if (nfca_poll->sel_res_len != 0)
                nfca_poll->sel_res = *data++;
 
-       ntf->rf_interface_type = *data++;
-       ntf->activation_params_len = *data++;
-
-       nfc_dbg("sel_res_len %d, sel_res 0x%x, rf_interface_type %d, activation_params_len %d",
+       nfc_dbg("sel_res_len %d, sel_res 0x%x",
                nfca_poll->sel_res_len,
-               nfca_poll->sel_res,
-               ntf->rf_interface_type,
-               ntf->activation_params_len);
-
-       switch (ntf->rf_interface_type) {
-       case NCI_RF_INTERFACE_ISO_DEP:
-               nfca_poll_iso_dep->rats_res_len = *data++;
-               if (nfca_poll_iso_dep->rats_res_len > 0) {
-                       memcpy(nfca_poll_iso_dep->rats_res,
+               nfca_poll->sel_res);
+
+       return data;
+}
+
+static int nci_extract_activation_params_iso_dep(struct nci_dev *ndev,
+                       struct nci_rf_intf_activated_ntf *ntf, __u8 *data)
+{
+       struct activation_params_nfca_poll_iso_dep *nfca_poll;
+
+       switch (ntf->activation_rf_tech_and_mode) {
+       case NCI_NFC_A_PASSIVE_POLL_MODE:
+               nfca_poll = &ntf->activation_params.nfca_poll_iso_dep;
+               nfca_poll->rats_res_len = *data++;
+               if (nfca_poll->rats_res_len > 0) {
+                       memcpy(nfca_poll->rats_res,
                                data,
-                               nfca_poll_iso_dep->rats_res_len);
+                               nfca_poll->rats_res_len);
                }
                break;
 
-       case NCI_RF_INTERFACE_FRAME:
-               /* no activation params */
-               break;
-
        default:
-               nfc_err("unsupported rf_interface_type 0x%x",
-                       ntf->rf_interface_type);
+               nfc_err("unsupported activation_rf_tech_and_mode 0x%x",
+                       ntf->activation_rf_tech_and_mode);
                return -EPROTO;
        }
 
@@ -133,7 +123,7 @@ static int nci_rf_activate_nfca_passive_poll(struct nci_dev *ndev,
 }
 
 static void nci_target_found(struct nci_dev *ndev,
-                               struct nci_rf_activate_ntf *ntf)
+                               struct nci_rf_intf_activated_ntf *ntf)
 {
        struct nfc_target nfc_tgt;
 
@@ -141,6 +131,8 @@ static void nci_target_found(struct nci_dev *ndev,
                nfc_tgt.supported_protocols = NFC_PROTO_MIFARE_MASK;
        else if (ntf->rf_protocol == NCI_RF_PROTOCOL_ISO_DEP)   /* 4A */
                nfc_tgt.supported_protocols = NFC_PROTO_ISO14443_MASK;
+       else
+               nfc_tgt.supported_protocols = 0;
 
        nfc_tgt.sens_res = ntf->rf_tech_specific_params.nfca_poll.sens_res;
        nfc_tgt.sel_res = ntf->rf_tech_specific_params.nfca_poll.sel_res;
@@ -158,49 +150,86 @@ static void nci_target_found(struct nci_dev *ndev,
        nfc_targets_found(ndev->nfc_dev, &nfc_tgt, 1);
 }
 
-static void nci_rf_activate_ntf_packet(struct nci_dev *ndev,
-                                       struct sk_buff *skb)
+static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
+                                               struct sk_buff *skb)
 {
-       struct nci_rf_activate_ntf ntf;
+       struct nci_rf_intf_activated_ntf ntf;
        __u8 *data = skb->data;
-       int rc = -1;
+       int err = 0;
 
        clear_bit(NCI_DISCOVERY, &ndev->flags);
        set_bit(NCI_POLL_ACTIVE, &ndev->flags);
 
-       ntf.target_handle = *data++;
+       ntf.rf_discovery_id = *data++;
+       ntf.rf_interface_type = *data++;
        ntf.rf_protocol = *data++;
-       ntf.rf_tech_and_mode = *data++;
+       ntf.activation_rf_tech_and_mode = *data++;
        ntf.rf_tech_specific_params_len = *data++;
 
-       nfc_dbg("target_handle %d, rf_protocol 0x%x, rf_tech_and_mode 0x%x, rf_tech_specific_params_len %d",
-               ntf.target_handle,
-               ntf.rf_protocol,
-               ntf.rf_tech_and_mode,
+       nfc_dbg("rf_discovery_id %d", ntf.rf_discovery_id);
+       nfc_dbg("rf_interface_type 0x%x", ntf.rf_interface_type);
+       nfc_dbg("rf_protocol 0x%x", ntf.rf_protocol);
+       nfc_dbg("activation_rf_tech_and_mode 0x%x",
+               ntf.activation_rf_tech_and_mode);
+       nfc_dbg("rf_tech_specific_params_len %d",
                ntf.rf_tech_specific_params_len);
 
-       switch (ntf.rf_tech_and_mode) {
-       case NCI_NFC_A_PASSIVE_POLL_MODE:
-               rc = nci_rf_activate_nfca_passive_poll(ndev, &ntf,
-                       data);
-               break;
+       if (ntf.rf_tech_specific_params_len > 0) {
+               switch (ntf.activation_rf_tech_and_mode) {
+               case NCI_NFC_A_PASSIVE_POLL_MODE:
+                       data = nci_extract_rf_params_nfca_passive_poll(ndev,
+                               &ntf, data);
+                       break;
+
+               default:
+                       nfc_err("unsupported activation_rf_tech_and_mode 0x%x",
+                               ntf.activation_rf_tech_and_mode);
+                       return;
+               }
+       }
 
-       default:
-               nfc_err("unsupported rf_tech_and_mode 0x%x",
-                       ntf.rf_tech_and_mode);
-               return;
+       ntf.data_exch_rf_tech_and_mode = *data++;
+       ntf.data_exch_tx_bit_rate = *data++;
+       ntf.data_exch_rx_bit_rate = *data++;
+       ntf.activation_params_len = *data++;
+
+       nfc_dbg("data_exch_rf_tech_and_mode 0x%x",
+               ntf.data_exch_rf_tech_and_mode);
+       nfc_dbg("data_exch_tx_bit_rate 0x%x",
+               ntf.data_exch_tx_bit_rate);
+       nfc_dbg("data_exch_rx_bit_rate 0x%x",
+               ntf.data_exch_rx_bit_rate);
+       nfc_dbg("activation_params_len %d",
+               ntf.activation_params_len);
+
+       if (ntf.activation_params_len > 0) {
+               switch (ntf.rf_interface_type) {
+               case NCI_RF_INTERFACE_ISO_DEP:
+                       err = nci_extract_activation_params_iso_dep(ndev,
+                               &ntf, data);
+                       break;
+
+               case NCI_RF_INTERFACE_FRAME:
+                       /* no activation params */
+                       break;
+
+               default:
+                       nfc_err("unsupported rf_interface_type 0x%x",
+                               ntf.rf_interface_type);
+                       return;
+               }
        }
 
-       if (!rc)
+       if (!err)
                nci_target_found(ndev, &ntf);
 }
 
 static void nci_rf_deactivate_ntf_packet(struct nci_dev *ndev,
                                        struct sk_buff *skb)
 {
-       __u8 type = skb->data[0];
+       struct nci_rf_deactivate_ntf *ntf = (void *) skb->data;
 
-       nfc_dbg("entry, type 0x%x", type);
+       nfc_dbg("entry, type 0x%x, reason 0x%x", ntf->type, ntf->reason);
 
        clear_bit(NCI_POLL_ACTIVE, &ndev->flags);
        ndev->target_active_prot = 0;
@@ -214,6 +243,9 @@ static void nci_rf_deactivate_ntf_packet(struct nci_dev *ndev,
                ndev->rx_data_reassembly = 0;
        }
 
+       /* set the available credits to initial value */
+       atomic_set(&ndev->credits_cnt, ndev->initial_num_credits);
+
        /* complete the data exchange transaction, if exists */
        if (test_bit(NCI_DATA_EXCHANGE, &ndev->flags))
                nci_data_exchange_complete(ndev, NULL, -EIO);
@@ -237,12 +269,8 @@ void nci_ntf_packet(struct nci_dev *ndev, struct sk_buff *skb)
                nci_core_conn_credits_ntf_packet(ndev, skb);
                break;
 
-       case NCI_OP_RF_FIELD_INFO_NTF:
-               nci_rf_field_info_ntf_packet(ndev, skb);
-               break;
-
-       case NCI_OP_RF_ACTIVATE_NTF:
-               nci_rf_activate_ntf_packet(ndev, skb);
+       case NCI_OP_RF_INTF_ACTIVATED_NTF:
+               nci_rf_intf_activated_ntf_packet(ndev, skb);
                break;
 
        case NCI_OP_RF_DEACTIVATE_NTF:
index 0403d4c..0591f5a 100644 (file)
@@ -42,10 +42,11 @@ static void nci_core_reset_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
 
        nfc_dbg("entry, status 0x%x", rsp->status);
 
-       if (rsp->status == NCI_STATUS_OK)
+       if (rsp->status == NCI_STATUS_OK) {
                ndev->nci_ver = rsp->nci_ver;
-
-       nfc_dbg("nci_ver 0x%x", ndev->nci_ver);
+               nfc_dbg("nci_ver 0x%x, config_status 0x%x",
+                       rsp->nci_ver, rsp->config_status);
+       }
 
        nci_req_complete(ndev, rsp->status);
 }
@@ -58,13 +59,13 @@ static void nci_core_init_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
        nfc_dbg("entry, status 0x%x", rsp_1->status);
 
        if (rsp_1->status != NCI_STATUS_OK)
-               return;
+               goto exit;
 
        ndev->nfcc_features = __le32_to_cpu(rsp_1->nfcc_features);
        ndev->num_supported_rf_interfaces = rsp_1->num_supported_rf_interfaces;
 
        if (ndev->num_supported_rf_interfaces >
-               NCI_MAX_SUPPORTED_RF_INTERFACES) {
+                       NCI_MAX_SUPPORTED_RF_INTERFACES) {
                ndev->num_supported_rf_interfaces =
                        NCI_MAX_SUPPORTED_RF_INTERFACES;
        }
@@ -73,20 +74,26 @@ static void nci_core_init_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
                rsp_1->supported_rf_interfaces,
                ndev->num_supported_rf_interfaces);
 
-       rsp_2 = (void *) (skb->data + 6 + ndev->num_supported_rf_interfaces);
+       rsp_2 = (void *) (skb->data + 6 + rsp_1->num_supported_rf_interfaces);
 
        ndev->max_logical_connections =
                rsp_2->max_logical_connections;
        ndev->max_routing_table_size =
                __le16_to_cpu(rsp_2->max_routing_table_size);
-       ndev->max_control_packet_payload_length =
-               rsp_2->max_control_packet_payload_length;
-       ndev->rf_sending_buffer_size =
-               __le16_to_cpu(rsp_2->rf_sending_buffer_size);
-       ndev->rf_receiving_buffer_size =
-               __le16_to_cpu(rsp_2->rf_receiving_buffer_size);
-       ndev->manufacturer_id =
-               __le16_to_cpu(rsp_2->manufacturer_id);
+       ndev->max_ctrl_pkt_payload_len =
+               rsp_2->max_ctrl_pkt_payload_len;
+       ndev->max_size_for_large_params =
+               __le16_to_cpu(rsp_2->max_size_for_large_params);
+       ndev->max_data_pkt_payload_size =
+               rsp_2->max_data_pkt_payload_size;
+       ndev->initial_num_credits =
+               rsp_2->initial_num_credits;
+       ndev->manufact_id =
+               rsp_2->manufact_id;
+       ndev->manufact_specific_info =
+               __le32_to_cpu(rsp_2->manufact_specific_info);
+
+       atomic_set(&ndev->credits_cnt, ndev->initial_num_credits);
 
        nfc_dbg("nfcc_features 0x%x",
                ndev->nfcc_features);
@@ -104,39 +111,23 @@ static void nci_core_init_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
                ndev->max_logical_connections);
        nfc_dbg("max_routing_table_size %d",
                ndev->max_routing_table_size);
-       nfc_dbg("max_control_packet_payload_length %d",
-               ndev->max_control_packet_payload_length);
-       nfc_dbg("rf_sending_buffer_size %d",
-               ndev->rf_sending_buffer_size);
-       nfc_dbg("rf_receiving_buffer_size %d",
-               ndev->rf_receiving_buffer_size);
-       nfc_dbg("manufacturer_id 0x%x",
-               ndev->manufacturer_id);
-
+       nfc_dbg("max_ctrl_pkt_payload_len %d",
+               ndev->max_ctrl_pkt_payload_len);
+       nfc_dbg("max_size_for_large_params %d",
+               ndev->max_size_for_large_params);
+       nfc_dbg("max_data_pkt_payload_size %d",
+               ndev->max_data_pkt_payload_size);
+       nfc_dbg("initial_num_credits %d",
+               ndev->initial_num_credits);
+       nfc_dbg("manufact_id 0x%x",
+               ndev->manufact_id);
+       nfc_dbg("manufact_specific_info 0x%x",
+               ndev->manufact_specific_info);
+
+exit:
        nci_req_complete(ndev, rsp_1->status);
 }
 
-static void nci_core_conn_create_rsp_packet(struct nci_dev *ndev,
-                                               struct sk_buff *skb)
-{
-       struct nci_core_conn_create_rsp *rsp = (void *) skb->data;
-
-       nfc_dbg("entry, status 0x%x", rsp->status);
-
-       if (rsp->status != NCI_STATUS_OK)
-               return;
-
-       ndev->max_pkt_payload_size = rsp->max_pkt_payload_size;
-       ndev->initial_num_credits = rsp->initial_num_credits;
-       ndev->conn_id = rsp->conn_id;
-
-       atomic_set(&ndev->credits_cnt, ndev->initial_num_credits);
-
-       nfc_dbg("max_pkt_payload_size %d", ndev->max_pkt_payload_size);
-       nfc_dbg("initial_num_credits %d", ndev->initial_num_credits);
-       nfc_dbg("conn_id %d", ndev->conn_id);
-}
-
 static void nci_rf_disc_map_rsp_packet(struct nci_dev *ndev,
                                        struct sk_buff *skb)
 {
@@ -196,10 +187,6 @@ void nci_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
                nci_core_init_rsp_packet(ndev, skb);
                break;
 
-       case NCI_OP_CORE_CONN_CREATE_RSP:
-               nci_core_conn_create_rsp_packet(ndev, skb);
-               break;
-
        case NCI_OP_RF_DISCOVER_MAP_RSP:
                nci_rf_disc_map_rsp_packet(ndev, skb);
                break;
index 82a6f34..0da505c 100644 (file)
@@ -1499,10 +1499,11 @@ retry:
 
        if (!skb) {
                size_t reserved = LL_RESERVED_SPACE(dev);
+               int tlen = dev->needed_tailroom;
                unsigned int hhlen = dev->header_ops ? dev->hard_header_len : 0;
 
                rcu_read_unlock();
-               skb = sock_wmalloc(sk, len + reserved, 0, GFP_KERNEL);
+               skb = sock_wmalloc(sk, len + reserved + tlen, 0, GFP_KERNEL);
                if (skb == NULL)
                        return -ENOBUFS;
                /* FIXME: Save some space for broken drivers that write a hard
@@ -1944,7 +1945,7 @@ static void tpacket_destruct_skb(struct sk_buff *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)
+               __be16 proto, unsigned char *addr, int hlen)
 {
        union {
                struct tpacket_hdr *h1;
@@ -1978,7 +1979,7 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
                return -EMSGSIZE;
        }
 
-       skb_reserve(skb, LL_RESERVED_SPACE(dev));
+       skb_reserve(skb, hlen);
        skb_reset_network_header(skb);
 
        data = ph.raw + po->tp_hdrlen - sizeof(struct sockaddr_ll);
@@ -2053,6 +2054,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
        unsigned char *addr;
        int len_sum = 0;
        int status = 0;
+       int hlen, tlen;
 
        mutex_lock(&po->pg_vec_lock);
 
@@ -2101,16 +2103,17 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
                }
 
                status = TP_STATUS_SEND_REQUEST;
+               hlen = LL_RESERVED_SPACE(dev);
+               tlen = dev->needed_tailroom;
                skb = sock_alloc_send_skb(&po->sk,
-                               LL_ALLOCATED_SPACE(dev)
-                               + sizeof(struct sockaddr_ll),
+                               hlen + tlen + sizeof(struct sockaddr_ll),
                                0, &err);
 
                if (unlikely(skb == NULL))
                        goto out_status;
 
                tp_len = tpacket_fill_skb(po, skb, ph, dev, size_max, proto,
-                               addr);
+                               addr, hlen);
 
                if (unlikely(tp_len < 0)) {
                        if (po->tp_loss) {
@@ -2207,6 +2210,7 @@ static int packet_snd(struct socket *sock,
        int vnet_hdr_len;
        struct packet_sock *po = pkt_sk(sk);
        unsigned short gso_type = 0;
+       int hlen, tlen;
 
        /*
         *      Get and verify the address.
@@ -2291,8 +2295,9 @@ static int packet_snd(struct socket *sock,
                goto out_unlock;
 
        err = -ENOBUFS;
-       skb = packet_alloc_skb(sk, LL_ALLOCATED_SPACE(dev),
-                              LL_RESERVED_SPACE(dev), len, vnet_hdr.hdr_len,
+       hlen = LL_RESERVED_SPACE(dev);
+       tlen = dev->needed_tailroom;
+       skb = packet_alloc_skb(sk, hlen + tlen, hlen, len, vnet_hdr.hdr_len,
                               msg->msg_flags & MSG_DONTWAIT, &err);
        if (skb == NULL)
                goto out_unlock;
index 2ba6e9f..9f60008 100644 (file)
@@ -534,6 +534,29 @@ static int pep_connresp_rcv(struct sock *sk, struct sk_buff *skb)
        return pipe_handler_send_created_ind(sk);
 }
 
+static int pep_enableresp_rcv(struct sock *sk, struct sk_buff *skb)
+{
+       struct pnpipehdr *hdr = pnp_hdr(skb);
+
+       if (hdr->error_code != PN_PIPE_NO_ERROR)
+               return -ECONNREFUSED;
+
+       return pep_indicate(sk, PNS_PIPE_ENABLED_IND, 0 /* sub-blocks */,
+               NULL, 0, GFP_ATOMIC);
+
+}
+
+static void pipe_start_flow_control(struct sock *sk)
+{
+       struct pep_sock *pn = pep_sk(sk);
+
+       if (!pn_flow_safe(pn->tx_fc)) {
+               atomic_set(&pn->tx_credits, 1);
+               sk->sk_write_space(sk);
+       }
+       pipe_grant_credits(sk, GFP_ATOMIC);
+}
+
 /* Queue an skb to an actively connected sock.
  * Socket lock must be held. */
 static int pipe_handler_do_rcv(struct sock *sk, struct sk_buff *skb)
@@ -579,13 +602,25 @@ static int pipe_handler_do_rcv(struct sock *sk, struct sk_buff *skb)
                        sk->sk_state = TCP_CLOSE_WAIT;
                        break;
                }
+               if (pn->init_enable == PN_PIPE_DISABLE)
+                       sk->sk_state = TCP_SYN_RECV;
+               else {
+                       sk->sk_state = TCP_ESTABLISHED;
+                       pipe_start_flow_control(sk);
+               }
+               break;
 
-               sk->sk_state = TCP_ESTABLISHED;
-               if (!pn_flow_safe(pn->tx_fc)) {
-                       atomic_set(&pn->tx_credits, 1);
-                       sk->sk_write_space(sk);
+       case PNS_PEP_ENABLE_RESP:
+               if (sk->sk_state != TCP_SYN_SENT)
+                       break;
+
+               if (pep_enableresp_rcv(sk, skb)) {
+                       sk->sk_state = TCP_CLOSE_WAIT;
+                       break;
                }
-               pipe_grant_credits(sk, GFP_ATOMIC);
+
+               sk->sk_state = TCP_ESTABLISHED;
+               pipe_start_flow_control(sk);
                break;
 
        case PNS_PEP_DISCONNECT_RESP:
@@ -864,14 +899,32 @@ static int pep_sock_connect(struct sock *sk, struct sockaddr *addr, int len)
        int err;
        u8 data[4] = { 0 /* sub-blocks */, PAD, PAD, PAD };
 
-       pn->pipe_handle = 1; /* anything but INVALID_HANDLE */
+       if (pn->pipe_handle == PN_PIPE_INVALID_HANDLE)
+               pn->pipe_handle = 1; /* anything but INVALID_HANDLE */
+
        err = pipe_handler_request(sk, PNS_PEP_CONNECT_REQ,
-                                       PN_PIPE_ENABLE, data, 4);
+                               pn->init_enable, data, 4);
        if (err) {
                pn->pipe_handle = PN_PIPE_INVALID_HANDLE;
                return err;
        }
+
        sk->sk_state = TCP_SYN_SENT;
+
+       return 0;
+}
+
+static int pep_sock_enable(struct sock *sk, struct sockaddr *addr, int len)
+{
+       int err;
+
+       err = pipe_handler_request(sk, PNS_PEP_ENABLE_REQ, PAD,
+                               NULL, 0);
+       if (err)
+               return err;
+
+       sk->sk_state = TCP_SYN_SENT;
+
        return 0;
 }
 
@@ -879,11 +932,14 @@ static int pep_ioctl(struct sock *sk, int cmd, unsigned long arg)
 {
        struct pep_sock *pn = pep_sk(sk);
        int answ;
+       int ret = -ENOIOCTLCMD;
 
        switch (cmd) {
        case SIOCINQ:
-               if (sk->sk_state == TCP_LISTEN)
-                       return -EINVAL;
+               if (sk->sk_state == TCP_LISTEN) {
+                       ret = -EINVAL;
+                       break;
+               }
 
                lock_sock(sk);
                if (sock_flag(sk, SOCK_URGINLINE) &&
@@ -894,10 +950,22 @@ static int pep_ioctl(struct sock *sk, int cmd, unsigned long arg)
                else
                        answ = 0;
                release_sock(sk);
-               return put_user(answ, (int __user *)arg);
+               ret = put_user(answ, (int __user *)arg);
+               break;
+
+       case SIOCPNENABLEPIPE:
+               lock_sock(sk);
+               if (sk->sk_state == TCP_SYN_SENT)
+                       ret =  -EBUSY;
+               else if (sk->sk_state == TCP_ESTABLISHED)
+                       ret = -EISCONN;
+               else
+                       ret = pep_sock_enable(sk, NULL, 0);
+               release_sock(sk);
+               break;
        }
 
-       return -ENOIOCTLCMD;
+       return ret;
 }
 
 static int pep_init(struct sock *sk)
@@ -960,6 +1028,18 @@ static int pep_setsockopt(struct sock *sk, int level, int optname,
                }
                goto out_norel;
 
+       case PNPIPE_HANDLE:
+               if ((sk->sk_state == TCP_CLOSE) &&
+                       (val >= 0) && (val < PN_PIPE_INVALID_HANDLE))
+                       pn->pipe_handle = val;
+               else
+                       err = -EINVAL;
+               break;
+
+       case PNPIPE_INITSTATE:
+               pn->init_enable = !!val;
+               break;
+
        default:
                err = -ENOPROTOOPT;
        }
@@ -995,6 +1075,10 @@ static int pep_getsockopt(struct sock *sk, int level, int optname,
                        return -EINVAL;
                break;
 
+       case PNPIPE_INITSTATE:
+               val = pn->init_enable;
+               break;
+
        default:
                return -ENOPROTOOPT;
        }
index 4cf6dc7..ec753b3 100644 (file)
@@ -9,7 +9,6 @@ config RDS
 
 config RDS_RDMA
        tristate "RDS over Infiniband and iWARP"
-       select LLIST
        depends on RDS && INFINIBAND && INFINIBAND_ADDR_TRANS
        ---help---
          Allow RDS to use Infiniband and iWARP as a transport.
index 5be1957..354760e 100644 (file)
@@ -644,7 +644,7 @@ static ssize_t rfkill_soft_store(struct device *dev,
        if (!capable(CAP_NET_ADMIN))
                return -EPERM;
 
-       err = strict_strtoul(buf, 0, &state);
+       err = kstrtoul(buf, 0, &state);
        if (err)
                return err;
 
@@ -688,7 +688,7 @@ static ssize_t rfkill_state_store(struct device *dev,
        if (!capable(CAP_NET_ADMIN))
                return -EPERM;
 
-       err = strict_strtoul(buf, 0, &state);
+       err = kstrtoul(buf, 0, &state);
        if (err)
                return err;
 
index 43ea7de..4cba13e 100644 (file)
@@ -306,10 +306,9 @@ static int rxrpc_krb5_decode_tagged_data(struct krb5_tagged_data *td,
        td->data_len = len;
 
        if (len > 0) {
-               td->data = kmalloc(len, GFP_KERNEL);
+               td->data = kmemdup(xdr, len, GFP_KERNEL);
                if (!td->data)
                        return -ENOMEM;
-               memcpy(td->data, xdr, len);
                len = (len + 3) & ~3;
                toklen -= len;
                xdr += len >> 2;
@@ -401,10 +400,9 @@ static int rxrpc_krb5_decode_ticket(u8 **_ticket, u16 *_tktlen,
        _debug("ticket len %u", len);
 
        if (len > 0) {
-               *_ticket = kmalloc(len, GFP_KERNEL);
+               *_ticket = kmemdup(xdr, len, GFP_KERNEL);
                if (!*_ticket)
                        return -ENOMEM;
-               memcpy(*_ticket, xdr, len);
                len = (len + 3) & ~3;
                toklen -= len;
                xdr += len >> 2;
index 3422b25..061bcb7 100644 (file)
@@ -152,15 +152,14 @@ static bool choke_match_flow(struct sk_buff *skb1,
 {
        int off1, off2, poff;
        const u32 *ports1, *ports2;
+       u32 _ports1, _ports2;
        u8 ip_proto;
        __u32 hash1;
 
        if (skb1->protocol != skb2->protocol)
                return false;
 
-       /* Use hash value as quick check
-        * Assumes that __skb_get_rxhash makes IP header and ports linear
-        */
+       /* Use rxhash value as quick check */
        hash1 = skb_get_rxhash(skb1);
        if (!hash1 || hash1 != skb_get_rxhash(skb2))
                return false;
@@ -172,10 +171,12 @@ static bool choke_match_flow(struct sk_buff *skb1,
        switch (skb1->protocol) {
        case __constant_htons(ETH_P_IP): {
                const struct iphdr *ip1, *ip2;
+               struct iphdr _ip1, _ip2;
 
-               ip1 = (const struct iphdr *) (skb1->data + off1);
-               ip2 = (const struct iphdr *) (skb2->data + off2);
-
+               ip1 = skb_header_pointer(skb1, off1, sizeof(_ip1), &_ip1);
+               ip2 = skb_header_pointer(skb2, off2, sizeof(_ip2), &_ip2);
+               if (!ip1 || !ip2)
+                       return false;
                ip_proto = ip1->protocol;
                if (ip_proto != ip2->protocol ||
                    ip1->saddr != ip2->saddr || ip1->daddr != ip2->daddr)
@@ -190,9 +191,12 @@ static bool choke_match_flow(struct sk_buff *skb1,
 
        case __constant_htons(ETH_P_IPV6): {
                const struct ipv6hdr *ip1, *ip2;
+               struct ipv6hdr _ip1, _ip2;
 
-               ip1 = (const struct ipv6hdr *) (skb1->data + off1);
-               ip2 = (const struct ipv6hdr *) (skb2->data + off2);
+               ip1 = skb_header_pointer(skb1, off1, sizeof(_ip1), &_ip1);
+               ip2 = skb_header_pointer(skb2, off2, sizeof(_ip2), &_ip2);
+               if (!ip1 || !ip2)
+                       return false;
 
                ip_proto = ip1->nexthdr;
                if (ip_proto != ip2->nexthdr ||
@@ -214,8 +218,11 @@ static bool choke_match_flow(struct sk_buff *skb1,
        off1 += poff;
        off2 += poff;
 
-       ports1 = (__force u32 *)(skb1->data + off1);
-       ports2 = (__force u32 *)(skb2->data + off2);
+       ports1 = skb_header_pointer(skb1, off1, sizeof(_ports1), &_ports1);
+       ports2 = skb_header_pointer(skb2, off2, sizeof(_ports2), &_ports2);
+       if (!ports1 || !ports2)
+               return false;
+
        return *ports1 == *ports2;
 }
 
index 69fca27..79ac145 100644 (file)
@@ -246,6 +246,7 @@ static void dev_watchdog(unsigned long arg)
                                    time_after(jiffies, (trans_start +
                                                         dev->watchdog_timeo))) {
                                        some_queue_timedout = 1;
+                                       txq->trans_timeout++;
                                        break;
                                }
                        }
index 8104278..91f4791 100644 (file)
@@ -107,7 +107,7 @@ static int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev,
                if (addr) {
                        addr->a.v6.sin6_family = AF_INET6;
                        addr->a.v6.sin6_port = 0;
-                       ipv6_addr_copy(&addr->a.v6.sin6_addr, &ifa->addr);
+                       addr->a.v6.sin6_addr = ifa->addr;
                        addr->a.v6.sin6_scope_id = ifa->idev->dev->ifindex;
                        addr->valid = 1;
                        spin_lock_bh(&sctp_local_addr_lock);
@@ -219,8 +219,8 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport)
        /* Fill in the dest address from the route entry passed with the skb
         * and the source address from the transport.
         */
-       ipv6_addr_copy(&fl6.daddr, &transport->ipaddr.v6.sin6_addr);
-       ipv6_addr_copy(&fl6.saddr, &transport->saddr.v6.sin6_addr);
+       fl6.daddr = transport->ipaddr.v6.sin6_addr;
+       fl6.saddr = transport->saddr.v6.sin6_addr;
 
        fl6.flowlabel = np->flow_label;
        IP6_ECN_flow_xmit(sk, fl6.flowlabel);
@@ -231,7 +231,7 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport)
 
        if (np->opt && np->opt->srcrt) {
                struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
-               ipv6_addr_copy(&fl6.daddr, rt0->addr);
+               fl6.daddr = *rt0->addr;
        }
 
        SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, src:%pI6 dst:%pI6\n",
@@ -265,7 +265,7 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
        sctp_scope_t scope;
 
        memset(fl6, 0, sizeof(struct flowi6));
-       ipv6_addr_copy(&fl6->daddr, &daddr->v6.sin6_addr);
+       fl6->daddr = daddr->v6.sin6_addr;
        fl6->fl6_dport = daddr->v6.sin6_port;
        fl6->flowi6_proto = IPPROTO_SCTP;
        if (ipv6_addr_type(&daddr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL)
@@ -277,7 +277,7 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
                fl6->fl6_sport = htons(asoc->base.bind_addr.port);
 
        if (saddr) {
-               ipv6_addr_copy(&fl6->saddr, &saddr->v6.sin6_addr);
+               fl6->saddr = saddr->v6.sin6_addr;
                fl6->fl6_sport = saddr->v6.sin6_port;
                SCTP_DEBUG_PRINTK("SRC=%pI6 - ", &fl6->saddr);
        }
@@ -334,7 +334,7 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
        }
        rcu_read_unlock();
        if (baddr) {
-               ipv6_addr_copy(&fl6->saddr, &baddr->v6.sin6_addr);
+               fl6->saddr = baddr->v6.sin6_addr;
                fl6->fl6_sport = baddr->v6.sin6_port;
                dst = ip6_dst_lookup_flow(sk, fl6, NULL, false);
        }
@@ -375,7 +375,7 @@ static void sctp_v6_get_saddr(struct sctp_sock *sk,
 
        if (t->dst) {
                saddr->v6.sin6_family = AF_INET6;
-               ipv6_addr_copy(&saddr->v6.sin6_addr, &fl6->saddr);
+               saddr->v6.sin6_addr = fl6->saddr;
        }
 }
 
@@ -400,7 +400,7 @@ static void sctp_v6_copy_addrlist(struct list_head *addrlist,
                if (addr) {
                        addr->a.v6.sin6_family = AF_INET6;
                        addr->a.v6.sin6_port = 0;
-                       ipv6_addr_copy(&addr->a.v6.sin6_addr, &ifp->addr);
+                       addr->a.v6.sin6_addr = ifp->addr;
                        addr->a.v6.sin6_scope_id = dev->ifindex;
                        addr->valid = 1;
                        INIT_LIST_HEAD(&addr->list);
@@ -416,7 +416,6 @@ static void sctp_v6_copy_addrlist(struct list_head *addrlist,
 static void sctp_v6_from_skb(union sctp_addr *addr,struct sk_buff *skb,
                             int is_saddr)
 {
-       void *from;
        __be16 *port;
        struct sctphdr *sh;
 
@@ -428,12 +427,11 @@ static void sctp_v6_from_skb(union sctp_addr *addr,struct sk_buff *skb,
        sh = sctp_hdr(skb);
        if (is_saddr) {
                *port  = sh->source;
-               from = &ipv6_hdr(skb)->saddr;
+               addr->v6.sin6_addr = ipv6_hdr(skb)->saddr;
        } else {
                *port = sh->dest;
-               from = &ipv6_hdr(skb)->daddr;
+               addr->v6.sin6_addr = ipv6_hdr(skb)->daddr;
        }
-       ipv6_addr_copy(&addr->v6.sin6_addr, from);
 }
 
 /* Initialize an sctp_addr from a socket. */
@@ -441,7 +439,7 @@ static void sctp_v6_from_sk(union sctp_addr *addr, struct sock *sk)
 {
        addr->v6.sin6_family = AF_INET6;
        addr->v6.sin6_port = 0;
-       ipv6_addr_copy(&addr->v6.sin6_addr, &inet6_sk(sk)->rcv_saddr);
+       addr->v6.sin6_addr = inet6_sk(sk)->rcv_saddr;
 }
 
 /* Initialize sk->sk_rcv_saddr from sctp_addr. */
@@ -454,7 +452,7 @@ static void sctp_v6_to_sk_saddr(union sctp_addr *addr, struct sock *sk)
                inet6_sk(sk)->rcv_saddr.s6_addr32[3] =
                        addr->v4.sin_addr.s_addr;
        } else {
-               ipv6_addr_copy(&inet6_sk(sk)->rcv_saddr, &addr->v6.sin6_addr);
+               inet6_sk(sk)->rcv_saddr = addr->v6.sin6_addr;
        }
 }
 
@@ -467,7 +465,7 @@ static void sctp_v6_to_sk_daddr(union sctp_addr *addr, struct sock *sk)
                inet6_sk(sk)->daddr.s6_addr32[2] = htonl(0x0000ffff);
                inet6_sk(sk)->daddr.s6_addr32[3] = addr->v4.sin_addr.s_addr;
        } else {
-               ipv6_addr_copy(&inet6_sk(sk)->daddr, &addr->v6.sin6_addr);
+               inet6_sk(sk)->daddr = addr->v6.sin6_addr;
        }
 }
 
@@ -479,7 +477,7 @@ static void sctp_v6_from_addr_param(union sctp_addr *addr,
        addr->v6.sin6_family = AF_INET6;
        addr->v6.sin6_port = port;
        addr->v6.sin6_flowinfo = 0; /* BUG */
-       ipv6_addr_copy(&addr->v6.sin6_addr, &param->v6.addr);
+       addr->v6.sin6_addr = param->v6.addr;
        addr->v6.sin6_scope_id = iif;
 }
 
@@ -493,7 +491,7 @@ static int sctp_v6_to_addr_param(const union sctp_addr *addr,
 
        param->v6.param_hdr.type = SCTP_PARAM_IPV6_ADDRESS;
        param->v6.param_hdr.length = htons(length);
-       ipv6_addr_copy(&param->v6.addr, &addr->v6.sin6_addr);
+       param->v6.addr = addr->v6.sin6_addr;
 
        return length;
 }
@@ -504,7 +502,7 @@ static void sctp_v6_to_addr(union sctp_addr *addr, struct in6_addr *saddr,
 {
        addr->sa.sa_family = AF_INET6;
        addr->v6.sin6_port = port;
-       ipv6_addr_copy(&addr->v6.sin6_addr, saddr);
+       addr->v6.sin6_addr = *saddr;
 }
 
 /* Compare addresses exactly.
@@ -759,7 +757,7 @@ static void sctp_inet6_event_msgname(struct sctp_ulpevent *event,
                }
 
                sin6from = &asoc->peer.primary_addr.v6;
-               ipv6_addr_copy(&sin6->sin6_addr, &sin6from->sin6_addr);
+               sin6->sin6_addr = sin6from->sin6_addr;
                if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
                        sin6->sin6_scope_id = sin6from->sin6_scope_id;
        }
@@ -787,7 +785,7 @@ static void sctp_inet6_skb_msgname(struct sk_buff *skb, char *msgname,
                }
 
                /* Otherwise, just copy the v6 address. */
-               ipv6_addr_copy(&sin6->sin6_addr, &ipv6_hdr(skb)->saddr);
+               sin6->sin6_addr = ipv6_hdr(skb)->saddr;
                if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) {
                        struct sctp_ulpevent *ev = sctp_skb2event(skb);
                        sin6->sin6_scope_id = ev->iif;
index 0121e0a..a85eeeb 100644 (file)
@@ -3400,8 +3400,10 @@ int sctp_process_asconf_ack(struct sctp_association *asoc,
                asconf_len -= length;
        }
 
-       if (no_err && asoc->src_out_of_asoc_ok)
+       if (no_err && asoc->src_out_of_asoc_ok) {
                asoc->src_out_of_asoc_ok = 0;
+               sctp_transport_immediate_rtx(asoc->peer.primary_path);
+       }
 
        /* Free the cached last sent asconf chunk. */
        list_del_init(&asconf->transmitted_list);
index 76388b0..1ff51c9 100644 (file)
@@ -666,6 +666,7 @@ static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds,
                                  struct sctp_chunk *chunk)
 {
        sctp_sender_hb_info_t *hbinfo;
+       int was_unconfirmed = 0;
 
        /* 8.3 Upon the receipt of the HEARTBEAT ACK, the sender of the
         * HEARTBEAT should clear the error counter of the destination
@@ -692,9 +693,11 @@ static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds,
        /* Mark the destination transport address as active if it is not so
         * marked.
         */
-       if ((t->state == SCTP_INACTIVE) || (t->state == SCTP_UNCONFIRMED))
+       if ((t->state == SCTP_INACTIVE) || (t->state == SCTP_UNCONFIRMED)) {
+               was_unconfirmed = 1;
                sctp_assoc_control_transport(asoc, t, SCTP_TRANSPORT_UP,
                                             SCTP_HEARTBEAT_SUCCESS);
+       }
 
        /* The receiver of the HEARTBEAT ACK should also perform an
         * RTT measurement for that destination transport address
@@ -712,6 +715,9 @@ static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds,
        /* Update the heartbeat timer.  */
        if (!mod_timer(&t->hb_timer, sctp_transport_timeout(t)))
                sctp_transport_hold(t);
+
+       if (was_unconfirmed && asoc->peer.transport_count == 1)
+               sctp_transport_immediate_rtx(t);
 }
 
 
index 13bf5fc..d56c07a 100644 (file)
@@ -804,7 +804,7 @@ static int sctp_send_asconf_del_ip(struct sock              *sk,
                                struct sockaddr_in6 *sin6;
 
                                sin6 = (struct sockaddr_in6 *)addrs;
-                               ipv6_addr_copy(&asoc->asconf_addr_del_pending->v6.sin6_addr, &sin6->sin6_addr);
+                               asoc->asconf_addr_del_pending->v6.sin6_addr = sin6->sin6_addr;
                        }
                        SCTP_DEBUG_PRINTK_IPADDR("send_asconf_del_ip: keep the last address asoc: %p ",
                            " at %p\n", asoc, asoc->asconf_addr_del_pending,
index 394c57c..3889330 100644 (file)
@@ -641,3 +641,19 @@ void sctp_transport_reset(struct sctp_transport *t)
        t->cacc.next_tsn_at_change = 0;
        t->cacc.cacc_saw_newack = 0;
 }
+
+/* Schedule retransmission on the given transport */
+void sctp_transport_immediate_rtx(struct sctp_transport *t)
+{
+       /* Stop pending T3_rtx_timer */
+       if (timer_pending(&t->T3_rtx_timer)) {
+               (void)del_timer(&t->T3_rtx_timer);
+               sctp_transport_put(t);
+       }
+       sctp_retransmit(&t->asoc->outqueue, t, SCTP_RTXR_T3_RTX);
+       if (!timer_pending(&t->T3_rtx_timer)) {
+               if (!mod_timer(&t->T3_rtx_timer, jiffies + t->rto))
+                       sctp_transport_hold(t);
+       }
+       return;
+}
index 2877647..e62b4f0 100644 (file)
@@ -538,6 +538,8 @@ int sock_tx_timestamp(struct sock *sk, __u8 *tx_flags)
                *tx_flags |= SKBTX_HW_TSTAMP;
        if (sock_flag(sk, SOCK_TIMESTAMPING_TX_SOFTWARE))
                *tx_flags |= SKBTX_SW_TSTAMP;
+       if (sock_flag(sk, SOCK_WIFI_STATUS))
+               *tx_flags |= SKBTX_WIFI_STATUS;
        return 0;
 }
 EXPORT_SYMBOL(sock_tx_timestamp);
@@ -549,6 +551,8 @@ static inline int __sock_sendmsg_nosec(struct kiocb *iocb, struct socket *sock,
 
        sock_update_classid(sock->sk);
 
+       sock_update_netprioidx(sock->sk);
+
        si->sock = sock;
        si->scm = NULL;
        si->msg = msg;
@@ -674,6 +678,22 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
 }
 EXPORT_SYMBOL_GPL(__sock_recv_timestamp);
 
+void __sock_recv_wifi_status(struct msghdr *msg, struct sock *sk,
+       struct sk_buff *skb)
+{
+       int ack;
+
+       if (!sock_flag(sk, SOCK_WIFI_STATUS))
+               return;
+       if (!skb->wifi_acked_valid)
+               return;
+
+       ack = skb->wifi_acked;
+
+       put_cmsg(msg, SOL_SOCKET, SCM_WIFI_STATUS, sizeof(ack), &ack);
+}
+EXPORT_SYMBOL_GPL(__sock_recv_wifi_status);
+
 static inline void sock_recv_drops(struct msghdr *msg, struct sock *sk,
                                   struct sk_buff *skb)
 {
index ce13632..fe258fc 100644 (file)
@@ -134,7 +134,7 @@ static void ip_map_init(struct cache_head *cnew, struct cache_head *citem)
        struct ip_map *item = container_of(citem, struct ip_map, h);
 
        strcpy(new->m_class, item->m_class);
-       ipv6_addr_copy(&new->m_addr, &item->m_addr);
+       new->m_addr = item->m_addr;
 }
 static void update(struct cache_head *cnew, struct cache_head *citem)
 {
@@ -274,7 +274,7 @@ static int ip_map_show(struct seq_file *m,
        }
        im = container_of(h, struct ip_map, h);
        /* class addr domain */
-       ipv6_addr_copy(&addr, &im->m_addr);
+       addr = im->m_addr;
 
        if (test_bit(CACHE_VALID, &h->flags) &&
            !test_bit(CACHE_NEGATIVE, &h->flags))
@@ -297,7 +297,7 @@ static struct ip_map *__ip_map_lookup(struct cache_detail *cd, char *class,
        struct cache_head *ch;
 
        strcpy(ip.m_class, class);
-       ipv6_addr_copy(&ip.m_addr, addr);
+       ip.m_addr = *addr;
        ch = sunrpc_cache_lookup(cd, &ip.h,
                                 hash_str(class, IP_HASHBITS) ^
                                 hash_ip6(*addr));
index 71bed1c..4653286 100644 (file)
@@ -157,7 +157,7 @@ static void svc_set_cmsg_data(struct svc_rqst *rqstp, struct cmsghdr *cmh)
                        cmh->cmsg_level = SOL_IPV6;
                        cmh->cmsg_type = IPV6_PKTINFO;
                        pki->ipi6_ifindex = daddr->sin6_scope_id;
-                       ipv6_addr_copy(&pki->ipi6_addr, &daddr->sin6_addr);
+                       pki->ipi6_addr = daddr->sin6_addr;
                        cmh->cmsg_len = CMSG_LEN(sizeof(*pki));
                }
                break;
@@ -523,7 +523,7 @@ static int svc_udp_get_dest_address6(struct svc_rqst *rqstp,
                return 0;
 
        daddr->sin6_family = AF_INET6;
-       ipv6_addr_copy(&daddr->sin6_addr, &pki->ipi6_addr);
+       daddr->sin6_addr = pki->ipi6_addr;
        daddr->sin6_scope_id = pki->ipi6_ifindex;
        return 1;
 }
index 220f3bd..ccdfed8 100644 (file)
@@ -492,6 +492,10 @@ int wiphy_register(struct wiphy *wiphy)
                    !(wiphy->wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY)))
                return -EINVAL;
 
+       if (WARN_ON(wiphy->ap_sme_capa &&
+                   !(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME)))
+               return -EINVAL;
+
        if (WARN_ON(wiphy->addresses && !wiphy->n_addresses))
                return -EINVAL;
 
index b9ec306..1c7d4df 100644 (file)
@@ -54,6 +54,8 @@ struct cfg80211_registered_device {
        int opencount; /* also protected by devlist_mtx */
        wait_queue_head_t dev_wait;
 
+       u32 ap_beacons_nlpid;
+
        /* BSSes/scanning */
        spinlock_t bss_lock;
        struct list_head bss_list;
@@ -376,7 +378,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
                          enum nl80211_channel_type channel_type,
                          bool channel_type_valid, unsigned int wait,
                          const u8 *buf, size_t len, bool no_cck,
-                         u64 *cookie);
+                         bool dont_wait_for_ack, u64 *cookie);
 
 /* SME */
 int __cfg80211_connect(struct cfg80211_registered_device *rdev,
index 21fc970..6c1bafd 100644 (file)
@@ -879,6 +879,9 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid)
        }
 
        spin_unlock_bh(&wdev->mgmt_registrations_lock);
+
+       if (nlpid == wdev->ap_unexpected_nlpid)
+               wdev->ap_unexpected_nlpid = 0;
 }
 
 void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev)
@@ -901,7 +904,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
                          enum nl80211_channel_type channel_type,
                          bool channel_type_valid, unsigned int wait,
                          const u8 *buf, size_t len, bool no_cck,
-                         u64 *cookie)
+                         bool dont_wait_for_ack, u64 *cookie)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        const struct ieee80211_mgmt *mgmt;
@@ -992,7 +995,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
        /* Transmit the Action frame as requested by user space */
        return rdev->ops->mgmt_tx(&rdev->wiphy, dev, chan, offchan,
                                  channel_type, channel_type_valid,
-                                 wait, buf, len, no_cck, cookie);
+                                 wait, buf, len, no_cck, dont_wait_for_ack,
+                                 cookie);
 }
 
 bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf,
@@ -1107,3 +1111,30 @@ void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
        nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp);
 }
 EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);
+
+bool cfg80211_rx_spurious_frame(struct net_device *dev,
+                               const u8 *addr, gfp_t gfp)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
+                   wdev->iftype != NL80211_IFTYPE_P2P_GO))
+               return false;
+
+       return nl80211_unexpected_frame(dev, addr, gfp);
+}
+EXPORT_SYMBOL(cfg80211_rx_spurious_frame);
+
+bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev,
+                                       const u8 *addr, gfp_t gfp)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
+                   wdev->iftype != NL80211_IFTYPE_P2P_GO &&
+                   wdev->iftype != NL80211_IFTYPE_AP_VLAN))
+               return false;
+
+       return nl80211_unexpected_4addr_frame(dev, addr, gfp);
+}
+EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame);
index 48260c2..6bc7c4b 100644 (file)
@@ -98,7 +98,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
        [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 },
        [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
        [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
-       [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 },
+       [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 },
        [NL80211_ATTR_KEY_TYPE] = { .type = NLA_U32 },
 
        [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 },
@@ -132,8 +132,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
        [NL80211_ATTR_MESH_CONFIG] = { .type = NLA_NESTED },
        [NL80211_ATTR_SUPPORT_MESH_AUTH] = { .type = NLA_FLAG },
 
-       [NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY,
-                                        .len = NL80211_HT_CAPABILITY_LEN },
+       [NL80211_ATTR_HT_CAPABILITY] = { .len = NL80211_HT_CAPABILITY_LEN },
 
        [NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 },
        [NL80211_ATTR_IE] = { .type = NLA_BINARY,
@@ -197,6 +196,9 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
        [NL80211_ATTR_TDLS_OPERATION] = { .type = NLA_U8 },
        [NL80211_ATTR_TDLS_SUPPORT] = { .type = NLA_FLAG },
        [NL80211_ATTR_TDLS_EXTERNAL_SETUP] = { .type = NLA_FLAG },
+       [NL80211_ATTR_DONT_WAIT_FOR_ACK] = { .type = NLA_FLAG },
+       [NL80211_ATTR_PROBE_RESP] = { .type = NLA_BINARY,
+                                     .len = IEEE80211_MAX_DATA_LEN },
 };
 
 /* policy for the key attributes */
@@ -204,7 +206,7 @@ static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = {
        [NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN },
        [NL80211_KEY_IDX] = { .type = NLA_U8 },
        [NL80211_KEY_CIPHER] = { .type = NLA_U32 },
-       [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 },
+       [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 },
        [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG },
        [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG },
        [NL80211_KEY_TYPE] = { .type = NLA_U32 },
@@ -759,6 +761,10 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX,
                    dev->wiphy.available_antennas_rx);
 
+       if (dev->wiphy.flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD)
+               NLA_PUT_U32(msg, NL80211_ATTR_PROBE_RESP_OFFLOAD,
+                           dev->wiphy.probe_resp_offload);
+
        if ((dev->wiphy.available_antennas_tx ||
             dev->wiphy.available_antennas_rx) && dev->ops->get_antenna) {
                u32 tx_ant = 0, rx_ant = 0;
@@ -891,6 +897,11 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
        }
        if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
                CMD(sched_scan_start, START_SCHED_SCAN);
+       CMD(probe_client, PROBE_CLIENT);
+       if (dev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) {
+               i++;
+               NLA_PUT_U32(msg, i, NL80211_CMD_REGISTER_BEACONS);
+       }
 
 #undef CMD
 
@@ -1008,6 +1019,12 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
        if (nl80211_put_iface_combinations(&dev->wiphy, msg))
                goto nla_put_failure;
 
+       if (dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME)
+               NLA_PUT_U32(msg, NL80211_ATTR_DEVICE_AP_SME,
+                           dev->wiphy.ap_sme_capa);
+
+       NLA_PUT_U32(msg, NL80211_ATTR_FEATURE_FLAGS, dev->wiphy.features);
+
        return genlmsg_end(msg, hdr);
 
  nla_put_failure:
@@ -1253,6 +1270,12 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
                        goto bad_res;
                }
 
+               if (netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+                   netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) {
+                       result = -EINVAL;
+                       goto bad_res;
+               }
+
                nla_for_each_nested(nl_txq_params,
                                    info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS],
                                    rem_txq_params) {
@@ -2150,6 +2173,13 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
                        nla_len(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]);
        }
 
+       if (info->attrs[NL80211_ATTR_PROBE_RESP]) {
+               params.probe_resp =
+                       nla_data(info->attrs[NL80211_ATTR_PROBE_RESP]);
+               params.probe_resp_len =
+                       nla_len(info->attrs[NL80211_ATTR_PROBE_RESP]);
+       }
+
        err = call(&rdev->wiphy, dev, &params);
        if (!err && params.interval)
                wdev->beacon_interval = params.interval;
@@ -5266,12 +5296,13 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
        bool channel_type_valid = false;
        u32 freq;
        int err;
-       void *hdr;
+       void *hdr = NULL;
        u64 cookie;
-       struct sk_buff *msg;
+       struct sk_buff *msg = NULL;
        unsigned int wait = 0;
-       bool offchan;
-       bool no_cck;
+       bool offchan, no_cck, dont_wait_for_ack;
+
+       dont_wait_for_ack = info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK];
 
        if (!info->attrs[NL80211_ATTR_FRAME] ||
            !info->attrs[NL80211_ATTR_WIPHY_FREQ])
@@ -5315,29 +5346,36 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
        if (chan == NULL)
                return -EINVAL;
 
-       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-       if (!msg)
-               return -ENOMEM;
+       if (!dont_wait_for_ack) {
+               msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+               if (!msg)
+                       return -ENOMEM;
 
-       hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
-                            NL80211_CMD_FRAME);
+               hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
+                                    NL80211_CMD_FRAME);
 
-       if (IS_ERR(hdr)) {
-               err = PTR_ERR(hdr);
-               goto free_msg;
+               if (IS_ERR(hdr)) {
+                       err = PTR_ERR(hdr);
+                       goto free_msg;
+               }
        }
+
        err = cfg80211_mlme_mgmt_tx(rdev, dev, chan, offchan, channel_type,
                                    channel_type_valid, wait,
                                    nla_data(info->attrs[NL80211_ATTR_FRAME]),
                                    nla_len(info->attrs[NL80211_ATTR_FRAME]),
-                                   no_cck, &cookie);
+                                   no_cck, dont_wait_for_ack, &cookie);
        if (err)
                goto free_msg;
 
-       NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
+       if (msg) {
+               NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
 
-       genlmsg_end(msg, hdr);
-       return genlmsg_reply(msg, info);
+               genlmsg_end(msg, hdr);
+               return genlmsg_reply(msg, info);
+       }
+
+       return 0;
 
  nla_put_failure:
        err = -ENOBUFS;
@@ -5827,6 +5865,91 @@ static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info)
        return err;
 }
 
+static int nl80211_register_unexpected_frame(struct sk_buff *skb,
+                                            struct genl_info *info)
+{
+       struct net_device *dev = info->user_ptr[1];
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+       if (wdev->iftype != NL80211_IFTYPE_AP &&
+           wdev->iftype != NL80211_IFTYPE_P2P_GO)
+               return -EINVAL;
+
+       if (wdev->ap_unexpected_nlpid)
+               return -EBUSY;
+
+       wdev->ap_unexpected_nlpid = info->snd_pid;
+       return 0;
+}
+
+static int nl80211_probe_client(struct sk_buff *skb,
+                               struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct sk_buff *msg;
+       void *hdr;
+       const u8 *addr;
+       u64 cookie;
+       int err;
+
+       if (wdev->iftype != NL80211_IFTYPE_AP &&
+           wdev->iftype != NL80211_IFTYPE_P2P_GO)
+               return -EOPNOTSUPP;
+
+       if (!info->attrs[NL80211_ATTR_MAC])
+               return -EINVAL;
+
+       if (!rdev->ops->probe_client)
+               return -EOPNOTSUPP;
+
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
+       hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
+                            NL80211_CMD_PROBE_CLIENT);
+
+       if (IS_ERR(hdr)) {
+               err = PTR_ERR(hdr);
+               goto free_msg;
+       }
+
+       addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+       err = rdev->ops->probe_client(&rdev->wiphy, dev, addr, &cookie);
+       if (err)
+               goto free_msg;
+
+       NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
+
+       genlmsg_end(msg, hdr);
+
+       return genlmsg_reply(msg, info);
+
+ nla_put_failure:
+       err = -ENOBUFS;
+ free_msg:
+       nlmsg_free(msg);
+       return err;
+}
+
+static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+
+       if (!(rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS))
+               return -EOPNOTSUPP;
+
+       if (rdev->ap_beacons_nlpid)
+               return -EBUSY;
+
+       rdev->ap_beacons_nlpid = info->snd_pid;
+
+       return 0;
+}
+
 #define NL80211_FLAG_NEED_WIPHY                0x01
 #define NL80211_FLAG_NEED_NETDEV       0x02
 #define NL80211_FLAG_NEED_RTNL         0x04
@@ -6382,6 +6505,30 @@ static struct genl_ops nl80211_ops[] = {
                .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
                                  NL80211_FLAG_NEED_RTNL,
        },
+       {
+               .cmd = NL80211_CMD_UNEXPECTED_FRAME,
+               .doit = nl80211_register_unexpected_frame,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
+       },
+       {
+               .cmd = NL80211_CMD_PROBE_CLIENT,
+               .doit = nl80211_probe_client,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
+       },
+       {
+               .cmd = NL80211_CMD_REGISTER_BEACONS,
+               .doit = nl80211_register_beacons,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_WIPHY |
+                                 NL80211_FLAG_NEED_RTNL,
+       },
 };
 
 static struct genl_multicast_group nl80211_mlme_mcgrp = {
@@ -6634,10 +6781,7 @@ void nl80211_send_reg_change_event(struct regulatory_request *request)
        if (wiphy_idx_valid(request->wiphy_idx))
                NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        rcu_read_lock();
        genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id,
@@ -6673,10 +6817,7 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
        NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -6757,10 +6898,7 @@ static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev,
        NLA_PUT_FLAG(msg, NL80211_ATTR_TIMED_OUT);
        NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -6816,10 +6954,7 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
        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_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -6857,10 +6992,7 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
        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_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -6898,10 +7030,7 @@ void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
        if (ie)
                NLA_PUT(msg, NL80211_ATTR_IE, ie_len, ie);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, GFP_KERNEL);
@@ -6934,10 +7063,7 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
        NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -6972,10 +7098,7 @@ void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev,
        if (ie_len && ie)
                NLA_PUT(msg, NL80211_ATTR_IE, ie_len , ie);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -7014,10 +7137,7 @@ void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
        if (tsc)
                NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, 6, tsc);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -7068,10 +7188,7 @@ void nl80211_send_beacon_hint_event(struct wiphy *wiphy,
                goto nla_put_failure;
        nla_nest_end(msg, nl_freq);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        rcu_read_lock();
        genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id,
@@ -7114,10 +7231,7 @@ static void nl80211_send_remain_on_chan_event(
        if (cmd == NL80211_CMD_REMAIN_ON_CHANNEL)
                NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -7188,10 +7302,7 @@ void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev,
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
        NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -7202,13 +7313,68 @@ void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev,
        nlmsg_free(msg);
 }
 
+static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd,
+                                      const u8 *addr, gfp_t gfp)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct sk_buff *msg;
+       void *hdr;
+       int err;
+       u32 nlpid = ACCESS_ONCE(wdev->ap_unexpected_nlpid);
+
+       if (!nlpid)
+               return false;
+
+       msg = nlmsg_new(100, gfp);
+       if (!msg)
+               return true;
+
+       hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
+       if (!hdr) {
+               nlmsg_free(msg);
+               return true;
+       }
+
+       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
+       NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+
+       err = genlmsg_end(msg, hdr);
+       if (err < 0) {
+               nlmsg_free(msg);
+               return true;
+       }
+
+       genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlpid);
+       return true;
+
+ nla_put_failure:
+       genlmsg_cancel(msg, hdr);
+       nlmsg_free(msg);
+       return true;
+}
+
+bool nl80211_unexpected_frame(struct net_device *dev, const u8 *addr, gfp_t gfp)
+{
+       return __nl80211_unexpected_frame(dev, NL80211_CMD_UNEXPECTED_FRAME,
+                                         addr, gfp);
+}
+
+bool nl80211_unexpected_4addr_frame(struct net_device *dev,
+                                   const u8 *addr, gfp_t gfp)
+{
+       return __nl80211_unexpected_frame(dev,
+                                         NL80211_CMD_UNEXPECTED_4ADDR_FRAME,
+                                         addr, gfp);
+}
+
 int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
                      struct net_device *netdev, u32 nlpid,
                      int freq, const u8 *buf, size_t len, gfp_t gfp)
 {
        struct sk_buff *msg;
        void *hdr;
-       int err;
 
        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
        if (!msg)
@@ -7225,16 +7391,9 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
        NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf);
 
-       err = genlmsg_end(msg, hdr);
-       if (err < 0) {
-               nlmsg_free(msg);
-               return err;
-       }
+       genlmsg_end(msg, hdr);
 
-       err = genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlpid);
-       if (err < 0)
-               return err;
-       return 0;
+       return genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlpid);
 
  nla_put_failure:
        genlmsg_cancel(msg, hdr);
@@ -7267,10 +7426,7 @@ void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev,
        if (ack)
                NLA_PUT_FLAG(msg, NL80211_ATTR_ACK);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp);
        return;
@@ -7312,10 +7468,7 @@ nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev,
 
        nla_nest_end(msg, pinfoattr);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -7357,10 +7510,7 @@ void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
 
        nla_nest_end(msg, rekey_attr);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -7403,10 +7553,7 @@ void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
 
        nla_nest_end(msg, attr);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -7448,7 +7595,45 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
 
        nla_nest_end(msg, pinfoattr);
 
-       if (genlmsg_end(msg, hdr) < 0) {
+       genlmsg_end(msg, hdr);
+
+       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+                               nl80211_mlme_mcgrp.id, gfp);
+       return;
+
+ nla_put_failure:
+       genlmsg_cancel(msg, hdr);
+       nlmsg_free(msg);
+}
+
+void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
+                          u64 cookie, bool acked, gfp_t gfp)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct sk_buff *msg;
+       void *hdr;
+       int err;
+
+       msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
+       if (!msg)
+               return;
+
+       hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PROBE_CLIENT);
+       if (!hdr) {
+               nlmsg_free(msg);
+               return;
+       }
+
+       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
+       NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+       NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
+       if (acked)
+               NLA_PUT_FLAG(msg, NL80211_ATTR_ACK);
+
+       err = genlmsg_end(msg, hdr);
+       if (err < 0) {
                nlmsg_free(msg);
                return;
        }
@@ -7461,6 +7646,45 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
        genlmsg_cancel(msg, hdr);
        nlmsg_free(msg);
 }
+EXPORT_SYMBOL(cfg80211_probe_status);
+
+void cfg80211_report_obss_beacon(struct wiphy *wiphy,
+                                const u8 *frame, size_t len,
+                                int freq, gfp_t gfp)
+{
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct sk_buff *msg;
+       void *hdr;
+       u32 nlpid = ACCESS_ONCE(rdev->ap_beacons_nlpid);
+
+       if (!nlpid)
+               return;
+
+       msg = nlmsg_new(len + 100, gfp);
+       if (!msg)
+               return;
+
+       hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
+       if (!hdr) {
+               nlmsg_free(msg);
+               return;
+       }
+
+       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+       if (freq)
+               NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
+       NLA_PUT(msg, NL80211_ATTR_FRAME, len, frame);
+
+       genlmsg_end(msg, hdr);
+
+       genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlpid);
+       return;
+
+ nla_put_failure:
+       genlmsg_cancel(msg, hdr);
+       nlmsg_free(msg);
+}
+EXPORT_SYMBOL(cfg80211_report_obss_beacon);
 
 static int nl80211_netlink_notify(struct notifier_block * nb,
                                  unsigned long state,
@@ -7475,9 +7699,12 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
 
        rcu_read_lock();
 
-       list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list)
+       list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {
                list_for_each_entry_rcu(wdev, &rdev->netdev_list, list)
                        cfg80211_mlme_unregister_socket(wdev, notify->pid);
+               if (rdev->ap_beacons_nlpid == notify->pid)
+                       rdev->ap_beacons_nlpid = 0;
+       }
 
        rcu_read_unlock();
 
index f24a1fb..12bf4d1 100644 (file)
@@ -117,4 +117,9 @@ void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
                                    struct net_device *netdev, int index,
                                    const u8 *bssid, bool preauth, gfp_t gfp);
 
+bool nl80211_unexpected_frame(struct net_device *dev,
+                             const u8 *addr, gfp_t gfp);
+bool nl80211_unexpected_4addr_frame(struct net_device *dev,
+                                   const u8 *addr, gfp_t gfp);
+
 #endif /* __NET_WIRELESS_NL80211_H */
index 6acba9d..e71f5a6 100644 (file)
@@ -2265,6 +2265,9 @@ void /* __init_or_exit */ regulatory_exit(void)
 
        kfree(last_request);
 
+       last_request = NULL;
+       dev_set_uevent_suppress(&reg_pdev->dev, true);
+
        platform_device_unregister(reg_pdev);
 
        spin_lock_bh(&reg_pending_beacons_lock);
index 0fb1424..31119e3 100644 (file)
@@ -259,17 +259,20 @@ static int cmp_ies(u8 num, u8 *ies1, size_t len1, u8 *ies2, size_t len2)
 {
        const u8 *ie1 = cfg80211_find_ie(num, ies1, len1);
        const u8 *ie2 = cfg80211_find_ie(num, ies2, len2);
-       int r;
 
+       /* equal if both missing */
        if (!ie1 && !ie2)
                return 0;
-       if (!ie1 || !ie2)
+       /* sort missing IE before (left of) present IE */
+       if (!ie1)
                return -1;
+       if (!ie2)
+               return 1;
 
-       r = memcmp(ie1 + 2, ie2 + 2, min(ie1[1], ie2[1]));
-       if (r == 0 && ie1[1] != ie2[1])
+       /* sort by length first, then by contents */
+       if (ie1[1] != ie2[1])
                return ie2[1] - ie1[1];
-       return r;
+       return memcmp(ie1 + 2, ie2 + 2, ie1[1]);
 }
 
 static bool is_bss(struct cfg80211_bss *a,
@@ -352,8 +355,8 @@ static bool is_mesh(struct cfg80211_bss *a,
            sizeof(struct ieee80211_meshconf_ie) - 2) == 0;
 }
 
-static int cmp_bss(struct cfg80211_bss *a,
-                  struct cfg80211_bss *b)
+static int cmp_bss_core(struct cfg80211_bss *a,
+                       struct cfg80211_bss *b)
 {
        int r;
 
@@ -375,7 +378,15 @@ static int cmp_bss(struct cfg80211_bss *a,
                               b->len_information_elements);
        }
 
-       r = memcmp(a->bssid, b->bssid, ETH_ALEN);
+       return memcmp(a->bssid, b->bssid, ETH_ALEN);
+}
+
+static int cmp_bss(struct cfg80211_bss *a,
+                  struct cfg80211_bss *b)
+{
+       int r;
+
+       r = cmp_bss_core(a, b);
        if (r)
                return r;
 
@@ -386,6 +397,52 @@ static int cmp_bss(struct cfg80211_bss *a,
                       b->len_information_elements);
 }
 
+static int cmp_hidden_bss(struct cfg80211_bss *a,
+                  struct cfg80211_bss *b)
+{
+       const u8 *ie1;
+       const u8 *ie2;
+       int i;
+       int r;
+
+       r = cmp_bss_core(a, b);
+       if (r)
+               return r;
+
+       ie1 = cfg80211_find_ie(WLAN_EID_SSID,
+                       a->information_elements,
+                       a->len_information_elements);
+       ie2 = cfg80211_find_ie(WLAN_EID_SSID,
+                       b->information_elements,
+                       b->len_information_elements);
+
+       /* Key comparator must use same algorithm in any rb-tree
+        * search function (order is important), otherwise ordering
+        * of items in the tree is broken and search gives incorrect
+        * results. This code uses same order as cmp_ies() does. */
+
+       /* sort missing IE before (left of) present IE */
+       if (!ie1)
+               return -1;
+       if (!ie2)
+               return 1;
+
+       /* zero-size SSID is used as an indication of the hidden bss */
+       if (!ie2[1])
+               return 0;
+
+       /* sort by length first, then by contents */
+       if (ie1[1] != ie2[1])
+               return ie2[1] - ie1[1];
+
+       /* zeroed SSID ie is another indication of a hidden bss */
+       for (i = 0; i < ie2[1]; i++)
+               if (ie2[i + 2])
+                       return -1;
+
+       return 0;
+}
+
 struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
                                      struct ieee80211_channel *channel,
                                      const u8 *bssid,
@@ -502,6 +559,48 @@ rb_find_bss(struct cfg80211_registered_device *dev,
 }
 
 static struct cfg80211_internal_bss *
+rb_find_hidden_bss(struct cfg80211_registered_device *dev,
+           struct cfg80211_internal_bss *res)
+{
+       struct rb_node *n = dev->bss_tree.rb_node;
+       struct cfg80211_internal_bss *bss;
+       int r;
+
+       while (n) {
+               bss = rb_entry(n, struct cfg80211_internal_bss, rbn);
+               r = cmp_hidden_bss(&res->pub, &bss->pub);
+
+               if (r == 0)
+                       return bss;
+               else if (r < 0)
+                       n = n->rb_left;
+               else
+                       n = n->rb_right;
+       }
+
+       return NULL;
+}
+
+static void
+copy_hidden_ies(struct cfg80211_internal_bss *res,
+                struct cfg80211_internal_bss *hidden)
+{
+       if (unlikely(res->pub.beacon_ies))
+               return;
+       if (WARN_ON(!hidden->pub.beacon_ies))
+               return;
+
+       res->pub.beacon_ies = kmalloc(hidden->pub.len_beacon_ies, GFP_ATOMIC);
+       if (unlikely(!res->pub.beacon_ies))
+               return;
+
+       res->beacon_ies_allocated = true;
+       res->pub.len_beacon_ies = hidden->pub.len_beacon_ies;
+       memcpy(res->pub.beacon_ies, hidden->pub.beacon_ies,
+                       res->pub.len_beacon_ies);
+}
+
+static struct cfg80211_internal_bss *
 cfg80211_bss_update(struct cfg80211_registered_device *dev,
                    struct cfg80211_internal_bss *res)
 {
@@ -604,6 +703,21 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
 
                kref_put(&res->ref, bss_release);
        } else {
+               struct cfg80211_internal_bss *hidden;
+
+               /* First check if the beacon is a probe response from
+                * a hidden bss. If so, copy beacon ies (with nullified
+                * ssid) into the probe response bss entry (with real ssid).
+                * It is required basically for PSM implementation
+                * (probe responses do not contain tim ie) */
+
+               /* TODO: The code is not trying to update existing probe
+                * response bss entries when beacon ies are
+                * getting changed. */
+               hidden = rb_find_hidden_bss(dev, res);
+               if (hidden)
+                       copy_hidden_ies(res, hidden);
+
                /* this "consumes" the reference */
                list_add_tail(&res->list, &dev->bss_list);
                rb_insert_bss(dev, res);
index 6897436..3c24eb9 100644 (file)
@@ -819,12 +819,24 @@ static int cfg80211_wext_giwfreq(struct net_device *dev,
                                 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;
 
        switch (wdev->iftype) {
        case NL80211_IFTYPE_STATION:
                return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra);
        case NL80211_IFTYPE_ADHOC:
                return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
+       case NL80211_IFTYPE_MONITOR:
+               if (!rdev->ops->get_channel)
+                       return -EINVAL;
+
+               chan = rdev->ops->get_channel(wdev->wiphy);
+               if (!chan)
+                       return -EINVAL;
+               freq->m = chan->center_freq;
+               freq->e = 6;
+               return 0;
        default:
                if (!wdev->channel)
                        return -EINVAL;
index 552df27..593c8a1 100644 (file)
@@ -61,8 +61,8 @@ __xfrm4_selector_match(const struct xfrm_selector *sel, const struct flowi *fl)
 {
        const struct flowi4 *fl4 = &fl->u.ip4;
 
-       return  addr_match(&fl4->daddr, &sel->daddr, sel->prefixlen_d) &&
-               addr_match(&fl4->saddr, &sel->saddr, sel->prefixlen_s) &&
+       return  addr4_match(fl4->daddr, sel->daddr.a4, sel->prefixlen_d) &&
+               addr4_match(fl4->saddr, sel->saddr.a4, sel->prefixlen_s) &&
                !((xfrm_flowi_dport(fl, &fl4->uli) ^ sel->dport) & sel->dport_mask) &&
                !((xfrm_flowi_sport(fl, &fl4->uli) ^ sel->sport) & sel->sport_mask) &&
                (fl4->flowi4_proto == sel->proto || !sel->proto) &&
index 9414b9c..5b228f9 100644 (file)
@@ -1035,16 +1035,12 @@ static struct xfrm_state *__find_acq_core(struct net *net, struct xfrm_mark *m,
                        break;
 
                case AF_INET6:
-                       ipv6_addr_copy((struct in6_addr *)x->sel.daddr.a6,
-                                      (const struct in6_addr *)daddr);
-                       ipv6_addr_copy((struct in6_addr *)x->sel.saddr.a6,
-                                      (const struct in6_addr *)saddr);
+                       *(struct in6_addr *)x->sel.daddr.a6 = *(struct in6_addr *)daddr;
+                       *(struct in6_addr *)x->sel.saddr.a6 = *(struct in6_addr *)saddr;
                        x->sel.prefixlen_d = 128;
                        x->sel.prefixlen_s = 128;
-                       ipv6_addr_copy((struct in6_addr *)x->props.saddr.a6,
-                                      (const struct in6_addr *)saddr);
-                       ipv6_addr_copy((struct in6_addr *)x->id.daddr.a6,
-                                      (const struct in6_addr *)daddr);
+                       *(struct in6_addr *)x->props.saddr.a6 = *(struct in6_addr *)saddr;
+                       *(struct in6_addr *)x->id.daddr.a6 = *(struct in6_addr *)daddr;
                        break;
                }
 
index 6bc7a86..d6f8433 100644 (file)
@@ -2,5 +2,9 @@
 # Makefile for encrypted keys
 #
 
-obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted.o ecryptfs_format.o
-obj-$(CONFIG_TRUSTED_KEYS) += masterkey_trusted.o
+obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys.o
+
+encrypted-keys-y := encrypted.o ecryptfs_format.o
+masterkey-$(CONFIG_TRUSTED_KEYS) := masterkey_trusted.o
+masterkey-$(CONFIG_TRUSTED_KEYS)-$(CONFIG_ENCRYPTED_KEYS) := masterkey_trusted.o
+encrypted-keys-y += $(masterkey-y) $(masterkey-m-m)
index dcc843c..41144f7 100644 (file)
@@ -444,7 +444,7 @@ static struct key *request_master_key(struct encrypted_key_payload *epayload,
                goto out;
 
        if (IS_ERR(mkey)) {
-               int ret = PTR_ERR(epayload);
+               int ret = PTR_ERR(mkey);
 
                if (ret == -ENOTSUPP)
                        pr_info("encrypted_key: key %s not supported",
index b6ade89..8136a2d 100644 (file)
@@ -2,7 +2,8 @@
 #define __ENCRYPTED_KEY_H
 
 #define ENCRYPTED_DEBUG 0
-#ifdef CONFIG_TRUSTED_KEYS
+#if defined(CONFIG_TRUSTED_KEYS) || \
+  (defined(CONFIG_TRUSTED_KEYS_MODULE) && defined(CONFIG_ENCRYPTED_KEYS_MODULE))
 extern struct key *request_trusted_key(const char *trusted_desc,
                                       u8 **master_key, size_t *master_keylen);
 #else
index 5b366d7..69ff52c 100644 (file)
@@ -102,7 +102,8 @@ int user_update(struct key *key, const void *data, size_t datalen)
                key->expiry = 0;
        }
 
-       kfree_rcu(zap, rcu);
+       if (zap)
+               kfree_rcu(zap, rcu);
 
 error:
        return ret;
index 893af8a..199616b 100644 (file)
@@ -118,8 +118,8 @@ int ipv6_skb_to_auditdata(struct sk_buff *skb,
        ip6 = ipv6_hdr(skb);
        if (ip6 == NULL)
                return -EINVAL;
-       ipv6_addr_copy(&ad->u.net.v6info.saddr, &ip6->saddr);
-       ipv6_addr_copy(&ad->u.net.v6info.daddr, &ip6->daddr);
+       ad->u.net.v6info.saddr = ip6->saddr;
+       ad->u.net.v6info.daddr = ip6->daddr;
        ret = 0;
        /* IPv6 can have several extension header before the Transport header
         * skip them */
index 1126c10..7e6c256 100644 (file)
@@ -3567,8 +3567,8 @@ static int selinux_parse_skb_ipv6(struct sk_buff *skb,
        if (ip6 == NULL)
                goto out;
 
-       ipv6_addr_copy(&ad->u.net.v6info.saddr, &ip6->saddr);
-       ipv6_addr_copy(&ad->u.net.v6info.daddr, &ip6->daddr);
+       ad->u.net.v6info.saddr = ip6->saddr;
+       ad->u.net.v6info.daddr = ip6->daddr;
        ret = 0;
 
        nexthdr = ip6->nexthdr;
@@ -3871,7 +3871,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
                if (family == PF_INET)
                        ad.u.net.v4info.saddr = addr4->sin_addr.s_addr;
                else
-                       ipv6_addr_copy(&ad.u.net.v6info.saddr, &addr6->sin6_addr);
+                       ad.u.net.v6info.saddr = addr6->sin6_addr;
 
                err = avc_has_perm(sksec->sid, sid,
                                   sksec->sclass, node_perm, &ad);
index 3bf46ab..8636585 100644 (file)
@@ -220,7 +220,7 @@ static int sel_netnode_sid_slow(void *addr, u16 family, u32 *sid)
        case PF_INET6:
                ret = security_node_sid(PF_INET6,
                                        addr, sizeof(struct in6_addr), sid);
-               ipv6_addr_copy(&new->nsec.addr.ipv6, addr);
+               new->nsec.addr.ipv6 = *(struct in6_addr *)addr;
                break;
        default:
                BUG();
index 6aceef5..5c32f36 100644 (file)
@@ -102,9 +102,6 @@ static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
 
 const char *smack_cipso_option = SMACK_CIPSO_OPTION;
 
-
-#define        SEQ_READ_FINISHED       ((loff_t)-1)
-
 /*
  * Values for parsing cipso rules
  * SMK_DIGITLEN: Length of a digit field in a rule.
@@ -357,10 +354,12 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf,
 
        rc = count;
        /*
+        * If this is "load" as opposed to "load-self" and a new rule
+        * it needs to get added for reporting.
         * smk_set_access returns true if there was already a rule
         * for the subject/object pair, and false if it was new.
         */
-       if (!smk_set_access(rule, rule_list, rule_lock)) {
+       if (load && !smk_set_access(rule, rule_list, rule_lock)) {
                smlp = kzalloc(sizeof(*smlp), GFP_KERNEL);
                if (smlp != NULL) {
                        smlp->smk_rule = rule;
@@ -377,12 +376,12 @@ out:
        return rc;
 }
 
-
 /*
- * Seq_file read operations for /smack/load
+ * Core logic for smackfs seq list operations.
  */
 
-static void *load_seq_start(struct seq_file *s, loff_t *pos)
+static void *smk_seq_start(struct seq_file *s, loff_t *pos,
+                               struct list_head *head)
 {
        struct list_head *list;
 
@@ -390,7 +389,7 @@ static void *load_seq_start(struct seq_file *s, loff_t *pos)
         * This is 0 the first time through.
         */
        if (s->index == 0)
-               s->private = &smack_rule_list;
+               s->private = head;
 
        if (s->private == NULL)
                return NULL;
@@ -404,11 +403,12 @@ static void *load_seq_start(struct seq_file *s, loff_t *pos)
        return list;
 }
 
-static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos)
+static void *smk_seq_next(struct seq_file *s, void *v, loff_t *pos,
+                               struct list_head *head)
 {
        struct list_head *list = v;
 
-       if (list_is_last(list, &smack_rule_list)) {
+       if (list_is_last(list, head)) {
                s->private = NULL;
                return NULL;
        }
@@ -416,6 +416,25 @@ static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos)
        return list->next;
 }
 
+static void smk_seq_stop(struct seq_file *s, void *v)
+{
+       /* No-op */
+}
+
+/*
+ * Seq_file read operations for /smack/load
+ */
+
+static void *load_seq_start(struct seq_file *s, loff_t *pos)
+{
+       return smk_seq_start(s, pos, &smack_rule_list);
+}
+
+static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+       return smk_seq_next(s, v, pos, &smack_rule_list);
+}
+
 static int load_seq_show(struct seq_file *s, void *v)
 {
        struct list_head *list = v;
@@ -446,16 +465,11 @@ static int load_seq_show(struct seq_file *s, void *v)
        return 0;
 }
 
-static void load_seq_stop(struct seq_file *s, void *v)
-{
-       /* No-op */
-}
-
 static const struct seq_operations load_seq_ops = {
        .start = load_seq_start,
        .next  = load_seq_next,
        .show  = load_seq_show,
-       .stop  = load_seq_stop,
+       .stop  = smk_seq_stop,
 };
 
 /**
@@ -574,28 +588,12 @@ static void smk_unlbl_ambient(char *oldambient)
 
 static void *cipso_seq_start(struct seq_file *s, loff_t *pos)
 {
-       if (*pos == SEQ_READ_FINISHED)
-               return NULL;
-       if (list_empty(&smack_known_list))
-               return NULL;
-
-       return smack_known_list.next;
+       return smk_seq_start(s, pos, &smack_known_list);
 }
 
 static void *cipso_seq_next(struct seq_file *s, void *v, loff_t *pos)
 {
-       struct list_head  *list = v;
-
-       /*
-        * labels with no associated cipso value wont be printed
-        * in cipso_seq_show
-        */
-       if (list_is_last(list, &smack_known_list)) {
-               *pos = SEQ_READ_FINISHED;
-               return NULL;
-       }
-
-       return list->next;
+       return smk_seq_next(s, v, pos, &smack_known_list);
 }
 
 /*
@@ -634,16 +632,11 @@ static int cipso_seq_show(struct seq_file *s, void *v)
        return 0;
 }
 
-static void cipso_seq_stop(struct seq_file *s, void *v)
-{
-       /* No-op */
-}
-
 static const struct seq_operations cipso_seq_ops = {
        .start = cipso_seq_start,
-       .stop  = cipso_seq_stop,
        .next  = cipso_seq_next,
        .show  = cipso_seq_show,
+       .stop  = smk_seq_stop,
 };
 
 /**
@@ -788,23 +781,12 @@ static const struct file_operations smk_cipso_ops = {
 
 static void *netlbladdr_seq_start(struct seq_file *s, loff_t *pos)
 {
-       if (*pos == SEQ_READ_FINISHED)
-               return NULL;
-       if (list_empty(&smk_netlbladdr_list))
-               return NULL;
-       return smk_netlbladdr_list.next;
+       return smk_seq_start(s, pos, &smk_netlbladdr_list);
 }
 
 static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos)
 {
-       struct list_head *list = v;
-
-       if (list_is_last(list, &smk_netlbladdr_list)) {
-               *pos = SEQ_READ_FINISHED;
-               return NULL;
-       }
-
-       return list->next;
+       return smk_seq_next(s, v, pos, &smk_netlbladdr_list);
 }
 #define BEBITS (sizeof(__be32) * 8)
 
@@ -828,16 +810,11 @@ static int netlbladdr_seq_show(struct seq_file *s, void *v)
        return 0;
 }
 
-static void netlbladdr_seq_stop(struct seq_file *s, void *v)
-{
-       /* No-op */
-}
-
 static const struct seq_operations netlbladdr_seq_ops = {
        .start = netlbladdr_seq_start,
-       .stop  = netlbladdr_seq_stop,
        .next  = netlbladdr_seq_next,
        .show  = netlbladdr_seq_show,
+       .stop  = smk_seq_stop,
 };
 
 /**
@@ -1405,23 +1382,14 @@ static void *load_self_seq_start(struct seq_file *s, loff_t *pos)
 {
        struct task_smack *tsp = current_security();
 
-       if (*pos == SEQ_READ_FINISHED)
-               return NULL;
-       if (list_empty(&tsp->smk_rules))
-               return NULL;
-       return tsp->smk_rules.next;
+       return smk_seq_start(s, pos, &tsp->smk_rules);
 }
 
 static void *load_self_seq_next(struct seq_file *s, void *v, loff_t *pos)
 {
        struct task_smack *tsp = current_security();
-       struct list_head *list = v;
 
-       if (list_is_last(list, &tsp->smk_rules)) {
-               *pos = SEQ_READ_FINISHED;
-               return NULL;
-       }
-       return list->next;
+       return smk_seq_next(s, v, pos, &tsp->smk_rules);
 }
 
 static int load_self_seq_show(struct seq_file *s, void *v)
@@ -1453,16 +1421,11 @@ static int load_self_seq_show(struct seq_file *s, void *v)
        return 0;
 }
 
-static void load_self_seq_stop(struct seq_file *s, void *v)
-{
-       /* No-op */
-}
-
 static const struct seq_operations load_self_seq_ops = {
        .start = load_self_seq_start,
        .next  = load_self_seq_next,
        .show  = load_self_seq_show,
-       .stop  = load_self_seq_stop,
+       .stop  = smk_seq_stop,
 };
 
 
index 5dbab38..130cfe6 100644 (file)
@@ -52,6 +52,7 @@ struct link_slave {
        struct link_ctl_info info;
        int vals[2];            /* current values */
        unsigned int flags;
+       struct snd_kcontrol *kctl; /* original kcontrol pointer */
        struct snd_kcontrol slave; /* the copy of original control entry */
 };
 
@@ -252,6 +253,7 @@ int _snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave,
                       slave->count * sizeof(*slave->vd), GFP_KERNEL);
        if (!srec)
                return -ENOMEM;
+       srec->kctl = slave;
        srec->slave = *slave;
        memcpy(srec->slave.vd, slave->vd, slave->count * sizeof(*slave->vd));
        srec->master = master_link;
@@ -333,10 +335,18 @@ static int master_put(struct snd_kcontrol *kcontrol,
 static void master_free(struct snd_kcontrol *kcontrol)
 {
        struct link_master *master = snd_kcontrol_chip(kcontrol);
-       struct link_slave *slave;
-
-       list_for_each_entry(slave, &master->slaves, list)
-               slave->master = NULL;
+       struct link_slave *slave, *n;
+
+       /* free all slave links and retore the original slave kctls */
+       list_for_each_entry_safe(slave, n, &master->slaves, list) {
+               struct snd_kcontrol *sctl = slave->kctl;
+               struct list_head olist = sctl->list;
+               memcpy(sctl, &slave->slave, sizeof(*sctl));
+               memcpy(sctl->vd, slave->slave.vd,
+                      sctl->count * sizeof(*sctl->vd));
+               sctl->list = olist; /* keep the current linked-list */
+               kfree(slave);
+       }
        kfree(master);
 }
 
index 916a186..e44b107 100644 (file)
@@ -2331,6 +2331,39 @@ int snd_hda_codec_reset(struct hda_codec *codec)
        return 0;
 }
 
+typedef int (*map_slave_func_t)(void *, struct snd_kcontrol *);
+
+/* apply the function to all matching slave ctls in the mixer list */
+static int map_slaves(struct hda_codec *codec, const char * const *slaves,
+                     map_slave_func_t func, void *data) 
+{
+       struct hda_nid_item *items;
+       const char * const *s;
+       int i, err;
+
+       items = codec->mixers.list;
+       for (i = 0; i < codec->mixers.used; i++) {
+               struct snd_kcontrol *sctl = items[i].kctl;
+               if (!sctl || !sctl->id.name ||
+                   sctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER)
+                       continue;
+               for (s = slaves; *s; s++) {
+                       if (!strcmp(sctl->id.name, *s)) {
+                               err = func(data, sctl);
+                               if (err)
+                                       return err;
+                               break;
+                       }
+               }
+       }
+       return 0;
+}
+
+static int check_slave_present(void *data, struct snd_kcontrol *sctl)
+{
+       return 1;
+}
+
 /**
  * snd_hda_add_vmaster - create a virtual master control and add slaves
  * @codec: HD-audio codec
@@ -2351,12 +2384,10 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
                        unsigned int *tlv, const char * const *slaves)
 {
        struct snd_kcontrol *kctl;
-       const char * const *s;
        int err;
 
-       for (s = slaves; *s && !snd_hda_find_mixer_ctl(codec, *s); s++)
-               ;
-       if (!*s) {
+       err = map_slaves(codec, slaves, check_slave_present, NULL);
+       if (err != 1) {
                snd_printdd("No slave found for %s\n", name);
                return 0;
        }
@@ -2367,23 +2398,10 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
        if (err < 0)
                return err;
 
-       for (s = slaves; *s; s++) {
-               struct snd_kcontrol *sctl;
-               int i = 0;
-               for (;;) {
-                       sctl = _snd_hda_find_mixer_ctl(codec, *s, i);
-                       if (!sctl) {
-                               if (!i)
-                                       snd_printdd("Cannot find slave %s, "
-                                                   "skipped\n", *s);
-                               break;
-                       }
-                       err = snd_ctl_add_slave(kctl, sctl);
-                       if (err < 0)
-                               return err;
-                       i++;
-               }
-       }
+       err = map_slaves(codec, slaves, (map_slave_func_t)snd_ctl_add_slave,
+                        kctl);
+       if (err < 0)
+               return err;
        return 0;
 }
 EXPORT_SYMBOL_HDA(snd_hda_add_vmaster);
@@ -4752,6 +4770,7 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
        memset(sequences_hp, 0, sizeof(sequences_hp));
        assoc_line_out = 0;
 
+       codec->ignore_misc_bit = true;
        end_nid = codec->start_nid + codec->num_nodes;
        for (nid = codec->start_nid; nid < end_nid; nid++) {
                unsigned int wid_caps = get_wcaps(codec, nid);
@@ -4767,6 +4786,9 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
                        continue;
 
                def_conf = snd_hda_codec_get_pincfg(codec, nid);
+               if (!(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) &
+                     AC_DEFCFG_MISC_NO_PRESENCE))
+                       codec->ignore_misc_bit = false;
                conn = get_defcfg_connect(def_conf);
                if (conn == AC_JACK_PORT_NONE)
                        continue;
index 755f2b0..5644711 100644 (file)
@@ -854,6 +854,7 @@ struct hda_codec {
        unsigned int no_sticky_stream:1; /* no sticky-PCM stream assignment */
        unsigned int pins_shutup:1;     /* pins are shut up */
        unsigned int no_trigger_sense:1; /* don't trigger at pin-sensing */
+       unsigned int ignore_misc_bit:1; /* ignore MISC_NO_PRESENCE bit */
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        unsigned int power_on :1;       /* current (global) power-state */
        unsigned int power_transition :1; /* power-state in transition */
index 1c8ddf5..7ae7578 100644 (file)
@@ -297,10 +297,18 @@ static int hdmi_update_eld(struct hdmi_eld *e,
                                        buf + ELD_FIXED_BYTES + mnl + 3 * i);
        }
 
+       /*
+        * HDMI sink's ELD info cannot always be retrieved for now, e.g.
+        * in console or for audio devices. Assume the highest speakers
+        * configuration, to _not_ prohibit multi-channel audio playback.
+        */
+       if (!e->spk_alloc)
+               e->spk_alloc = 0xffff;
+
+       e->eld_valid = true;
        return 0;
 
 out_fail:
-       e->eld_ver = 0;
        return -EINVAL;
 }
 
@@ -323,9 +331,6 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld,
         * ELD is valid, actual eld_size is assigned in hdmi_update_eld()
         */
 
-       if (!eld->eld_valid)
-               return -ENOENT;
-
        size = snd_hdmi_get_eld_size(codec, nid);
        if (size == 0) {
                /* wfg: workaround for ASUS P5E-VM HDMI board */
index dcbea0d..618ddad 100644 (file)
@@ -510,13 +510,15 @@ int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid);
 
 static inline bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid)
 {
-       return (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT) &&
-               /* disable MISC_NO_PRESENCE check because it may break too
-                * many devices
-                */
-               /*(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid) &
-                 AC_DEFCFG_MISC_NO_PRESENCE)) &&*/
-               (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP);
+       if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT))
+               return false;
+       if (!codec->ignore_misc_bit &&
+           (get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) &
+            AC_DEFCFG_MISC_NO_PRESENCE))
+               return false;
+       if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP))
+               return false;
+       return true;
 }
 
 /* flags for hda_nid_item */
@@ -651,6 +653,9 @@ struct hdmi_eld {
        int     spk_alloc;
        int     sad_count;
        struct cea_sad sad[ELD_MAX_SAD];
+       /*
+        * all fields above eld_buffer will be cleared before updating ELD
+        */
        char    eld_buffer[ELD_MAX_SIZE];
 #ifdef CONFIG_PROC_FS
        struct snd_info_entry *proc_entry;
index 2a2d864..2fbab8e 100644 (file)
@@ -237,6 +237,15 @@ static int cs_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
        return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
 }
 
+static void cs_update_input_select(struct hda_codec *codec)
+{
+       struct cs_spec *spec = codec->spec;
+       if (spec->cur_adc)
+               snd_hda_codec_write(codec, spec->cur_adc, 0,
+                                   AC_VERB_SET_CONNECT_SEL,
+                                   spec->adc_idx[spec->cur_input]);
+}
+
 /*
  * Analog capture
  */
@@ -250,6 +259,7 @@ static int cs_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
        spec->cur_adc = spec->adc_nid[spec->cur_input];
        spec->cur_adc_stream_tag = stream_tag;
        spec->cur_adc_format = format;
+       cs_update_input_select(codec);
        snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
        return 0;
 }
@@ -689,10 +699,8 @@ static int change_cur_input(struct hda_codec *codec, unsigned int idx,
                                           spec->cur_adc_stream_tag, 0,
                                           spec->cur_adc_format);
        }
-       snd_hda_codec_write(codec, spec->cur_adc, 0,
-                           AC_VERB_SET_CONNECT_SEL,
-                           spec->adc_idx[idx]);
        spec->cur_input = idx;
+       cs_update_input_select(codec);
        return 1;
 }
 
@@ -973,10 +981,7 @@ static void cs_automic(struct hda_codec *codec)
                } else  {
                        spec->cur_input = spec->last_input;
                }
-
-               snd_hda_codec_write_cache(codec, spec->cur_adc, 0,
-                                       AC_VERB_SET_CONNECT_SEL,
-                                       spec->adc_idx[spec->cur_input]);
+               cs_update_input_select(codec);
        } else {
                if (present)
                        change_cur_input(codec, spec->automic_idx, 0);
@@ -1073,9 +1078,7 @@ static void init_input(struct hda_codec *codec)
                        cs_automic(codec);
                else  {
                        spec->cur_adc = spec->adc_nid[spec->cur_input];
-                       snd_hda_codec_write(codec, spec->cur_adc, 0,
-                                       AC_VERB_SET_CONNECT_SEL,
-                                       spec->adc_idx[spec->cur_input]);
+                       cs_update_input_select(codec);
                }
        } else {
                change_cur_input(codec, spec->cur_input, 1);
index 5e706e4..0de2119 100644 (file)
@@ -3062,7 +3062,6 @@ static const struct snd_pci_quirk cxt5066_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x1993, "Asus U50F", CXT5066_ASUS),
        SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD),
        SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5),
-       SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5),
        SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board",
                      CXT5066_LAPTOP),
        SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5),
index 81b7b79..9850c5b 100644 (file)
@@ -65,7 +65,10 @@ struct hdmi_spec_per_pin {
        hda_nid_t pin_nid;
        int num_mux_nids;
        hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];
+
+       struct hda_codec *codec;
        struct hdmi_eld sink_eld;
+       struct delayed_work work;
 };
 
 struct hdmi_spec {
@@ -745,8 +748,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx,
  * Unsolicited events
  */
 
-static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid,
-                              struct hdmi_eld *eld);
+static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, bool retry);
 
 static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
 {
@@ -755,7 +757,6 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
        int pd = !!(res & AC_UNSOL_RES_PD);
        int eldv = !!(res & AC_UNSOL_RES_ELDV);
        int pin_idx;
-       struct hdmi_eld *eld;
 
        printk(KERN_INFO
                "HDMI hot plug event: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
@@ -764,17 +765,8 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
        pin_idx = pin_nid_to_pin_index(spec, pin_nid);
        if (pin_idx < 0)
                return;
-       eld = &spec->pins[pin_idx].sink_eld;
-
-       hdmi_present_sense(codec, pin_nid, eld);
 
-       /*
-        * HDMI sink's ELD info cannot always be retrieved for now, e.g.
-        * in console or for audio devices. Assume the highest speakers
-        * configuration, to _not_ prohibit multi-channel audio playback.
-        */
-       if (!eld->spk_alloc)
-               eld->spk_alloc = 0xffff;
+       hdmi_present_sense(&spec->pins[pin_idx], true);
 }
 
 static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
@@ -968,9 +960,11 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx)
        return 0;
 }
 
-static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid,
-                              struct hdmi_eld *eld)
+static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, bool retry)
 {
+       struct hda_codec *codec = per_pin->codec;
+       struct hdmi_eld *eld = &per_pin->sink_eld;
+       hda_nid_t pin_nid = per_pin->pin_nid;
        /*
         * Always execute a GetPinSense verb here, even when called from
         * hdmi_intrinsic_event; for some NVIDIA HW, the unsolicited
@@ -980,26 +974,39 @@ static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid,
         * the unsolicited response to avoid custom WARs.
         */
        int present = snd_hda_pin_sense(codec, pin_nid);
+       bool eld_valid = false;
 
-       memset(eld, 0, sizeof(*eld));
+       memset(eld, 0, offsetof(struct hdmi_eld, eld_buffer));
 
        eld->monitor_present    = !!(present & AC_PINSENSE_PRESENCE);
        if (eld->monitor_present)
-               eld->eld_valid  = !!(present & AC_PINSENSE_ELDV);
-       else
-               eld->eld_valid  = 0;
+               eld_valid       = !!(present & AC_PINSENSE_ELDV);
 
        printk(KERN_INFO
                "HDMI status: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
-               codec->addr, pin_nid, eld->monitor_present, eld->eld_valid);
+               codec->addr, pin_nid, eld->monitor_present, eld_valid);
 
-       if (eld->eld_valid)
+       if (eld_valid) {
                if (!snd_hdmi_get_eld(eld, codec, pin_nid))
                        snd_hdmi_show_eld(eld);
+               else if (retry) {
+                       queue_delayed_work(codec->bus->workq,
+                                          &per_pin->work,
+                                          msecs_to_jiffies(300));
+               }
+       }
 
        snd_hda_input_jack_report(codec, pin_nid);
 }
 
+static void hdmi_repoll_eld(struct work_struct *work)
+{
+       struct hdmi_spec_per_pin *per_pin =
+       container_of(to_delayed_work(work), struct hdmi_spec_per_pin, work);
+
+       hdmi_present_sense(per_pin, false);
+}
+
 static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
 {
        struct hdmi_spec *spec = codec->spec;
@@ -1228,7 +1235,7 @@ static int generic_hdmi_build_jack(struct hda_codec *codec, int pin_idx)
        if (err < 0)
                return err;
 
-       hdmi_present_sense(codec, per_pin->pin_nid, &per_pin->sink_eld);
+       hdmi_present_sense(per_pin, false);
        return 0;
 }
 
@@ -1279,6 +1286,8 @@ static int generic_hdmi_init(struct hda_codec *codec)
                                    AC_VERB_SET_UNSOLICITED_ENABLE,
                                    AC_USRSP_EN | pin_nid);
 
+               per_pin->codec = codec;
+               INIT_DELAYED_WORK(&per_pin->work, hdmi_repoll_eld);
                snd_hda_eld_proc_new(codec, eld, pin_idx);
        }
        return 0;
@@ -1293,10 +1302,12 @@ static void generic_hdmi_free(struct hda_codec *codec)
                struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
                struct hdmi_eld *eld = &per_pin->sink_eld;
 
+               cancel_delayed_work(&per_pin->work);
                snd_hda_eld_proc_free(codec, eld);
        }
        snd_hda_input_jack_free(codec);
 
+       flush_workqueue(codec->bus->workq);
        kfree(spec);
 }
 
index a24e068..336d14e 100644 (file)
@@ -284,7 +284,7 @@ static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx,
        struct alc_spec *spec = codec->spec;
        const struct hda_input_mux *imux;
        unsigned int mux_idx;
-       int i, type;
+       int i, type, num_conns;
        hda_nid_t nid;
 
        mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
@@ -307,16 +307,17 @@ static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx,
                spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
 
        /* no selection? */
-       if (snd_hda_get_conn_list(codec, nid, NULL) <= 1)
+       num_conns = snd_hda_get_conn_list(codec, nid, NULL);
+       if (num_conns <= 1)
                return 1;
 
        type = get_wcaps_type(get_wcaps(codec, nid));
        if (type == AC_WID_AUD_MIX) {
                /* Matrix-mixer style (e.g. ALC882) */
-               for (i = 0; i < imux->num_items; i++) {
-                       unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
-                       snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
-                                                imux->items[i].index,
+               int active = imux->items[idx].index;
+               for (i = 0; i < num_conns; i++) {
+                       unsigned int v = (i == active) ? 0 : HDA_AMP_MUTE;
+                       snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, i,
                                                 HDA_AMP_MUTE, v);
                }
        } else {
@@ -1451,7 +1452,7 @@ static void alc_apply_fixup(struct hda_codec *codec, int action)
                switch (fix->type) {
                case ALC_FIXUP_SKU:
                        if (action != ALC_FIXUP_ACT_PRE_PROBE || !fix->v.sku)
-                               break;;
+                               break;
                        snd_printdd(KERN_INFO "hda_codec: %s: "
                                    "Apply sku override for %s\n",
                                    codec->chip_name, modelname);
index 4e715fe..470f6f2 100644 (file)
@@ -95,6 +95,7 @@ enum {
        STAC_92HD83XXX_REF,
        STAC_92HD83XXX_PWR_REF,
        STAC_DELL_S14,
+       STAC_DELL_VOSTRO_3500,
        STAC_92HD83XXX_HP,
        STAC_92HD83XXX_HP_cNB11_INTQUAD,
        STAC_HP_DV7_4000,
@@ -226,7 +227,6 @@ struct sigmatel_spec {
 
        /* power management */
        unsigned int num_pwrs;
-       const unsigned int *pwr_mapping;
        const hda_nid_t *pwr_nids;
        const hda_nid_t *dac_list;
 
@@ -373,18 +373,15 @@ static const unsigned long stac92hd73xx_capvols[] = {
 
 #define STAC92HD83_DAC_COUNT 3
 
-static const hda_nid_t stac92hd83xxx_pwr_nids[4] = {
-       0xa, 0xb, 0xd, 0xe,
+static const hda_nid_t stac92hd83xxx_pwr_nids[7] = {
+       0x0a, 0x0b, 0x0c, 0xd, 0x0e,
+       0x0f, 0x10
 };
 
 static const hda_nid_t stac92hd83xxx_slave_dig_outs[2] = {
        0x1e, 0,
 };
 
-static const unsigned int stac92hd83xxx_pwr_mapping[4] = {
-       0x03, 0x0c, 0x20, 0x40,
-};
-
 static const hda_nid_t stac92hd83xxx_dmic_nids[] = {
                0x11, 0x20,
 };
@@ -1659,6 +1656,12 @@ static const unsigned int dell_s14_pin_configs[10] = {
        0x40f000f0, 0x40f000f0,
 };
 
+static const unsigned int dell_vostro_3500_pin_configs[10] = {
+       0x02a11020, 0x0221101f, 0x400000f0, 0x90170110,
+       0x400000f1, 0x400000f2, 0x400000f3, 0x90a60160,
+       0x400000f4, 0x400000f5,
+};
+
 static const unsigned int hp_dv7_4000_pin_configs[10] = {
        0x03a12050, 0x0321201f, 0x40f000f0, 0x90170110,
        0x40f000f0, 0x40f000f0, 0x90170110, 0xd5a30140,
@@ -1675,6 +1678,7 @@ static const unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = {
        [STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs,
        [STAC_92HD83XXX_PWR_REF] = ref92hd83xxx_pin_configs,
        [STAC_DELL_S14] = dell_s14_pin_configs,
+       [STAC_DELL_VOSTRO_3500] = dell_vostro_3500_pin_configs,
        [STAC_92HD83XXX_HP_cNB11_INTQUAD] = hp_cNB11_intquad_pin_configs,
        [STAC_HP_DV7_4000] = hp_dv7_4000_pin_configs,
 };
@@ -1684,6 +1688,7 @@ static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
        [STAC_92HD83XXX_REF] = "ref",
        [STAC_92HD83XXX_PWR_REF] = "mic-ref",
        [STAC_DELL_S14] = "dell-s14",
+       [STAC_DELL_VOSTRO_3500] = "dell-vostro-3500",
        [STAC_92HD83XXX_HP] = "hp",
        [STAC_92HD83XXX_HP_cNB11_INTQUAD] = "hp_cNB11_intquad",
        [STAC_HP_DV7_4000] = "hp-dv7-4000",
@@ -1697,6 +1702,8 @@ static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
                      "DFI LanParty", STAC_92HD83XXX_REF),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ba,
                      "unknown Dell", STAC_DELL_S14),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x1028,
+                     "Dell Vostro 3500", STAC_DELL_VOSTRO_3500),
        SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x3600,
                          "HP", STAC_92HD83XXX_HP),
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1656,
@@ -4459,8 +4466,12 @@ static int stac92xx_init(struct hda_codec *codec)
                                stac_toggle_power_map(codec, nid, 1);
                        continue;
                }
-               if (enable_pin_detect(codec, nid, STAC_PWR_EVENT))
+               if (enable_pin_detect(codec, nid, STAC_PWR_EVENT)) {
                        stac_issue_unsol_event(codec, nid);
+                       continue;
+               }
+               /* none of the above, turn the port OFF */
+               stac_toggle_power_map(codec, nid, 0);
        }
 
        /* sync mute LED */
@@ -4716,11 +4727,7 @@ static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid,
        if (idx >= spec->num_pwrs)
                return;
 
-       /* several codecs have two power down bits */
-       if (spec->pwr_mapping)
-               idx = spec->pwr_mapping[idx];
-       else
-               idx = 1 << idx;
+       idx = 1 << idx;
 
        val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0) & 0xff;
        if (enable)
@@ -5618,9 +5625,6 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
                snd_hda_codec_set_pincfg(codec, 0xf, 0x2181205e);
        }
 
-       /* reset pin power-down; Windows may leave these bits after reboot */
-       snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7EC, 0);
-       snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7ED, 0);
        codec->no_trigger_sense = 1;
        codec->spec = spec;
 
@@ -5630,7 +5634,6 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
        codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs;
        spec->digbeep_nid = 0x21;
        spec->pwr_nids = stac92hd83xxx_pwr_nids;
-       spec->pwr_mapping = stac92hd83xxx_pwr_mapping;
        spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids);
        spec->multiout.dac_nids = spec->dac_nids;
        spec->init = stac92hd83xxx_core_init;
@@ -5647,9 +5650,6 @@ again:
                stac92xx_set_config_regs(codec,
                                stac92hd83xxx_brd_tbl[spec->board_config]);
 
-       if (spec->board_config != STAC_92HD83XXX_PWR_REF)
-               spec->num_pwrs = 0;
-
        codec->patch_ops = stac92xx_patch_ops;
 
        if (find_mute_led_gpio(codec, 0))
@@ -5858,8 +5858,6 @@ again:
                    (codec->revision_id & 0xf) == 1)
                        spec->stream_delay = 40; /* 40 milliseconds */
 
-               /* no output amps */
-               spec->num_pwrs = 0;
                /* disable VSW */
                spec->init = stac92hd71bxx_core_init;
                unmute_init++;
@@ -5874,8 +5872,6 @@ again:
                if ((codec->revision_id & 0xf) == 1)
                        spec->stream_delay = 40; /* 40 milliseconds */
 
-               /* no output amps */
-               spec->num_pwrs = 0;
                /* fallthru */
        default:
                spec->init = stac92hd71bxx_core_init;
index 29e3125..11718b4 100644 (file)
@@ -1077,6 +1077,13 @@ static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(struct snd_pcm_substream *subs
                }
                if (civ != igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV))
                        continue;
+
+               /* IO read operation is very expensive inside virtual machine
+                * as it is emulated. The probability that subsequent PICB read
+                * will return different result is high enough to loop till
+                * timeout here.
+                * Same CIV is strict enough condition to be sure that PICB
+                * is valid inside VM on emulated card. */
                if (chip->inside_vm)
                        break;
                if (ptr1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb))
@@ -2930,6 +2937,45 @@ static unsigned int sis_codec_bits[3] = {
        ICH_PCR, ICH_SCR, ICH_SIS_TCR
 };
 
+static int __devinit snd_intel8x0_inside_vm(struct pci_dev *pci)
+{
+       int result  = inside_vm;
+       char *msg   = NULL;
+
+       /* check module parameter first (override detection) */
+       if (result >= 0) {
+               msg = result ? "enable (forced) VM" : "disable (forced) VM";
+               goto fini;
+       }
+
+       /* detect KVM and Parallels virtual environments */
+       result = kvm_para_available();
+#ifdef X86_FEATURE_HYPERVISOR
+       result = result || boot_cpu_has(X86_FEATURE_HYPERVISOR);
+#endif
+       if (!result)
+               goto fini;
+
+       /* check for known (emulated) devices */
+       if (pci->subsystem_vendor == 0x1af4 &&
+           pci->subsystem_device == 0x1100) {
+               /* KVM emulated sound, PCI SSID: 1af4:1100 */
+               msg = "enable KVM";
+       } else if (pci->subsystem_vendor == 0x1ab8) {
+               /* Parallels VM emulated sound, PCI SSID: 1ab8:xxxx */
+               msg = "enable Parallels VM";
+       } else {
+               msg = "disable (unknown or VT-d) VM";
+               result = 0;
+       }
+
+fini:
+       if (msg != NULL)
+               printk(KERN_INFO "intel8x0: %s optimization\n", msg);
+
+       return result;
+}
+
 static int __devinit snd_intel8x0_create(struct snd_card *card,
                                         struct pci_dev *pci,
                                         unsigned long device_type,
@@ -2997,9 +3043,7 @@ static int __devinit snd_intel8x0_create(struct snd_card *card,
        if (xbox)
                chip->xbox = 1;
 
-       chip->inside_vm = inside_vm;
-       if (inside_vm)
-               printk(KERN_INFO "intel8x0: enable KVM optimization\n");
+       chip->inside_vm = snd_intel8x0_inside_vm(pci);
 
        if (pci->vendor == PCI_VENDOR_ID_INTEL &&
            pci->device == PCI_DEVICE_ID_INTEL_440MX)
@@ -3243,14 +3287,6 @@ static int __devinit snd_intel8x0_probe(struct pci_dev *pci,
                        buggy_irq = 0;
        }
 
-       if (inside_vm < 0) {
-               /* detect KVM and Parallels virtual environments */
-               inside_vm = kvm_para_available();
-#if defined(__i386__) || defined(__x86_64__)
-               inside_vm = inside_vm || boot_cpu_has(X86_FEATURE_HYPERVISOR);
-#endif
-       }
-
        if ((err = snd_intel8x0_create(card, pci, pci_id->driver_data,
                                       &chip)) < 0) {
                snd_card_free(card);
index a3ce1b2..1aa52ef 100644 (file)
@@ -876,7 +876,7 @@ static void __devinit snd_ps3_audio_set_base_addr(uint64_t ioaddr_start)
                (0x0fUL << 12) |
                (PS3_AUDIO_IOID);
 
-       ret = lv1_gpu_attribute(0x100, 0x007, val, 0, 0);
+       ret = lv1_gpu_attribute(0x100, 0x007, val);
        if (ret)
                pr_info("%s: gpu_attribute failed %d\n", __func__,
                        ret);
index 6b73efd..9c982e4 100644 (file)
@@ -56,7 +56,7 @@ static int wm8994_retune_mobile_base[] = {
 static int wm8994_readable(struct snd_soc_codec *codec, unsigned int reg)
 {
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-       struct wm8994 *control = wm8994->control_data;
+       struct wm8994 *control = codec->control_data;
 
        switch (reg) {
        case WM8994_GPIO_1:
@@ -3030,19 +3030,34 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
 {
        struct wm8994_priv *wm8994 = data;
        struct snd_soc_codec *codec = wm8994->codec;
-       int reg;
+       int reg, count;
 
-       reg = snd_soc_read(codec, WM8958_MIC_DETECT_3);
-       if (reg < 0) {
-               dev_err(codec->dev, "Failed to read mic detect status: %d\n",
-                       reg);
-               return IRQ_NONE;
-       }
+       /* We may occasionally read a detection without an impedence
+        * range being provided - if that happens loop again.
+        */
+       count = 10;
+       do {
+               reg = snd_soc_read(codec, WM8958_MIC_DETECT_3);
+               if (reg < 0) {
+                       dev_err(codec->dev,
+                               "Failed to read mic detect status: %d\n",
+                               reg);
+                       return IRQ_NONE;
+               }
 
-       if (!(reg & WM8958_MICD_VALID)) {
-               dev_dbg(codec->dev, "Mic detect data not valid\n");
-               goto out;
-       }
+               if (!(reg & WM8958_MICD_VALID)) {
+                       dev_dbg(codec->dev, "Mic detect data not valid\n");
+                       goto out;
+               }
+
+               if (!(reg & WM8958_MICD_STS) || (reg & WM8958_MICD_LVL_MASK))
+                       break;
+
+               msleep(1);
+       } while (count--);
+
+       if (count == 0)
+               dev_warn(codec->dev, "No impedence range reported for jack\n");
 
 #ifndef CONFIG_SND_SOC_WM8994_MODULE
        trace_snd_soc_jack_irq(dev_name(codec->dev));
@@ -3180,9 +3195,9 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 
        wm8994_request_irq(codec->control_data, WM8994_IRQ_FIFOS_ERR,
                           wm8994_fifo_error, "FIFO error", codec);
-       wm8994_request_irq(wm8994->control_data, WM8994_IRQ_TEMP_WARN,
+       wm8994_request_irq(codec->control_data, WM8994_IRQ_TEMP_WARN,
                           wm8994_temp_warn, "Thermal warning", codec);
-       wm8994_request_irq(wm8994->control_data, WM8994_IRQ_TEMP_SHUT,
+       wm8994_request_irq(codec->control_data, WM8994_IRQ_TEMP_SHUT,
                           wm8994_temp_shut, "Thermal shutdown", codec);
 
        ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_DCS_DONE,
index 60f65ac..ab23869 100644 (file)
@@ -765,10 +765,61 @@ static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
  * interface to ALSA control for feature/mixer units
  */
 
+/* volume control quirks */
+static void volume_control_quirks(struct usb_mixer_elem_info *cval,
+                                 struct snd_kcontrol *kctl)
+{
+       switch (cval->mixer->chip->usb_id) {
+       case USB_ID(0x0471, 0x0101):
+       case USB_ID(0x0471, 0x0104):
+       case USB_ID(0x0471, 0x0105):
+       case USB_ID(0x0672, 0x1041):
+       /* quirk for UDA1321/N101.
+        * note that detection between firmware 2.1.1.7 (N101)
+        * and later 2.1.1.21 is not very clear from datasheets.
+        * I hope that the min value is -15360 for newer firmware --jk
+        */
+               if (!strcmp(kctl->id.name, "PCM Playback Volume") &&
+                   cval->min == -15616) {
+                       snd_printk(KERN_INFO
+                                "set volume quirk for UDA1321/N101 chip\n");
+                       cval->max = -256;
+               }
+               break;
+
+       case USB_ID(0x046d, 0x09a4):
+               if (!strcmp(kctl->id.name, "Mic Capture Volume")) {
+                       snd_printk(KERN_INFO
+                               "set volume quirk for QuickCam E3500\n");
+                       cval->min = 6080;
+                       cval->max = 8768;
+                       cval->res = 192;
+               }
+               break;
+
+       case USB_ID(0x046d, 0x0808):
+       case USB_ID(0x046d, 0x0809):
+       case USB_ID(0x046d, 0x081d): /* HD Webcam c510 */
+       case USB_ID(0x046d, 0x0991):
+       /* Most audio usb devices lie about volume resolution.
+        * Most Logitech webcams have res = 384.
+        * Proboly there is some logitech magic behind this number --fishor
+        */
+               if (!strcmp(kctl->id.name, "Mic Capture Volume")) {
+                       snd_printk(KERN_INFO
+                               "set resolution quirk: cval->res = 384\n");
+                       cval->res = 384;
+               }
+               break;
+
+       }
+}
+
 /*
  * retrieve the minimum and maximum values for the specified control
  */
-static int get_min_max(struct usb_mixer_elem_info *cval, int default_min)
+static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
+                                  int default_min, struct snd_kcontrol *kctl)
 {
        /* for failsafe */
        cval->min = default_min;
@@ -844,6 +895,9 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min)
                cval->initialized = 1;
        }
 
+       if (kctl)
+               volume_control_quirks(cval, kctl);
+
        /* USB descriptions contain the dB scale in 1/256 dB unit
         * while ALSA TLV contains in 1/100 dB unit
         */
@@ -864,6 +918,7 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min)
        return 0;
 }
 
+#define get_min_max(cval, def) get_min_max_with_quirks(cval, def, NULL)
 
 /* get a feature/mixer unit info */
 static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
@@ -882,7 +937,7 @@ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol, struct snd_ctl_
                uinfo->value.integer.max = 1;
        } else {
                if (!cval->initialized) {
-                       get_min_max(cval, 0);
+                       get_min_max_with_quirks(cval, 0, kcontrol);
                        if (cval->initialized && cval->dBmin >= cval->dBmax) {
                                kcontrol->vd[0].access &= 
                                        ~(SNDRV_CTL_ELEM_ACCESS_TLV_READ |
@@ -1045,9 +1100,6 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
                cval->ch_readonly = readonly_mask;
        }
 
-       /* get min/max values */
-       get_min_max(cval, 0);
-
        /* if all channels in the mask are marked read-only, make the control
         * read-only. set_cur_mix_value() will check the mask again and won't
         * issue write commands to read-only channels. */
@@ -1069,6 +1121,9 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
                len = snd_usb_copy_string_desc(state, nameid,
                                kctl->id.name, sizeof(kctl->id.name));
 
+       /* get min/max values */
+       get_min_max_with_quirks(cval, 0, kctl);
+
        switch (control) {
        case UAC_FU_MUTE:
        case UAC_FU_VOLUME:
@@ -1118,51 +1173,6 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
                break;
        }
 
-       /* volume control quirks */
-       switch (state->chip->usb_id) {
-       case USB_ID(0x0471, 0x0101):
-       case USB_ID(0x0471, 0x0104):
-       case USB_ID(0x0471, 0x0105):
-       case USB_ID(0x0672, 0x1041):
-       /* quirk for UDA1321/N101.
-        * note that detection between firmware 2.1.1.7 (N101)
-        * and later 2.1.1.21 is not very clear from datasheets.
-        * I hope that the min value is -15360 for newer firmware --jk
-        */
-               if (!strcmp(kctl->id.name, "PCM Playback Volume") &&
-                   cval->min == -15616) {
-                       snd_printk(KERN_INFO
-                                "set volume quirk for UDA1321/N101 chip\n");
-                       cval->max = -256;
-               }
-               break;
-
-       case USB_ID(0x046d, 0x09a4):
-               if (!strcmp(kctl->id.name, "Mic Capture Volume")) {
-                       snd_printk(KERN_INFO
-                               "set volume quirk for QuickCam E3500\n");
-                       cval->min = 6080;
-                       cval->max = 8768;
-                       cval->res = 192;
-               }
-               break;
-
-       case USB_ID(0x046d, 0x0808):
-       case USB_ID(0x046d, 0x0809):
-       case USB_ID(0x046d, 0x0991):
-       /* Most audio usb devices lie about volume resolution.
-        * Most Logitech webcams have res = 384.
-        * Proboly there is some logitech magic behind this number --fishor
-        */
-               if (!strcmp(kctl->id.name, "Mic Capture Volume")) {
-                       snd_printk(KERN_INFO
-                               "set resolution quirk: cval->res = 384\n");
-                       cval->res = 384;
-               }
-               break;
-
-       }
-
        range = (cval->max - cval->min) / cval->res;
        /* Are there devices with volume range more than 255? I use a bit more
         * to be sure. 384 is a resolution magic number found on Logitech
index 2e5bc73..a3ddac0 100644 (file)
@@ -137,12 +137,12 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
                return -ENOMEM;
        }
        if (fp->nr_rates > 0) {
-               rate_table = kmalloc(sizeof(int) * fp->nr_rates, GFP_KERNEL);
+               rate_table = kmemdup(fp->rate_table,
+                                    sizeof(int) * fp->nr_rates, GFP_KERNEL);
                if (!rate_table) {
                        kfree(fp);
                        return -ENOMEM;
                }
-               memcpy(rate_table, fp->rate_table, sizeof(int) * fp->nr_rates);
                fp->rate_table = rate_table;
        }
 
@@ -224,10 +224,9 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip,
        if (altsd->bNumEndpoints != 1)
                return -ENXIO;
 
-       fp = kmalloc(sizeof(*fp), GFP_KERNEL);
+       fp = kmemdup(&ua_format, sizeof(*fp), GFP_KERNEL);
        if (!fp)
                return -ENOMEM;
-       memcpy(fp, &ua_format, sizeof(*fp));
 
        fp->iface = altsd->bInterfaceNumber;
        fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
index 8d02ccb..30e2bef 100755 (executable)
@@ -42,6 +42,7 @@ $default{"BISECT_MANUAL"}     = 0;
 $default{"BISECT_SKIP"}                = 1;
 $default{"SUCCESS_LINE"}       = "login:";
 $default{"DETECT_TRIPLE_FAULT"} = 1;
+$default{"NO_INSTALL"}         = 0;
 $default{"BOOTED_TIMEOUT"}     = 1;
 $default{"DIE_ON_FAILURE"}     = 1;
 $default{"SSH_EXEC"}           = "ssh \$SSH_USER\@\$MACHINE \$SSH_COMMAND";
@@ -84,6 +85,7 @@ my $grub_number;
 my $target;
 my $make;
 my $post_install;
+my $no_install;
 my $noclean;
 my $minconfig;
 my $start_minconfig;
@@ -115,6 +117,7 @@ my $timeout;
 my $booted_timeout;
 my $detect_triplefault;
 my $console;
+my $reboot_success_line;
 my $success_line;
 my $stop_after_success;
 my $stop_after_failure;
@@ -130,6 +133,12 @@ my %config_help;
 my %variable;
 my %force_config;
 
+# do not force reboots on config problems
+my $no_reboot = 1;
+
+# default variables that can be used
+chomp ($variable{"PWD"} = `pwd`);
+
 $config_help{"MACHINE"} = << "EOF"
  The machine hostname that you will test.
 EOF
@@ -241,6 +250,7 @@ sub read_yn {
 
 sub get_ktest_config {
     my ($config) = @_;
+    my $ans;
 
     return if (defined($opt{$config}));
 
@@ -254,16 +264,17 @@ sub get_ktest_config {
        if (defined($default{$config})) {
            print "\[$default{$config}\] ";
        }
-       $entered_configs{$config} = <STDIN>;
-       $entered_configs{$config} =~ s/^\s*(.*\S)\s*$/$1/;
-       if ($entered_configs{$config} =~ /^\s*$/) {
+       $ans = <STDIN>;
+       $ans =~ s/^\s*(.*\S)\s*$/$1/;
+       if ($ans =~ /^\s*$/) {
            if ($default{$config}) {
-               $entered_configs{$config} = $default{$config};
+               $ans = $default{$config};
            } else {
                print "Your answer can not be blank\n";
                next;
            }
        }
+       $entered_configs{$config} = process_variables($ans);
        last;
     }
 }
@@ -298,7 +309,7 @@ sub get_ktest_configs {
 }
 
 sub process_variables {
-    my ($value) = @_;
+    my ($value, $remove_undef) = @_;
     my $retval = "";
 
     # We want to check for '\', and it is just easier
@@ -316,6 +327,10 @@ sub process_variables {
        $retval = "$retval$begin";
        if (defined($variable{$var})) {
            $retval = "$retval$variable{$var}";
+       } elsif (defined($remove_undef) && $remove_undef) {
+           # for if statements, any variable that is not defined,
+           # we simple convert to 0
+           $retval = "${retval}0";
        } else {
            # put back the origin piece.
            $retval = "$retval\$\{$var\}";
@@ -331,10 +346,17 @@ sub process_variables {
 }
 
 sub set_value {
-    my ($lvalue, $rvalue) = @_;
+    my ($lvalue, $rvalue, $override, $overrides, $name) = @_;
 
     if (defined($opt{$lvalue})) {
-       die "Error: Option $lvalue defined more than once!\n";
+       if (!$override || defined(${$overrides}{$lvalue})) {
+           my $extra = "";
+           if ($override) {
+               $extra = "In the same override section!\n";
+           }
+           die "$name: $.: Option $lvalue defined more than once!\n$extra";
+       }
+       ${$overrides}{$lvalue} = $rvalue;
     }
     if ($rvalue =~ /^\s*$/) {
        delete $opt{$lvalue};
@@ -355,86 +377,274 @@ sub set_variable {
     }
 }
 
-sub read_config {
-    my ($config) = @_;
+sub process_compare {
+    my ($lval, $cmp, $rval) = @_;
+
+    # remove whitespace
+
+    $lval =~ s/^\s*//;
+    $lval =~ s/\s*$//;
+
+    $rval =~ s/^\s*//;
+    $rval =~ s/\s*$//;
+
+    if ($cmp eq "==") {
+       return $lval eq $rval;
+    } elsif ($cmp eq "!=") {
+       return $lval ne $rval;
+    }
+
+    my $statement = "$lval $cmp $rval";
+    my $ret = eval $statement;
+
+    # $@ stores error of eval
+    if ($@) {
+       return -1;
+    }
+
+    return $ret;
+}
+
+sub value_defined {
+    my ($val) = @_;
+
+    return defined($variable{$2}) ||
+       defined($opt{$2});
+}
+
+my $d = 0;
+sub process_expression {
+    my ($name, $val) = @_;
+
+    my $c = $d++;
+
+    while ($val =~ s/\(([^\(]*?)\)/\&\&\&\&VAL\&\&\&\&/) {
+       my $express = $1;
+
+       if (process_expression($name, $express)) {
+           $val =~ s/\&\&\&\&VAL\&\&\&\&/ 1 /;
+       } else {
+           $val =~ s/\&\&\&\&VAL\&\&\&\&/ 0 /;
+       }
+    }
+
+    $d--;
+    my $OR = "\\|\\|";
+    my $AND = "\\&\\&";
+
+    while ($val =~ s/^(.*?)($OR|$AND)//) {
+       my $express = $1;
+       my $op = $2;
+
+       if (process_expression($name, $express)) {
+           if ($op eq "||") {
+               return 1;
+           }
+       } else {
+           if ($op eq "&&") {
+               return 0;
+           }
+       }
+    }
+
+    if ($val =~ /(.*)(==|\!=|>=|<=|>|<)(.*)/) {
+       my $ret = process_compare($1, $2, $3);
+       if ($ret < 0) {
+           die "$name: $.: Unable to process comparison\n";
+       }
+       return $ret;
+    }
+
+    if ($val =~ /^\s*(NOT\s*)?DEFINED\s+(\S+)\s*$/) {
+       if (defined $1) {
+           return !value_defined($2);
+       } else {
+           return value_defined($2);
+       }
+    }
+
+    if ($val =~ /^\s*0\s*$/) {
+       return 0;
+    } elsif ($val =~ /^\s*\d+\s*$/) {
+       return 1;
+    }
+
+    die ("$name: $.: Undefined content $val in if statement\n");
+}
+
+sub process_if {
+    my ($name, $value) = @_;
+
+    # Convert variables and replace undefined ones with 0
+    my $val = process_variables($value, 1);
+    my $ret = process_expression $name, $val;
+
+    return $ret;
+}
 
-    open(IN, $config) || die "can't read file $config";
+sub __read_config {
+    my ($config, $current_test_num) = @_;
+
+    my $in;
+    open($in, $config) || die "can't read file $config";
 
     my $name = $config;
     $name =~ s,.*/(.*),$1,;
 
-    my $test_num = 0;
+    my $test_num = $$current_test_num;
     my $default = 1;
     my $repeat = 1;
     my $num_tests_set = 0;
     my $skip = 0;
     my $rest;
+    my $line;
     my $test_case = 0;
+    my $if = 0;
+    my $if_set = 0;
+    my $override = 0;
 
-    while (<IN>) {
+    my %overrides;
+
+    while (<$in>) {
 
        # ignore blank lines and comments
        next if (/^\s*$/ || /\s*\#/);
 
-       if (/^\s*TEST_START(.*)/) {
+       if (/^\s*(TEST_START|DEFAULTS)\b(.*)/) {
 
-           $rest = $1;
+           my $type = $1;
+           $rest = $2;
+           $line = $2;
 
-           if ($num_tests_set) {
-               die "$name: $.: Can not specify both NUM_TESTS and TEST_START\n";
-           }
+           my $old_test_num;
+           my $old_repeat;
+           $override = 0;
+
+           if ($type eq "TEST_START") {
+
+               if ($num_tests_set) {
+                   die "$name: $.: Can not specify both NUM_TESTS and TEST_START\n";
+               }
 
-           my $old_test_num = $test_num;
-           my $old_repeat = $repeat;
+               $old_test_num = $test_num;
+               $old_repeat = $repeat;
 
-           $test_num += $repeat;
-           $default = 0;
-           $repeat = 1;
+               $test_num += $repeat;
+               $default = 0;
+               $repeat = 1;
+           } else {
+               $default = 1;
+           }
 
-           if ($rest =~ /\s+SKIP(.*)/) {
-               $rest = $1;
+           # If SKIP is anywhere in the line, the command will be skipped
+           if ($rest =~ s/\s+SKIP\b//) {
                $skip = 1;
            } else {
                $test_case = 1;
                $skip = 0;
            }
 
-           if ($rest =~ /\s+ITERATE\s+(\d+)(.*)$/) {
-               $repeat = $1;
-               $rest = $2;
-               $repeat_tests{"$test_num"} = $repeat;
+           if ($rest =~ s/\sELSE\b//) {
+               if (!$if) {
+                   die "$name: $.: ELSE found with out matching IF section\n$_";
+               }
+               $if = 0;
+
+               if ($if_set) {
+                   $skip = 1;
+               } else {
+                   $skip = 0;
+               }
            }
 
-           if ($rest =~ /\s+SKIP(.*)/) {
-               $rest = $1;
-               $skip = 1;
+           if ($rest =~ s/\sIF\s+(.*)//) {
+               if (process_if($name, $1)) {
+                   $if_set = 1;
+               } else {
+                   $skip = 1;
+               }
+               $if = 1;
+           } else {
+               $if = 0;
+               $if_set = 0;
            }
 
-           if ($rest !~ /^\s*$/) {
-               die "$name: $.: Gargbage found after TEST_START\n$_";
+           if (!$skip) {
+               if ($type eq "TEST_START") {
+                   if ($rest =~ s/\s+ITERATE\s+(\d+)//) {
+                       $repeat = $1;
+                       $repeat_tests{"$test_num"} = $repeat;
+                   }
+               } elsif ($rest =~ s/\sOVERRIDE\b//) {
+                   # DEFAULT only
+                   $override = 1;
+                   # Clear previous overrides
+                   %overrides = ();
+               }
+           }
+
+           if (!$skip && $rest !~ /^\s*$/) {
+               die "$name: $.: Gargbage found after $type\n$_";
            }
 
-           if ($skip) {
+           if ($skip && $type eq "TEST_START") {
                $test_num = $old_test_num;
                $repeat = $old_repeat;
            }
 
-       } elsif (/^\s*DEFAULTS(.*)$/) {
-           $default = 1;
-
+       } elsif (/^\s*ELSE\b(.*)$/) {
+           if (!$if) {
+               die "$name: $.: ELSE found with out matching IF section\n$_";
+           }
            $rest = $1;
-
-           if ($rest =~ /\s+SKIP(.*)/) {
-               $rest = $1;
+           if ($if_set) {
                $skip = 1;
+               $rest = "";
            } else {
                $skip = 0;
+
+               if ($rest =~ /\sIF\s+(.*)/) {
+                   # May be a ELSE IF section.
+                   if (!process_if($name, $1)) {
+                       $skip = 1;
+                   }
+                   $rest = "";
+               } else {
+                   $if = 0;
+               }
            }
 
            if ($rest !~ /^\s*$/) {
                die "$name: $.: Gargbage found after DEFAULTS\n$_";
            }
 
+       } elsif (/^\s*INCLUDE\s+(\S+)/) {
+
+           next if ($skip);
+
+           if (!$default) {
+               die "$name: $.: INCLUDE can only be done in default sections\n$_";
+           }
+
+           my $file = process_variables($1);
+
+           if ($file !~ m,^/,) {
+               # check the path of the config file first
+               if ($config =~ m,(.*)/,) {
+                   if (-f "$1/$file") {
+                       $file = "$1/$file";
+                   }
+               }
+           }
+               
+           if ( ! -r $file ) {
+               die "$name: $.: Can't read file $file\n$_";
+           }
+
+           if (__read_config($file, \$test_num)) {
+               $test_case = 1;
+           }
+
        } elsif (/^\s*([A-Z_\[\]\d]+)\s*=\s*(.*?)\s*$/) {
 
            next if ($skip);
@@ -460,10 +670,10 @@ sub read_config {
            }
 
            if ($default || $lvalue =~ /\[\d+\]$/) {
-               set_value($lvalue, $rvalue);
+               set_value($lvalue, $rvalue, $override, \%overrides, $name);
            } else {
                my $val = "$lvalue\[$test_num\]";
-               set_value($val, $rvalue);
+               set_value($val, $rvalue, $override, \%overrides, $name);
 
                if ($repeat > 1) {
                    $repeats{$val} = $repeat;
@@ -490,13 +700,26 @@ sub read_config {
        }
     }
 
-    close(IN);
-
     if ($test_num) {
        $test_num += $repeat - 1;
        $opt{"NUM_TESTS"} = $test_num;
     }
 
+    close($in);
+
+    $$current_test_num = $test_num;
+
+    return $test_case;
+}
+
+sub read_config {
+    my ($config) = @_;
+
+    my $test_case;
+    my $test_num = 0;
+
+    $test_case = __read_config $config, \$test_num;
+
     # make sure we have all mandatory configs
     get_ktest_configs;
 
@@ -603,8 +826,20 @@ sub doprint {
 }
 
 sub run_command;
+sub start_monitor;
+sub end_monitor;
+sub wait_for_monitor;
 
 sub reboot {
+    my ($time) = @_;
+
+    if (defined($time)) {
+       start_monitor;
+       # flush out current monitor
+       # May contain the reboot success line
+       wait_for_monitor 1;
+    }
+
     # try to reboot normally
     if (run_command $reboot) {
        if (defined($powercycle_after_reboot)) {
@@ -615,12 +850,17 @@ sub reboot {
        # nope? power cycle it.
        run_command "$power_cycle";
     }
+
+    if (defined($time)) {
+       wait_for_monitor($time, $reboot_success_line);
+       end_monitor;
+    }
 }
 
 sub do_not_reboot {
     my $i = $iteration;
 
-    return $test_type eq "build" ||
+    return $test_type eq "build" || $no_reboot ||
        ($test_type eq "patchcheck" && $opt{"PATCHCHECK_TYPE[$i]"} eq "build") ||
        ($test_type eq "bisect" && $opt{"BISECT_TYPE[$i]"} eq "build");
 }
@@ -693,16 +933,29 @@ sub end_monitor {
 }
 
 sub wait_for_monitor {
-    my ($time) = @_;
+    my ($time, $stop) = @_;
+    my $full_line = "";
     my $line;
+    my $booted = 0;
 
     doprint "** Wait for monitor to settle down **\n";
 
     # read the monitor and wait for the system to calm down
-    do {
+    while (!$booted) {
        $line = wait_for_input($monitor_fp, $time);
-       print "$line" if (defined($line));
-    } while (defined($line));
+       last if (!defined($line));
+       print "$line";
+       $full_line .= $line;
+
+       if (defined($stop) && $full_line =~ /$stop/) {
+           doprint "wait for monitor detected $stop\n";
+           $booted = 1;
+       }
+
+       if ($line =~ /\n/) {
+           $full_line = "";
+       }
+    }
     print "** Monitor flushed **\n";
 }
 
@@ -719,10 +972,7 @@ sub fail {
        # no need to reboot for just building.
        if (!do_not_reboot) {
            doprint "REBOOTING\n";
-           reboot;
-           start_monitor;
-           wait_for_monitor $sleep_time;
-           end_monitor;
+           reboot $sleep_time;
        }
 
        my $name = "";
@@ -854,9 +1104,12 @@ sub get_grub_index {
     open(IN, "$ssh_grub |")
        or die "unable to get menu.lst";
 
+    my $found = 0;
+
     while (<IN>) {
        if (/^\s*title\s+$grub_menu\s*$/) {
            $grub_number++;
+           $found = 1;
            last;
        } elsif (/^\s*title\s/) {
            $grub_number++;
@@ -865,7 +1118,7 @@ sub get_grub_index {
     close(IN);
 
     die "Could not find '$grub_menu' in /boot/grub/menu on $machine"
-       if ($grub_number < 0);
+       if (!$found);
     doprint "$grub_number\n";
 }
 
@@ -902,7 +1155,8 @@ sub wait_for_input
 
 sub reboot_to {
     if ($reboot_type eq "grub") {
-       run_ssh "'(echo \"savedefault --default=$grub_number --once\" | grub --batch && reboot)'";
+       run_ssh "'(echo \"savedefault --default=$grub_number --once\" | grub --batch)'";
+       reboot;
        return;
     }
 
@@ -1083,6 +1337,8 @@ sub do_post_install {
 
 sub install {
 
+    return if ($no_install);
+
     run_scp "$outputdir/$build_target", "$target_image" or
        dodie "failed to copy image";
 
@@ -1140,6 +1396,11 @@ sub get_version {
 }
 
 sub start_monitor_and_boot {
+    # Make sure the stable kernel has finished booting
+    start_monitor;
+    wait_for_monitor 5;
+    end_monitor;
+
     get_grub_index;
     get_version;
     install;
@@ -1250,6 +1511,10 @@ sub build {
 
     unlink $buildlog;
 
+    # Failed builds should not reboot the target
+    my $save_no_reboot = $no_reboot;
+    $no_reboot = 1;
+
     if (defined($pre_build)) {
        my $ret = run_command $pre_build;
        if (!$ret && defined($pre_build_die) &&
@@ -1272,15 +1537,15 @@ sub build {
        # allow for empty configs
        run_command "touch $output_config";
 
-       run_command "mv $output_config $outputdir/config_temp" or
-           dodie "moving .config";
+       if (!$noclean) {
+           run_command "mv $output_config $outputdir/config_temp" or
+               dodie "moving .config";
 
-       if (!$noclean && !run_command "$make mrproper") {
-           dodie "make mrproper";
-       }
+           run_command "$make mrproper" or dodie "make mrproper";
 
-       run_command "mv $outputdir/config_temp $output_config" or
-           dodie "moving config_temp";
+           run_command "mv $outputdir/config_temp $output_config" or
+               dodie "moving config_temp";
+       }
 
     } elsif (!$noclean) {
        unlink "$output_config";
@@ -1318,10 +1583,15 @@ sub build {
 
     if (!$build_ret) {
        # bisect may need this to pass
-       return 0 if ($in_bisect);
+       if ($in_bisect) {
+           $no_reboot = $save_no_reboot;
+           return 0;
+       }
        fail "failed build" and return 0;
     }
 
+    $no_reboot = $save_no_reboot;
+
     return 1;
 }
 
@@ -1356,10 +1626,7 @@ sub success {
 
     if ($i != $opt{"NUM_TESTS"} && !do_not_reboot) {
        doprint "Reboot and wait $sleep_time seconds\n";
-       reboot;
-       start_monitor;
-       wait_for_monitor $sleep_time;
-       end_monitor;
+       reboot $sleep_time;
     }
 }
 
@@ -1500,10 +1767,7 @@ sub run_git_bisect {
 
 sub bisect_reboot {
     doprint "Reboot and sleep $bisect_sleep_time seconds\n";
-    reboot;
-    start_monitor;
-    wait_for_monitor $bisect_sleep_time;
-    end_monitor;
+    reboot $bisect_sleep_time;
 }
 
 # returns 1 on success, 0 on failure, -1 on skip
@@ -2066,10 +2330,7 @@ sub config_bisect {
 
 sub patchcheck_reboot {
     doprint "Reboot and sleep $patchcheck_sleep_time seconds\n";
-    reboot;
-    start_monitor;
-    wait_for_monitor $patchcheck_sleep_time;
-    end_monitor;
+    reboot $patchcheck_sleep_time;
 }
 
 sub patchcheck {
@@ -2178,12 +2439,31 @@ sub patchcheck {
 }
 
 my %depends;
+my %depcount;
 my $iflevel = 0;
 my @ifdeps;
 
 # prevent recursion
 my %read_kconfigs;
 
+sub add_dep {
+    # $config depends on $dep
+    my ($config, $dep) = @_;
+
+    if (defined($depends{$config})) {
+       $depends{$config} .= " " . $dep;
+    } else {
+       $depends{$config} = $dep;
+    }
+
+    # record the number of configs depending on $dep
+    if (defined $depcount{$dep}) {
+       $depcount{$dep}++;
+    } else {
+       $depcount{$dep} = 1;
+    } 
+}
+
 # taken from streamline_config.pl
 sub read_kconfig {
     my ($kconfig) = @_;
@@ -2230,30 +2510,19 @@ sub read_kconfig {
            $config = $2;
 
            for (my $i = 0; $i < $iflevel; $i++) {
-               if ($i) {
-                   $depends{$config} .= " " . $ifdeps[$i];
-               } else {
-                   $depends{$config} = $ifdeps[$i];
-               }
-               $state = "DEP";
+               add_dep $config, $ifdeps[$i];
            }
 
        # collect the depends for the config
        } elsif ($state eq "NEW" && /^\s*depends\s+on\s+(.*)$/) {
 
-           if (defined($depends{$1})) {
-               $depends{$config} .= " " . $1;
-           } else {
-               $depends{$config} = $1;
-           }
+           add_dep $config, $1;
 
        # Get the configs that select this config
-       } elsif ($state ne "NONE" && /^\s*select\s+(\S+)/) {
-           if (defined($depends{$1})) {
-               $depends{$1} .= " " . $config;
-           } else {
-               $depends{$1} = $config;
-           }
+       } elsif ($state eq "NEW" && /^\s*select\s+(\S+)/) {
+
+           # selected by depends on config
+           add_dep $1, $config;
 
        # Check for if statements
        } elsif (/^if\s+(.*\S)\s*$/) {
@@ -2365,11 +2634,18 @@ sub make_new_config {
     close OUT;
 }
 
+sub chomp_config {
+    my ($config) = @_;
+
+    $config =~ s/CONFIG_//;
+
+    return $config;
+}
+
 sub get_depends {
     my ($dep) = @_;
 
-    my $kconfig = $dep;
-    $kconfig =~ s/CONFIG_//;
+    my $kconfig = chomp_config $dep;
 
     $dep = $depends{"$kconfig"};
 
@@ -2419,8 +2695,7 @@ sub test_this_config {
        return undef;
     }
 
-    my $kconfig = $config;
-    $kconfig =~ s/CONFIG_//;
+    my $kconfig = chomp_config $config;
 
     # Test dependencies first
     if (defined($depends{"$kconfig"})) {
@@ -2510,6 +2785,14 @@ sub make_min_config {
 
     my @config_keys = keys %min_configs;
 
+    # All configs need a depcount
+    foreach my $config (@config_keys) {
+       my $kconfig = chomp_config $config;
+       if (!defined $depcount{$kconfig}) {
+               $depcount{$kconfig} = 0;
+       }
+    }
+
     # Remove anything that was set by the make allnoconfig
     # we shouldn't need them as they get set for us anyway.
     foreach my $config (@config_keys) {
@@ -2548,8 +2831,13 @@ sub make_min_config {
        # Now disable each config one by one and do a make oldconfig
        # till we find a config that changes our list.
 
-       # Put configs that did not modify the config at the end.
        my @test_configs = keys %min_configs;
+
+       # Sort keys by who is most dependent on
+       @test_configs = sort  { $depcount{chomp_config($b)} <=> $depcount{chomp_config($a)} }
+                         @test_configs ;
+
+       # Put configs that did not modify the config at the end.
        my $reset = 1;
        for (my $i = 0; $i < $#test_configs; $i++) {
            if (!defined($nochange_config{$test_configs[0]})) {
@@ -2659,10 +2947,7 @@ sub make_min_config {
        }
 
        doprint "Reboot and wait $sleep_time seconds\n";
-       reboot;
-       start_monitor;
-       wait_for_monitor $sleep_time;
-       end_monitor;
+       reboot $sleep_time;
     }
 
     success $i;
@@ -2783,6 +3068,9 @@ sub set_test_option {
 # First we need to do is the builds
 for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
 
+    # Do not reboot on failing test options
+    $no_reboot = 1;
+
     $iteration = $i;
 
     my $makecmd = set_test_option("MAKE_CMD", $i);
@@ -2811,6 +3099,7 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
     $reboot_type = set_test_option("REBOOT_TYPE", $i);
     $grub_menu = set_test_option("GRUB_MENU", $i);
     $post_install = set_test_option("POST_INSTALL", $i);
+    $no_install = set_test_option("NO_INSTALL", $i);
     $reboot_script = set_test_option("REBOOT_SCRIPT", $i);
     $reboot_on_error = set_test_option("REBOOT_ON_ERROR", $i);
     $poweroff_on_error = set_test_option("POWEROFF_ON_ERROR", $i);
@@ -2832,6 +3121,7 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
     $console = set_test_option("CONSOLE", $i);
     $detect_triplefault = set_test_option("DETECT_TRIPLE_FAULT", $i);
     $success_line = set_test_option("SUCCESS_LINE", $i);
+    $reboot_success_line = set_test_option("REBOOT_SUCCESS_LINE", $i);
     $stop_after_success = set_test_option("STOP_AFTER_SUCCESS", $i);
     $stop_after_failure = set_test_option("STOP_AFTER_FAILURE", $i);
     $stop_test_after = set_test_option("STOP_TEST_AFTER", $i);
@@ -2850,9 +3140,11 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
 
     chdir $builddir || die "can't change directory to $builddir";
 
-    if (!-d $tmpdir) {
-       mkpath($tmpdir) or
-           die "can't create $tmpdir";
+    foreach my $dir ($tmpdir, $outputdir) {
+       if (!-d $dir) {
+           mkpath($dir) or
+               die "can't create $dir";
+       }
     }
 
     $ENV{"SSH_USER"} = $ssh_user;
@@ -2889,8 +3181,11 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
        $run_type = "ERROR";
     }
 
+    my $installme = "";
+    $installme = " no_install" if ($no_install);
+
     doprint "\n\n";
-    doprint "RUNNING TEST $i of $opt{NUM_TESTS} with option $test_type $run_type\n\n";
+    doprint "RUNNING TEST $i of $opt{NUM_TESTS} with option $test_type $run_type$installme\n\n";
 
     unlink $dmesg;
     unlink $buildlog;
@@ -2911,6 +3206,9 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
            die "failed to checkout $checkout";
     }
 
+    $no_reboot = 0;
+
+
     if ($test_type eq "bisect") {
        bisect $i;
        next;
@@ -2929,6 +3227,13 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
        build $build_type or next;
     }
 
+    if ($test_type eq "install") {
+       get_version;
+       install;
+       success $i;
+       next;
+    }
+
     if ($test_type ne "build") {
        my $failed = 0;
        start_monitor_and_boot or $failed = 1;
index b8bcd14..dbedfa1 100644 (file)
 # the same option name under the same test or as default
 # ktest will fail to execute, and no tests will run.
 #
+# DEFAULTS OVERRIDE
+#
+# Options defined in the DEFAULTS section can not be duplicated
+# even if they are defined in two different DEFAULT sections.
+# This is done to catch mistakes where an option is added but
+# the previous option was forgotten about and not commented.
+#
+# The OVERRIDE keyword can be added to a section to allow this
+# section to override other DEFAULT sections values that have
+# been defined previously. It will only override options that
+# have been defined before its use. Options defined later
+# in a non override section will still error. The same option
+# can not be defined in the same section even if that section
+# is marked OVERRIDE.
+#
+#
+#
+# Both TEST_START and DEFAULTS sections can also have the IF keyword
+# The value after the IF must evaluate into a 0 or non 0 positive
+# integer, and can use the config variables (explained below).
+#
+# DEFAULTS IF ${IS_X86_32}
+#
+# The above will process the DEFAULTS section if the config
+# variable IS_X86_32 evaluates to a non zero positive integer
+# otherwise if it evaluates to zero, it will act the same
+# as if the SKIP keyword was used.
+#
+# The ELSE keyword can be used directly after a section with
+# a IF statement.
+#
+# TEST_START IF ${RUN_NET_TESTS}
+# BUILD_TYPE = useconfig:${CONFIG_DIR}/config-network
+#
+# ELSE
+#
+# BUILD_TYPE = useconfig:${CONFIG_DIR}/config-normal
+#
+#
+# The ELSE keyword can also contain an IF statement to allow multiple
+# if then else sections. But all the sections must be either
+# DEFAULT or TEST_START, they can not be a mixture.
+#
+# TEST_START IF ${RUN_NET_TESTS}
+# BUILD_TYPE = useconfig:${CONFIG_DIR}/config-network
+#
+# ELSE IF ${RUN_DISK_TESTS}
+# BUILD_TYPE = useconfig:${CONFIG_DIR}/config-tests
+#
+# ELSE IF ${RUN_CPU_TESTS}
+# BUILD_TYPE = useconfig:${CONFIG_DIR}/config-cpu
+#
+# ELSE
+# BUILD_TYPE = useconfig:${CONFIG_DIR}/config-network
+#
+# The if statement may also have comparisons that will and for
+# == and !=, strings may be used for both sides.
+#
+# BOX_TYPE := x86_32
+#
+# DEFAULTS IF ${BOX_TYPE} == x86_32
+# BUILD_TYPE = useconfig:${CONFIG_DIR}/config-32
+# ELSE
+# BUILD_TYPE = useconfig:${CONFIG_DIR}/config-64
+#
+# The DEFINED keyword can be used by the IF statements too.
+# It returns true if the given config variable or option has been defined
+# or false otherwise.
+#
+# 
+# DEFAULTS IF DEFINED USE_CC
+# CC := ${USE_CC}
+# ELSE
+# CC := gcc
+#
+#
+# As well as NOT DEFINED.
+#
+# DEFAULTS IF NOT DEFINED MAKE_CMD
+# MAKE_CMD := make ARCH=x86
+#
+#
+# And/or ops (&&,||) may also be used to make complex conditionals.
+#
+# TEST_START IF (DEFINED ALL_TESTS || ${MYTEST} == boottest) && ${MACHINE} == gandalf
+#
+# Notice the use of paranthesis. Without any paranthesis the above would be
+# processed the same as:
+#
+# TEST_START IF DEFINED ALL_TESTS || (${MYTEST} == boottest && ${MACHINE} == gandalf)
+#
+#
+#
+# INCLUDE file
+#
+# The INCLUDE keyword may be used in DEFAULT sections. This will
+# read another config file and process that file as well. The included
+# file can include other files, add new test cases or default
+# statements. Config variables will be passed to these files and changes
+# to config variables will be seen by top level config files. Including
+# a file is processed just like the contents of the file was cut and pasted
+# into the top level file, except, that include files that end with
+# TEST_START sections will have that section ended at the end of
+# the include file. That is, an included file is included followed
+# by another DEFAULT keyword.
+#
+# Unlike other files referenced in this config, the file path does not need
+# to be absolute. If the file does not start with '/', then the directory
+# that the current config file was located in is used. If no config by the
+# given name is found there, then the current directory is searched.
+#
+# INCLUDE myfile
+# DEFAULT
+#
+# is the same as:
+#
+# INCLUDE myfile
+#
+# Note, if the include file does not contain a full path, the file is
+# searched first by the location of the original include file, and then
+# by the location that ktest.pl was executed in.
+#
 
 #### Config variables ####
 #
 
 # The default test type (default test)
 # The test types may be:
-#   build - only build the kernel, do nothing else
-#   boot - build and boot the kernel
-#   test - build, boot and if TEST is set, run the test script
+#   build   - only build the kernel, do nothing else
+#   install - build and install, but do nothing else (does not reboot)
+#   boot    - build, install, and boot the kernel
+#   test    - build, boot and if TEST is set, run the test script
 #          (If TEST is not set, it defaults back to boot)
 #   bisect - Perform a bisect on the kernel (see BISECT_TYPE below)
 #   patchcheck - Do a test on a series of commits in git (see PATCHCHECK below)
 # or on some systems:
 #POST_INSTALL = ssh user@target /sbin/dracut -f /boot/initramfs-test.img $KERNEL_VERSION
 
+# If for some reason you just want to boot the kernel and you do not
+# want the test to install anything new. For example, you may just want
+# to boot test the same kernel over and over and do not want to go through
+# the hassle of installing anything, you can set this option to 1
+# (default 0)
+#NO_INSTALL = 1
+
 # If there is a script that you require to run before the build is done
 # you can specify it with PRE_BUILD.
 #
 # (default "login:")
 #SUCCESS_LINE = login:
 
+# To speed up between reboots, defining a line that the
+# default kernel produces that represents that the default
+# kernel has successfully booted and can be used to pass
+# a new test kernel to it. Otherwise ktest.pl will wait till
+# SLEEP_TIME to continue.
+# (default undefined)
+#REBOOT_SUCCESS_LINE = login:
+
 # In case the console constantly fills the screen, having
 # a specified time to stop the test after success is recommended.
 # (in seconds)
 # another test. If a reboot to the reliable kernel happens,
 # we wait SLEEP_TIME for the console to stop producing output
 # before starting the next test.
+#
+# You can speed up reboot times even more by setting REBOOT_SUCCESS_LINE.
 # (default 60)
 #SLEEP_TIME = 60