Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/bwh/sfc...
authorDavid S. Miller <davem@davemloft.net>
Sat, 10 Mar 2012 02:54:28 +0000 (21:54 -0500)
committerDavid S. Miller <davem@davemloft.net>
Sat, 10 Mar 2012 02:54:28 +0000 (21:54 -0500)
732 files changed:
Documentation/devicetree/bindings/gpio/led.txt
Documentation/devicetree/bindings/vendor-prefixes.txt
Documentation/hwmon/jc42
Documentation/input/alps.txt
Documentation/kernel-parameters.txt
MAINTAINERS
Makefile
arch/alpha/include/asm/futex.h
arch/arm/Kconfig
arch/arm/boot/.gitignore
arch/arm/include/asm/pmu.h
arch/arm/kernel/ecard.c
arch/arm/kernel/perf_event.c
arch/arm/kernel/perf_event_v6.c
arch/arm/kernel/perf_event_v7.c
arch/arm/kernel/perf_event_xscale.c
arch/arm/mach-at91/at91sam9g45_devices.c
arch/arm/mach-at91/at91sam9rl_devices.c
arch/arm/mach-ep93xx/vision_ep9307.c
arch/arm/mach-exynos/mach-universal_c210.c
arch/arm/mach-lpc32xx/include/mach/irqs.h
arch/arm/mach-lpc32xx/irq.c
arch/arm/mach-lpc32xx/serial.c
arch/arm/mach-mmp/aspenite.c
arch/arm/mach-mmp/pxa168.c
arch/arm/mach-mmp/tavorevb.c
arch/arm/mach-omap1/board-innovator.c
arch/arm/mach-omap2/Kconfig
arch/arm/mach-omap2/board-n8x0.c
arch/arm/mach-omap2/board-omap3evm.c
arch/arm/mach-omap2/common.h
arch/arm/mach-omap2/cpuidle44xx.c
arch/arm/mach-omap2/gpmc-smsc911x.c
arch/arm/mach-omap2/hsmmc.c
arch/arm/mach-omap2/id.c
arch/arm/mach-omap2/io.c
arch/arm/mach-omap2/mailbox.c
arch/arm/mach-omap2/mux.c
arch/arm/mach-omap2/omap-iommu.c
arch/arm/mach-omap2/omap4-common.c
arch/arm/mach-omap2/pm.c
arch/arm/mach-omap2/twl-common.c
arch/arm/mach-omap2/usb-host.c
arch/arm/mach-pxa/generic.h
arch/arm/mach-pxa/hx4700.c
arch/arm/mach-pxa/mfp-pxa2xx.c
arch/arm/mach-pxa/pxa25x.c
arch/arm/mach-pxa/pxa27x.c
arch/arm/mach-pxa/pxa3xx.c
arch/arm/mach-pxa/pxa95x.c
arch/arm/mach-pxa/saarb.c
arch/arm/mach-pxa/sharpsl_pm.c
arch/arm/mach-pxa/spitz_pm.c
arch/arm/mach-s3c2440/common.h
arch/arm/mach-s3c2440/mach-anubis.c
arch/arm/mach-s3c2440/mach-at2440evb.c
arch/arm/mach-s3c2440/mach-gta02.c
arch/arm/mach-s3c2440/mach-mini2440.c
arch/arm/mach-s3c2440/mach-nexcoder.c
arch/arm/mach-s3c2440/mach-osiris.c
arch/arm/mach-s3c2440/mach-rx1950.c
arch/arm/mach-s3c2440/mach-rx3715.c
arch/arm/mach-s3c2440/mach-smdk2440.c
arch/arm/mach-s3c2440/s3c2440.c
arch/arm/mach-s3c2440/s3c244x.c
arch/arm/mach-ux500/Kconfig
arch/arm/mach-vexpress/Kconfig
arch/arm/mm/proc-v7.S
arch/arm/plat-omap/common.c
arch/arm/plat-omap/include/plat/irqs.h
arch/arm/plat-omap/include/plat/omap-secure.h
arch/arm/plat-s3c24xx/dma.c
arch/arm/plat-samsung/devs.c
arch/arm/plat-spear/time.c
arch/c6x/include/asm/processor.h
arch/mips/alchemy/common/time.c
arch/mips/ath79/dev-wmac.c
arch/mips/bcm47xx/Makefile
arch/mips/bcm47xx/nvram.c
arch/mips/bcm47xx/setup.c
arch/mips/bcm47xx/sprom.c [new file with mode: 0644]
arch/mips/configs/nlm_xlp_defconfig
arch/mips/configs/nlm_xlr_defconfig
arch/mips/configs/powertv_defconfig
arch/mips/include/asm/mach-au1x00/gpio-au1300.h
arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
arch/mips/include/asm/mach-bcm47xx/nvram.h
arch/mips/include/asm/page.h
arch/mips/kernel/smp-bmips.c
arch/mips/kernel/traps.c
arch/mips/kernel/vmlinux.lds.S
arch/mips/mm/fault.c
arch/mips/pci/pci.c
arch/mips/pmc-sierra/yosemite/ht-irq.c
arch/mips/txx9/generic/7segled.c
arch/openrisc/include/asm/ptrace.h
arch/openrisc/kernel/init_task.c
arch/openrisc/kernel/irq.c
arch/openrisc/kernel/ptrace.c
arch/parisc/Makefile
arch/powerpc/boot/dts/bluestone.dts
arch/s390/Kconfig
arch/s390/include/asm/compat.h
arch/s390/kernel/crash_dump.c
arch/s390/kernel/process.c
arch/s390/kernel/ptrace.c
arch/s390/kernel/setup.c
arch/s390/kernel/signal.c
arch/s390/mm/fault.c
arch/s390/mm/init.c
arch/s390/mm/mmap.c
arch/x86/ia32/ia32_aout.c
arch/x86/include/asm/perf_event.h
arch/x86/kernel/cpu/intel_cacheinfo.c
arch/x86/kernel/cpu/mcheck/mce_amd.c
arch/x86/kernel/cpu/perf_event.h
arch/x86/kernel/cpu/perf_event_amd.c
arch/x86/kernel/entry_64.S
arch/x86/kernel/microcode_amd.c
arch/x86/kvm/svm.c
arch/x86/lib/delay.c
arch/x86/mm/hugetlbpage.c
arch/x86/pci/acpi.c
arch/x86/xen/enlighten.c
arch/x86/xen/mmu.c
block/partitions/ldm.c
drivers/bcma/driver_chipcommon_pmu.c
drivers/bcma/main.c
drivers/bcma/sprom.c
drivers/block/floppy.c
drivers/bluetooth/ath3k.c
drivers/bluetooth/bfusb.c
drivers/bluetooth/bluecard_cs.c
drivers/bluetooth/bpa10x.c
drivers/bluetooth/bt3c_cs.c
drivers/bluetooth/btmrvl_debugfs.c
drivers/bluetooth/btmrvl_main.c
drivers/bluetooth/btsdio.c
drivers/bluetooth/btuart_cs.c
drivers/bluetooth/btusb.c
drivers/bluetooth/btwilink.c
drivers/bluetooth/dtl1_cs.c
drivers/bluetooth/hci_ath.c
drivers/bluetooth/hci_bcsp.c
drivers/bluetooth/hci_h4.c
drivers/bluetooth/hci_ldisc.c
drivers/bluetooth/hci_ll.c
drivers/bluetooth/hci_uart.h
drivers/bluetooth/hci_vhci.c
drivers/crypto/mv_cesa.c
drivers/gpu/drm/exynos/exynos_drm_connector.c
drivers/gpu/drm/exynos/exynos_drm_drv.h
drivers/gpu/drm/exynos/exynos_drm_fimd.c
drivers/gpu/drm/gma500/cdv_device.c
drivers/gpu/drm/gma500/framebuffer.c
drivers/gpu/drm/gma500/gtt.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/r600_blit_shaders.c
drivers/gpu/drm/radeon/r600_cs.c
drivers/gpu/drm/radeon/r600d.h
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_display.c
drivers/gpu/drm/radeon/radeon_encoders.c
drivers/gpu/drm/radeon/radeon_fb.c
drivers/gpu/drm/radeon/radeon_gart.c
drivers/gpu/drm/radeon/radeon_mode.h
drivers/hid/hid-ids.h
drivers/hid/hid-input.c
drivers/hid/usbhid/hid-quirks.c
drivers/hwmon/Kconfig
drivers/hwmon/f75375s.c
drivers/hwmon/jc42.c
drivers/hwmon/pmbus/pmbus_core.c
drivers/hwmon/pmbus/zl6100.c
drivers/i2c/busses/i2c-mxs.c
drivers/input/evdev.c
drivers/input/misc/twl4030-vibra.c
drivers/input/mouse/alps.c
drivers/input/tablet/Kconfig
drivers/input/tablet/wacom_wac.c
drivers/iommu/amd_iommu_init.c
drivers/iommu/omap-iommu-debug.c
drivers/iommu/omap-iommu.c
drivers/md/dm-flakey.c
drivers/md/dm-io.c
drivers/md/dm-ioctl.c
drivers/md/dm-raid.c
drivers/md/dm-thin-metadata.c
drivers/md/raid1.c
drivers/md/raid10.c
drivers/mfd/ab8500-core.c
drivers/mfd/mfd-core.c
drivers/mfd/s5m-core.c
drivers/mfd/tps65910.c
drivers/mfd/tps65912-core.c
drivers/mfd/wm8350-irq.c
drivers/mfd/wm8994-core.c
drivers/mfd/wm8994-regmap.c
drivers/misc/c2port/core.c
drivers/mmc/core/core.c
drivers/mmc/core/host.c
drivers/mmc/core/mmc.c
drivers/mmc/core/sd.c
drivers/mmc/core/sdio.c
drivers/mmc/host/atmel-mci.c
drivers/mmc/host/mmci.c
drivers/mmc/host/sdhci-esdhc-imx.c
drivers/net/caif/caif_hsi.c
drivers/net/ethernet/atheros/atl1c/atl1c_main.c
drivers/net/ethernet/broadcom/tg3.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
drivers/net/ethernet/cisco/enic/enic.h
drivers/net/ethernet/cisco/enic/enic_main.c
drivers/net/ethernet/ibm/ehea/ehea_main.c
drivers/net/ethernet/ibm/emac/core.c
drivers/net/ethernet/ibm/emac/core.h
drivers/net/ethernet/ibm/emac/emac.h
drivers/net/ethernet/mellanox/mlx4/en_netdev.c
drivers/net/ethernet/mellanox/mlx4/en_rx.c
drivers/net/ethernet/mellanox/mlx4/en_tx.c
drivers/net/ethernet/mellanox/mlx4/fw.c
drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
drivers/net/ethernet/mellanox/mlx4/mr.c
drivers/net/ethernet/mellanox/mlx4/port.c
drivers/net/ethernet/mellanox/mlx4/qp.c
drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
drivers/net/ethernet/oki-semi/pch_gbe/Kconfig
drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h
drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
drivers/net/ethernet/packetengines/Kconfig
drivers/net/ethernet/qlogic/qla3xxx.c
drivers/net/ethernet/realtek/8139too.c
drivers/net/ethernet/realtek/r8169.c
drivers/net/hyperv/netvsc_drv.c
drivers/net/usb/usbnet.c
drivers/net/vmxnet3/vmxnet3_drv.c
drivers/net/vmxnet3/vmxnet3_int.h
drivers/net/wireless/airo.c
drivers/net/wireless/ath/ath5k/ahb.c
drivers/net/wireless/ath/ath5k/ath5k.h
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath5k/mac80211-ops.c
drivers/net/wireless/ath/ath5k/phy.c
drivers/net/wireless/ath/ath5k/reset.c
drivers/net/wireless/ath/ath6kl/cfg80211.c
drivers/net/wireless/ath/ath6kl/wmi.c
drivers/net/wireless/ath/ath9k/Kconfig
drivers/net/wireless/ath/ath9k/Makefile
drivers/net/wireless/ath/ath9k/ar9001_initvals.h
drivers/net/wireless/ath/ath9k/ar9002_hw.c
drivers/net/wireless/ath/ath9k/ar9002_initvals.h
drivers/net/wireless/ath/ath9k/ar9003_calib.c
drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
drivers/net/wireless/ath/ath9k/ar9003_hw.c
drivers/net/wireless/ath/ath9k/ar9003_mac.c
drivers/net/wireless/ath/ath9k/ar9003_mac.h
drivers/net/wireless/ath/ath9k/ar9003_mci.c
drivers/net/wireless/ath/ath9k/ar9003_mci.h
drivers/net/wireless/ath/ath9k/ar9003_phy.c
drivers/net/wireless/ath/ath9k/ar9003_phy.h
drivers/net/wireless/ath/ath9k/ar9462_1p0_initvals.h [deleted file]
drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/beacon.c
drivers/net/wireless/ath/ath9k/btcoex.c
drivers/net/wireless/ath/ath9k/btcoex.h
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/debug.h
drivers/net/wireless/ath/ath9k/gpio.c
drivers/net/wireless/ath/ath9k/htc.h
drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
drivers/net/wireless/ath/ath9k/htc_drv_init.c
drivers/net/wireless/ath/ath9k/htc_drv_main.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/mac.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/mci.c
drivers/net/wireless/ath/ath9k/mci.h
drivers/net/wireless/ath/ath9k/rc.c
drivers/net/wireless/ath/ath9k/rc.h
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/ath9k/reg.h
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/carl9170/tx.c
drivers/net/wireless/b43/main.c
drivers/net/wireless/b43legacy/phy.c
drivers/net/wireless/brcm80211/Kconfig
drivers/net/wireless/brcm80211/brcmfmac/Makefile
drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
drivers/net/wireless/brcm80211/brcmfmac/usb.c [new file with mode: 0644]
drivers/net/wireless/brcm80211/brcmfmac/usb.h [new file with mode: 0644]
drivers/net/wireless/brcm80211/brcmfmac/usb_rdl.h [new file with mode: 0644]
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
drivers/net/wireless/brcm80211/brcmsmac/ampdu.c
drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
drivers/net/wireless/brcm80211/brcmsmac/main.c
drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
drivers/net/wireless/brcm80211/brcmsmac/srom.c
drivers/net/wireless/ipw2x00/ipw2100.c
drivers/net/wireless/ipw2x00/ipw2200.h
drivers/net/wireless/iwlegacy/3945-debug.c
drivers/net/wireless/iwlegacy/3945-mac.c
drivers/net/wireless/iwlegacy/3945.c
drivers/net/wireless/iwlegacy/3945.h
drivers/net/wireless/iwlegacy/4965-calib.c
drivers/net/wireless/iwlegacy/4965-debug.c
drivers/net/wireless/iwlegacy/4965-mac.c
drivers/net/wireless/iwlegacy/4965.c
drivers/net/wireless/iwlegacy/4965.h
drivers/net/wireless/iwlegacy/Kconfig
drivers/net/wireless/iwlegacy/common.c
drivers/net/wireless/iwlegacy/common.h
drivers/net/wireless/iwlegacy/debug.c
drivers/net/wireless/iwlwifi/Kconfig
drivers/net/wireless/iwlwifi/Makefile
drivers/net/wireless/iwlwifi/iwl-1000.c
drivers/net/wireless/iwlwifi/iwl-2000.c
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-6000.c
drivers/net/wireless/iwlwifi/iwl-agn-calib.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-tt.c
drivers/net/wireless/iwlwifi/iwl-agn-tx.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-agn.h
drivers/net/wireless/iwlwifi/iwl-bus.h [deleted file]
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-debug.c [new file with mode: 0644]
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.h
drivers/net/wireless/iwlwifi/iwl-drv.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-drv.h [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-eeprom.c
drivers/net/wireless/iwlwifi/iwl-eeprom.h
drivers/net/wireless/iwlwifi/iwl-fw-file.h [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-fw.h [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-io.c
drivers/net/wireless/iwlwifi/iwl-io.h
drivers/net/wireless/iwlwifi/iwl-led.c
drivers/net/wireless/iwlwifi/iwl-mac80211.c
drivers/net/wireless/iwlwifi/iwl-notif-wait.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-notif-wait.h [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-op-mode.h [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-pci.c
drivers/net/wireless/iwlwifi/iwl-power.c
drivers/net/wireless/iwlwifi/iwl-prph.h
drivers/net/wireless/iwlwifi/iwl-scan.c
drivers/net/wireless/iwlwifi/iwl-shared.h
drivers/net/wireless/iwlwifi/iwl-testmode.c
drivers/net/wireless/iwlwifi/iwl-testmode.h
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.c [deleted file]
drivers/net/wireless/iwlwifi/iwl-trans.h
drivers/net/wireless/iwlwifi/iwl-ucode.c
drivers/net/wireless/iwlwifi/iwl-ucode.h [deleted file]
drivers/net/wireless/iwlwifi/iwl-wifi.h [deleted file]
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/cmdevt.c
drivers/net/wireless/mwifiex/decl.h
drivers/net/wireless/mwifiex/fw.h
drivers/net/wireless/mwifiex/init.c
drivers/net/wireless/mwifiex/ioctl.h
drivers/net/wireless/mwifiex/join.c
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/scan.c
drivers/net/wireless/mwifiex/sta_event.c
drivers/net/wireless/mwifiex/sta_ioctl.c
drivers/net/wireless/p54/main.c
drivers/net/wireless/p54/p54pci.c
drivers/net/wireless/p54/p54spi.c
drivers/net/wireless/p54/txrx.c
drivers/net/wireless/rndis_wlan.c
drivers/net/wireless/rt2x00/Kconfig
drivers/net/wireless/rt2x00/rt2800.h
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/net/wireless/rt2x00/rt2800lib.h
drivers/net/wireless/rt2x00/rt2800pci.c
drivers/net/wireless/rt2x00/rt2800usb.c
drivers/net/wireless/rt2x00/rt2x00.h
drivers/net/wireless/rt2x00/rt2x00config.c
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rt2x00/rt2x00lib.h
drivers/net/wireless/rt2x00/rt2x00link.c
drivers/net/wireless/rtl818x/rtl8187/dev.c
drivers/net/wireless/rtl818x/rtl8187/rtl8187.h
drivers/net/wireless/rtlwifi/Kconfig
drivers/net/wireless/rtlwifi/base.c
drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c
drivers/net/wireless/rtlwifi/rtl8192de/phy.c
drivers/net/wireless/rtlwifi/rtl8192se/fw.h
drivers/net/wireless/rtlwifi/rtl8192se/phy.c
drivers/net/wireless/rtlwifi/rtl8192se/sw.c
drivers/net/wireless/rtlwifi/usb.c
drivers/net/wireless/wl1251/Makefile
drivers/net/wireless/wl1251/boot.c
drivers/net/wireless/wl1251/io.h
drivers/net/wireless/wl1251/wl1251.h
drivers/net/wireless/wl12xx/Makefile
drivers/net/wireless/wl12xx/acx.c
drivers/net/wireless/wl12xx/acx.h
drivers/net/wireless/wl12xx/boot.c
drivers/net/wireless/wl12xx/boot.h
drivers/net/wireless/wl12xx/cmd.c
drivers/net/wireless/wl12xx/cmd.h
drivers/net/wireless/wl12xx/conf.h
drivers/net/wireless/wl12xx/debug.h
drivers/net/wireless/wl12xx/debugfs.c
drivers/net/wireless/wl12xx/event.c
drivers/net/wireless/wl12xx/event.h
drivers/net/wireless/wl12xx/init.c
drivers/net/wireless/wl12xx/io.c
drivers/net/wireless/wl12xx/io.h
drivers/net/wireless/wl12xx/main.c
drivers/net/wireless/wl12xx/ps.c
drivers/net/wireless/wl12xx/ps.h
drivers/net/wireless/wl12xx/reg.h
drivers/net/wireless/wl12xx/rx.c
drivers/net/wireless/wl12xx/scan.c
drivers/net/wireless/wl12xx/scan.h
drivers/net/wireless/wl12xx/sdio.c
drivers/net/wireless/wl12xx/spi.c
drivers/net/wireless/wl12xx/testmode.c
drivers/net/wireless/wl12xx/tx.c
drivers/net/wireless/wl12xx/tx.h
drivers/net/wireless/wl12xx/wl12xx.h
drivers/net/wireless/wl12xx/wl12xx_80211.h
drivers/net/wireless/zd1211rw/zd_mac.c
drivers/nfc/pn533.c
drivers/of/fdt.c
drivers/of/of_mdio.c
drivers/parisc/iommu-helpers.h
drivers/pcmcia/pxa2xx_base.c
drivers/pps/pps.c
drivers/ptp/Kconfig
drivers/ptp/Makefile
drivers/ptp/ptp_pch.c [new file with mode: 0644]
drivers/rapidio/devices/tsi721.c
drivers/regulator/88pm8607.c
drivers/regulator/da9052-regulator.c
drivers/regulator/tps65910-regulator.c
drivers/rtc/rtc-r9701.c
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_ioctl.c
drivers/s390/char/fs3270.c
drivers/s390/char/vmcp.c
drivers/s390/cio/chsc_sch.c
drivers/s390/cio/qdio_main.c
drivers/s390/net/ctcm_fsms.c
drivers/s390/net/ctcm_main.c
drivers/s390/net/ctcm_mpc.c
drivers/s390/net/lcs.c
drivers/s390/net/qeth_core_main.c
drivers/s390/net/qeth_core_mpc.c
drivers/s390/net/qeth_core_mpc.h
drivers/s390/net/qeth_l2_main.c
drivers/s390/net/qeth_l3_main.c
drivers/s390/scsi/zfcp_cfdc.c
drivers/scsi/osd/osd_uld.c
drivers/scsi/sd_dif.c
drivers/spi/spi-pl022.c
drivers/ssb/pci.c
drivers/ssb/pcmcia.c
drivers/ssb/sdio.c
drivers/tty/Kconfig
drivers/usb/host/ehci-fsl.c
drivers/usb/host/ehci-fsl.h
drivers/video/omap2/displays/Kconfig
drivers/video/omap2/dss/apply.c
drivers/video/omap2/dss/hdmi.c
drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c
drivers/video/via/hw.c
drivers/virtio/virtio_balloon.c
drivers/watchdog/Kconfig
drivers/watchdog/booke_wdt.c
drivers/watchdog/hpwdt.c
drivers/watchdog/pnx4008_wdt.c
drivers/watchdog/s3c2410_wdt.c
fs/aio.c
fs/binfmt_aout.c
fs/binfmt_elf.c
fs/cifs/dir.c
fs/cifs/inode.c
fs/dcache.c
fs/dlm/lowcomms.c
fs/ecryptfs/miscdev.c
fs/exec.c
fs/gfs2/glock.c
fs/gfs2/inode.c
fs/gfs2/ops_fstype.c
fs/gfs2/rgrp.c
fs/namei.c
fs/ntfs/attrib.c
fs/ntfs/mft.c
fs/ntfs/super.c
include/asm-generic/iomap.h
include/asm-generic/pci_iomap.h
include/drm/Kbuild
include/drm/exynos_drm.h
include/linux/amba/serial.h
include/linux/bcma/bcma.h
include/linux/bcma/bcma_driver_chipcommon.h
include/linux/dcache.h
include/linux/kmsg_dump.h
include/linux/memcontrol.h
include/linux/mlx4/device.h
include/linux/netdevice.h
include/linux/netfilter/Kbuild
include/linux/netfilter/ipset/ip_set.h
include/linux/netfilter/ipset/ip_set_ahash.h
include/linux/netfilter/nf_conntrack_tcp.h
include/linux/netfilter/nfnetlink.h
include/linux/netfilter/nfnetlink_conntrack.h
include/linux/netfilter/nfnetlink_cttimeout.h [new file with mode: 0644]
include/linux/netfilter/xt_CT.h
include/linux/netfilter/xt_LOG.h [new file with mode: 0644]
include/linux/netfilter_ipv4/Kbuild
include/linux/netfilter_ipv4/ipt_LOG.h
include/linux/netfilter_ipv4/ipt_SAME.h [deleted file]
include/linux/netfilter_ipv4/ipt_realm.h [deleted file]
include/linux/netfilter_ipv6/ip6t_LOG.h
include/linux/nfc.h
include/linux/nl80211.h
include/linux/of.h
include/linux/percpu.h
include/linux/regset.h
include/linux/sched.h
include/linux/skbuff.h
include/linux/ssb/ssb.h
include/net/bluetooth/bluetooth.h
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
include/net/bluetooth/hci_mon.h [new file with mode: 0644]
include/net/bluetooth/l2cap.h
include/net/bluetooth/mgmt.h
include/net/bluetooth/smp.h
include/net/cfg80211.h
include/net/inetpeer.h
include/net/ip.h
include/net/iucv/af_iucv.h
include/net/mac80211.h
include/net/netfilter/nf_conntrack_extend.h
include/net/netfilter/nf_conntrack_helper.h
include/net/netfilter/nf_conntrack_l4proto.h
include/net/netfilter/nf_conntrack_timeout.h [new file with mode: 0644]
include/net/netfilter/xt_log.h
include/net/nfc/nci_core.h
include/net/nfc/nfc.h
include/net/sctp/sctp.h
include/trace/events/sched.h
kernel/events/hw_breakpoint.c
kernel/fork.c
kernel/hung_task.c
kernel/irq/autoprobe.c
kernel/irq/chip.c
kernel/irq/internals.h
kernel/irq/manage.c
kernel/kprobes.c
kernel/printk.c
kernel/sched/core.c
kernel/sched/fair.c
lib/debugobjects.c
lib/vsprintf.c
mm/huge_memory.c
mm/hugetlb.c
mm/ksm.c
mm/memblock.c
mm/memcontrol.c
mm/mempolicy.c
mm/migrate.c
mm/mlock.c
mm/mmap.c
mm/mprotect.c
mm/page_cgroup.c
mm/percpu-vm.c
mm/swap.c
mm/swap_state.c
net/bluetooth/Kconfig
net/bluetooth/bnep/sock.c
net/bluetooth/cmtp/sock.c
net/bluetooth/hci_conn.c
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/hci_sock.c
net/bluetooth/hci_sysfs.c
net/bluetooth/hidp/sock.c
net/bluetooth/l2cap_core.c
net/bluetooth/l2cap_sock.c
net/bluetooth/lib.c
net/bluetooth/mgmt.c
net/bluetooth/rfcomm/tty.c
net/bluetooth/smp.c
net/bridge/br_multicast.c
net/bridge/br_netfilter.c
net/bridge/br_stp.c
net/bridge/br_stp_if.c
net/bridge/netfilter/ebtables.c
net/core/dev.c
net/core/rtnetlink.c
net/ipv4/inetpeer.c
net/ipv4/ip_input.c
net/ipv4/netfilter/Kconfig
net/ipv4/netfilter/Makefile
net/ipv4/netfilter/ipt_LOG.c [deleted file]
net/ipv4/netfilter/nf_conntrack_proto_icmp.c
net/ipv4/netfilter/nf_nat_core.c
net/ipv4/netfilter/nf_nat_h323.c
net/ipv4/netfilter/nf_nat_sip.c
net/ipv4/route.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv6/addrconf.c
net/ipv6/netfilter/Kconfig
net/ipv6/netfilter/Makefile
net/ipv6/netfilter/ip6t_LOG.c [deleted file]
net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
net/iucv/af_iucv.c
net/mac80211/cfg.c
net/mac80211/debugfs_netdev.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/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/netfilter/Kconfig
net/netfilter/Makefile
net/netfilter/ipset/ip_set_bitmap_ip.c
net/netfilter/ipset/ip_set_bitmap_ipmac.c
net/netfilter/ipset/ip_set_bitmap_port.c
net/netfilter/ipset/ip_set_core.c
net/netfilter/ipset/ip_set_getport.c
net/netfilter/ipset/ip_set_hash_ip.c
net/netfilter/ipset/ip_set_hash_ipport.c
net/netfilter/ipset/ip_set_hash_ipportip.c
net/netfilter/ipset/ip_set_hash_ipportnet.c
net/netfilter/ipset/ip_set_hash_net.c
net/netfilter/ipset/ip_set_hash_netiface.c
net/netfilter/ipset/ip_set_hash_netport.c
net/netfilter/ipset/ip_set_list_set.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_ecache.c
net/netfilter/nf_conntrack_helper.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_conntrack_proto_dccp.c
net/netfilter/nf_conntrack_proto_generic.c
net/netfilter/nf_conntrack_proto_gre.c
net/netfilter/nf_conntrack_proto_sctp.c
net/netfilter/nf_conntrack_proto_tcp.c
net/netfilter/nf_conntrack_proto_udp.c
net/netfilter/nf_conntrack_proto_udplite.c
net/netfilter/nf_conntrack_timeout.c [new file with mode: 0644]
net/netfilter/nfnetlink_cttimeout.c [new file with mode: 0644]
net/netfilter/xt_CT.c
net/netfilter/xt_LOG.c [new file with mode: 0644]
net/nfc/af_nfc.c
net/nfc/core.c
net/nfc/llcp/commands.c
net/nfc/llcp/llcp.c
net/nfc/llcp/llcp.h
net/nfc/llcp/sock.c
net/nfc/nci/core.c
net/nfc/nci/data.c
net/nfc/nci/ntf.c
net/nfc/nci/rsp.c
net/nfc/netlink.c
net/nfc/nfc.h
net/nfc/rawsock.c
net/openvswitch/actions.c
net/openvswitch/datapath.c
net/sctp/socket.c
net/wireless/mesh.c
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/nl80211.h
net/wireless/util.c
scripts/mod/file2alias.c
sound/pci/azt3328.c
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/patch_cirrus.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/rme9652/hdspm.c
sound/soc/imx/imx-ssi.c
sound/soc/samsung/neo1973_wm8753.c
sound/soc/soc-dapm.c
tools/perf/builtin-record.c
tools/perf/builtin-top.c
tools/perf/perf.h
tools/perf/util/event.c
tools/perf/util/evlist.c
tools/perf/util/probe-event.c
tools/perf/util/probe-finder.c
tools/perf/util/top.h
tools/perf/util/util.c
tools/testing/ktest/ktest.pl

index 141087cf3107733b8bb4e2c33a8fcd5dbba8076c..fd2bd56e7195a809dcab552cd070e29aefed2840 100644 (file)
@@ -7,9 +7,9 @@ Each LED is represented as a sub-node of the gpio-leds device.  Each
 node's name represents the name of the corresponding LED.
 
 LED sub-node properties:
-- gpios :  Should specify the LED's GPIO, see "Specifying GPIO information
-  for devices" in Documentation/devicetree/booting-without-of.txt.  Active
-  low LEDs should be indicated using flags in the GPIO specifier.
+- gpios :  Should specify the LED's GPIO, see "gpios property" in
+  Documentation/devicetree/gpio.txt.  Active low LEDs should be
+  indicated using flags in the GPIO specifier.
 - label :  (optional) The label for this LED.  If omitted, the label is
   taken from the node name (excluding the unit address).
 - linux,default-trigger :  (optional) This parameter, if present, is a
index ecc6a6cd26c198ff412ce2af839cc3b602d73a29..a20008ab319a9d5acba2f57bdaff0a5338a1d547 100644 (file)
@@ -30,6 +30,7 @@ national      National Semiconductor
 nintendo       Nintendo
 nvidia NVIDIA
 nxp    NXP Semiconductors
+picochip       Picochip Ltd
 powervr        Imagination Technologies
 qcom   Qualcomm, Inc.
 ramtron        Ramtron International
index a22ecf48f255c24220eec21cb1769e29c5db11c7..52729a756c1b55374ef7521898e6ded4753b61b9 100644 (file)
@@ -7,21 +7,29 @@ Supported chips:
     Addresses scanned: I2C 0x18 - 0x1f
     Datasheets:
        http://www.analog.com/static/imported-files/data_sheets/ADT7408.pdf
-  * IDT TSE2002B3, TS3000B3
-    Prefix: 'tse2002b3', 'ts3000b3'
+  * Atmel AT30TS00
+    Prefix: 'at30ts00'
     Addresses scanned: I2C 0x18 - 0x1f
     Datasheets:
-       http://www.idt.com/products/getdoc.cfm?docid=18715691
-       http://www.idt.com/products/getdoc.cfm?docid=18715692
+       http://www.atmel.com/Images/doc8585.pdf
+  * IDT TSE2002B3, TSE2002GB2, TS3000B3, TS3000GB2
+    Prefix: 'tse2002', 'ts3000'
+    Addresses scanned: I2C 0x18 - 0x1f
+    Datasheets:
+       http://www.idt.com/sites/default/files/documents/IDT_TSE2002B3C_DST_20100512_120303152056.pdf
+       http://www.idt.com/sites/default/files/documents/IDT_TSE2002GB2A1_DST_20111107_120303145914.pdf
+       http://www.idt.com/sites/default/files/documents/IDT_TS3000B3A_DST_20101129_120303152013.pdf
+       http://www.idt.com/sites/default/files/documents/IDT_TS3000GB2A1_DST_20111104_120303151012.pdf
   * Maxim MAX6604
     Prefix: 'max6604'
     Addresses scanned: I2C 0x18 - 0x1f
     Datasheets:
        http://datasheets.maxim-ic.com/en/ds/MAX6604.pdf
-  * Microchip MCP9805, MCP98242, MCP98243, MCP9843
-    Prefixes: 'mcp9805', 'mcp98242', 'mcp98243', 'mcp9843'
+  * Microchip MCP9804, MCP9805, MCP98242, MCP98243, MCP9843
+    Prefixes: 'mcp9804', 'mcp9805', 'mcp98242', 'mcp98243', 'mcp9843'
     Addresses scanned: I2C 0x18 - 0x1f
     Datasheets:
+       http://ww1.microchip.com/downloads/en/DeviceDoc/22203C.pdf
        http://ww1.microchip.com/downloads/en/DeviceDoc/21977b.pdf
        http://ww1.microchip.com/downloads/en/DeviceDoc/21996a.pdf
        http://ww1.microchip.com/downloads/en/DeviceDoc/22153c.pdf
@@ -48,6 +56,12 @@ Supported chips:
     Datasheets:
        http://www.st.com/stonline/products/literature/ds/13447/stts424.pdf
        http://www.st.com/stonline/products/literature/ds/13448/stts424e02.pdf
+  * ST Microelectronics STTS2002, STTS3000
+    Prefix: 'stts2002', 'stts3000'
+    Addresses scanned: I2C 0x18 - 0x1f
+    Datasheets:
+       http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATASHEET/CD00225278.pdf
+       http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATA_BRIEF/CD00270920.pdf
   * JEDEC JC 42.4 compliant temperature sensor chips
     Prefix: 'jc42'
     Addresses scanned: I2C 0x18 - 0x1f
index f274c28b510355dde7c2bfca3c9fc5a4ecd0b400..2f95308251d4162ac21d4ccd3fc9454c371cb217 100644 (file)
@@ -13,7 +13,8 @@ Detection
 
 All ALPS touchpads should respond to the "E6 report" command sequence:
 E8-E6-E6-E6-E9. An ALPS touchpad should respond with either 00-00-0A or
-00-00-64.
+00-00-64 if no buttons are pressed. The bits 0-2 of the first byte will be 1s
+if some buttons are pressed.
 
 If the E6 report is successful, the touchpad model is identified using the "E7
 report" sequence: E8-E7-E7-E7-E9. The response is the model signature and is
index 033d4e69b43b107d9780ec959105823e6cefd07c..d99fd9c0ec0e16900663e1378eac9911d4afc845 100644 (file)
@@ -2211,6 +2211,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 
                        default: off.
 
+       printk.always_kmsg_dump=
+                       Trigger kmsg_dump for cases other than kernel oops or
+                       panics
+                       Format: <bool>  (1/Y/y=enable, 0/N/n=disable)
+                       default: disabled
+
        printk.time=    Show timing data prefixed to each printk message line
                        Format: <bool>  (1/Y/y=enable, 0/N/n=disable)
 
index 3b5fe0c09c2389362eda5ef7c8ad833376000a38..0d01192651efab735b803c9c9cce07ce560b8a06 100644 (file)
@@ -962,7 +962,7 @@ F:  drivers/tty/serial/msm_serial.c
 F:     drivers/platform/msm/
 F:     drivers/*/pm8???-*
 F:     include/linux/mfd/pm8xxx/
-T:     git git://codeaurora.org/quic/kernel/davidb/linux-msm.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davidb/linux-msm.git
 S:     Maintained
 
 ARM/TOSA MACHINE SUPPORT
@@ -1310,7 +1310,7 @@ F:        drivers/atm/
 F:     include/linux/atm*
 
 ATMEL AT91 MCI DRIVER
-M:     Nicolas Ferre <nicolas.ferre@atmel.com>
+M:     Ludovic Desroches <ludovic.desroches@atmel.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 W:     http://www.atmel.com/products/AT91/
 W:     http://www.at91.com/
@@ -1318,7 +1318,7 @@ S:        Maintained
 F:     drivers/mmc/host/at91_mci.c
 
 ATMEL AT91 / AT32 MCI DRIVER
-M:     Nicolas Ferre <nicolas.ferre@atmel.com>
+M:     Ludovic Desroches <ludovic.desroches@atmel.com>
 S:     Maintained
 F:     drivers/mmc/host/atmel-mci.c
 F:     drivers/mmc/host/atmel-mci-regs.h
@@ -1568,7 +1568,6 @@ F:        drivers/net/ethernet/broadcom/tg3.*
 
 BROADCOM BRCM80211 IEEE802.11n WIRELESS DRIVER
 M:     Brett Rudley <brudley@broadcom.com>
-M:     Henry Ptasinski <henryp@broadcom.com>
 M:     Roland Vossen <rvossen@broadcom.com>
 M:     Arend van Spriel <arend@broadcom.com>
 M:     Franky (Zhenhui) Lin <frankyl@broadcom.com>
@@ -3782,7 +3781,7 @@ F:        Documentation/kdump/
 
 KERNEL AUTOMOUNTER v4 (AUTOFS4)
 M:     Ian Kent <raven@themaw.net>
-L:     autofs@linux.kernel.org
+L:     autofs@vger.kernel.org
 S:     Maintained
 F:     fs/autofs4/
 
@@ -4687,7 +4686,7 @@ NTFS FILESYSTEM
 M:     Anton Altaparmakov <anton@tuxera.com>
 L:     linux-ntfs-dev@lists.sourceforge.net
 W:     http://www.tuxera.com/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/aia21/ntfs-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/aia21/ntfs.git
 S:     Supported
 F:     Documentation/filesystems/ntfs.txt
 F:     fs/ntfs/
@@ -7271,7 +7270,7 @@ WATCHDOG DEVICE DRIVERS
 M:     Wim Van Sebroeck <wim@iguana.be>
 L:     linux-watchdog@vger.kernel.org
 W:     http://www.linux-watchdog.org/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog.git
+T:     git git://www.linux-watchdog.org/linux-watchdog.git
 S:     Maintained
 F:     Documentation/watchdog/
 F:     drivers/watchdog/
index b61a9638b6fc7beb5c796c1910edf4082f4fa791..66d13c917bc7db231daa3d084a6eded9bd764f10 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 3
 PATCHLEVEL = 3
 SUBLEVEL = 0
-EXTRAVERSION = -rc5
+EXTRAVERSION = -rc6
 NAME = Saber-toothed Squirrel
 
 # *DOCUMENTATION*
index e8a761aee088a9bc5a8d2ce62d6bf1fde2183a92..f939794363ac6f94ad82a192ede6b9410f7bc002 100644 (file)
@@ -108,7 +108,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
        "       lda     $31,3b-2b(%0)\n"
        "       .previous\n"
        :       "+r"(ret), "=&r"(prev), "=&r"(cmp)
-       :       "r"(uaddr), "r"((long)oldval), "r"(newval)
+       :       "r"(uaddr), "r"((long)(int)oldval), "r"(newval)
        :       "memory");
 
        *uval = prev;
index a48aecc17eacc2e3d3f5cf4b0ff4183f29b33440..dfb0312f4e73024f14eb0181bccf9e40870cbd3a 100644 (file)
@@ -1280,7 +1280,7 @@ config ARM_ERRATA_743622
        depends on CPU_V7
        help
          This option enables the workaround for the 743622 Cortex-A9
-         (r2p0..r2p2) erratum. Under very rare conditions, a faulty
+         (r2p*) erratum. Under very rare conditions, a faulty
          optimisation in the Cortex-A9 Store Buffer may lead to data
          corruption. This workaround sets a specific bit in the diagnostic
          register of the Cortex-A9 which disables the Store Buffer
index ce1c5ff746e7d2930fc0ec2005b6e65b35bd9a91..3c79f85975aaa26c7c2e353fefc54d71d89bc5bf 100644 (file)
@@ -3,3 +3,4 @@ zImage
 xipImage
 bootpImage
 uImage
+*.dtb
index b5a5be2536c1158acf5a9c979eccb0f5588bb97c..90114faa9f3c7c087f6fce6b871b16ab5e433b44 100644 (file)
@@ -134,7 +134,7 @@ int __init armpmu_register(struct arm_pmu *armpmu, char *name, int type);
 
 u64 armpmu_event_update(struct perf_event *event,
                        struct hw_perf_event *hwc,
-                       int idx, int overflow);
+                       int idx);
 
 int armpmu_event_set_period(struct perf_event *event,
                            struct hw_perf_event *hwc,
index 4dd0edab6a658880ed505145fff2c5ce001ae639..1651d49507444267e1d5bf5783837e0f1d483420 100644 (file)
@@ -242,6 +242,7 @@ static void ecard_init_pgtables(struct mm_struct *mm)
 
        memcpy(dst_pgd, src_pgd, sizeof(pgd_t) * (EASI_SIZE / PGDIR_SIZE));
 
+       vma.vm_flags = VM_EXEC;
        vma.vm_mm = mm;
 
        flush_tlb_range(&vma, IO_START, IO_START + IO_SIZE);
index 5bb91bf3d47f24c9c6fb75324535c39e54b2c62e..b2abfa18f1378d9cea0b790e3933c60999c4eaa0 100644 (file)
@@ -180,7 +180,7 @@ armpmu_event_set_period(struct perf_event *event,
 u64
 armpmu_event_update(struct perf_event *event,
                    struct hw_perf_event *hwc,
-                   int idx, int overflow)
+                   int idx)
 {
        struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
        u64 delta, prev_raw_count, new_raw_count;
@@ -193,13 +193,7 @@ again:
                             new_raw_count) != prev_raw_count)
                goto again;
 
-       new_raw_count &= armpmu->max_period;
-       prev_raw_count &= armpmu->max_period;
-
-       if (overflow)
-               delta = armpmu->max_period - prev_raw_count + new_raw_count + 1;
-       else
-               delta = new_raw_count - prev_raw_count;
+       delta = (new_raw_count - prev_raw_count) & armpmu->max_period;
 
        local64_add(delta, &event->count);
        local64_sub(delta, &hwc->period_left);
@@ -216,7 +210,7 @@ armpmu_read(struct perf_event *event)
        if (hwc->idx < 0)
                return;
 
-       armpmu_event_update(event, hwc, hwc->idx, 0);
+       armpmu_event_update(event, hwc, hwc->idx);
 }
 
 static void
@@ -232,7 +226,7 @@ armpmu_stop(struct perf_event *event, int flags)
        if (!(hwc->state & PERF_HES_STOPPED)) {
                armpmu->disable(hwc, hwc->idx);
                barrier(); /* why? */
-               armpmu_event_update(event, hwc, hwc->idx, 0);
+               armpmu_event_update(event, hwc, hwc->idx);
                hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
        }
 }
@@ -518,7 +512,13 @@ __hw_perf_event_init(struct perf_event *event)
        hwc->config_base            |= (unsigned long)mapping;
 
        if (!hwc->sample_period) {
-               hwc->sample_period  = armpmu->max_period;
+               /*
+                * For non-sampling runs, limit the sample_period to half
+                * of the counter width. That way, the new counter value
+                * is far less likely to overtake the previous one unless
+                * you have some serious IRQ latency issues.
+                */
+               hwc->sample_period  = armpmu->max_period >> 1;
                hwc->last_period    = hwc->sample_period;
                local64_set(&hwc->period_left, hwc->sample_period);
        }
@@ -679,6 +679,28 @@ static void __init cpu_pmu_init(struct arm_pmu *armpmu)
        armpmu->type = ARM_PMU_DEVICE_CPU;
 }
 
+/*
+ * PMU hardware loses all context when a CPU goes offline.
+ * When a CPU is hotplugged back in, since some hardware registers are
+ * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading
+ * junk values out of them.
+ */
+static int __cpuinit pmu_cpu_notify(struct notifier_block *b,
+                                       unsigned long action, void *hcpu)
+{
+       if ((action & ~CPU_TASKS_FROZEN) != CPU_STARTING)
+               return NOTIFY_DONE;
+
+       if (cpu_pmu && cpu_pmu->reset)
+               cpu_pmu->reset(NULL);
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata pmu_cpu_notifier = {
+       .notifier_call = pmu_cpu_notify,
+};
+
 /*
  * CPU PMU identification and registration.
  */
@@ -730,6 +752,7 @@ init_hw_perf_events(void)
                pr_info("enabled with %s PMU driver, %d counters available\n",
                        cpu_pmu->name, cpu_pmu->num_events);
                cpu_pmu_init(cpu_pmu);
+               register_cpu_notifier(&pmu_cpu_notifier);
                armpmu_register(cpu_pmu, "cpu", PERF_TYPE_RAW);
        } else {
                pr_info("no hardware support available\n");
index 533be9930ec22f803e672a2e57217b8c65bfc40b..b78af0cc6ef36ddf8b371c9b57541b19caab5677 100644 (file)
@@ -467,23 +467,6 @@ armv6pmu_enable_event(struct hw_perf_event *hwc,
        raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
 }
 
-static int counter_is_active(unsigned long pmcr, int idx)
-{
-       unsigned long mask = 0;
-       if (idx == ARMV6_CYCLE_COUNTER)
-               mask = ARMV6_PMCR_CCOUNT_IEN;
-       else if (idx == ARMV6_COUNTER0)
-               mask = ARMV6_PMCR_COUNT0_IEN;
-       else if (idx == ARMV6_COUNTER1)
-               mask = ARMV6_PMCR_COUNT1_IEN;
-
-       if (mask)
-               return pmcr & mask;
-
-       WARN_ONCE(1, "invalid counter number (%d)\n", idx);
-       return 0;
-}
-
 static irqreturn_t
 armv6pmu_handle_irq(int irq_num,
                    void *dev)
@@ -513,7 +496,8 @@ armv6pmu_handle_irq(int irq_num,
                struct perf_event *event = cpuc->events[idx];
                struct hw_perf_event *hwc;
 
-               if (!counter_is_active(pmcr, idx))
+               /* Ignore if we don't have an event. */
+               if (!event)
                        continue;
 
                /*
@@ -524,7 +508,7 @@ armv6pmu_handle_irq(int irq_num,
                        continue;
 
                hwc = &event->hw;
-               armpmu_event_update(event, hwc, idx, 1);
+               armpmu_event_update(event, hwc, idx);
                data.period = event->hw.last_period;
                if (!armpmu_event_set_period(event, hwc, idx))
                        continue;
index 6933244c68f964ffed73f11cfbdaac1ca13b2f74..4d7095af2ab3a55075f080b3d4fee66b84d39f17 100644 (file)
@@ -809,6 +809,11 @@ static inline int armv7_pmnc_disable_intens(int idx)
 
        counter = ARMV7_IDX_TO_COUNTER(idx);
        asm volatile("mcr p15, 0, %0, c9, c14, 2" : : "r" (BIT(counter)));
+       isb();
+       /* Clear the overflow flag in case an interrupt is pending. */
+       asm volatile("mcr p15, 0, %0, c9, c12, 3" : : "r" (BIT(counter)));
+       isb();
+
        return idx;
 }
 
@@ -955,6 +960,10 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev)
                struct perf_event *event = cpuc->events[idx];
                struct hw_perf_event *hwc;
 
+               /* Ignore if we don't have an event. */
+               if (!event)
+                       continue;
+
                /*
                 * We have a single interrupt for all counters. Check that
                 * each counter has overflowed before we process it.
@@ -963,7 +972,7 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev)
                        continue;
 
                hwc = &event->hw;
-               armpmu_event_update(event, hwc, idx, 1);
+               armpmu_event_update(event, hwc, idx);
                data.period = event->hw.last_period;
                if (!armpmu_event_set_period(event, hwc, idx))
                        continue;
index 3b99d8269829b971db3d8f0618629c77d8317c5a..71a21e6712f5356daa77aa134796701101ce1a13 100644 (file)
@@ -255,11 +255,14 @@ xscale1pmu_handle_irq(int irq_num, void *dev)
                struct perf_event *event = cpuc->events[idx];
                struct hw_perf_event *hwc;
 
+               if (!event)
+                       continue;
+
                if (!xscale1_pmnc_counter_has_overflowed(pmnc, idx))
                        continue;
 
                hwc = &event->hw;
-               armpmu_event_update(event, hwc, idx, 1);
+               armpmu_event_update(event, hwc, idx);
                data.period = event->hw.last_period;
                if (!armpmu_event_set_period(event, hwc, idx))
                        continue;
@@ -592,11 +595,14 @@ xscale2pmu_handle_irq(int irq_num, void *dev)
                struct perf_event *event = cpuc->events[idx];
                struct hw_perf_event *hwc;
 
-               if (!xscale2_pmnc_counter_has_overflowed(pmnc, idx))
+               if (!event)
+                       continue;
+
+               if (!xscale2_pmnc_counter_has_overflowed(of_flags, idx))
                        continue;
 
                hwc = &event->hw;
-               armpmu_event_update(event, hwc, idx, 1);
+               armpmu_event_update(event, hwc, idx);
                data.period = event->hw.last_period;
                if (!armpmu_event_set_period(event, hwc, idx))
                        continue;
@@ -663,7 +669,7 @@ xscale2pmu_enable_event(struct hw_perf_event *hwc, int idx)
 static void
 xscale2pmu_disable_event(struct hw_perf_event *hwc, int idx)
 {
-       unsigned long flags, ien, evtsel;
+       unsigned long flags, ien, evtsel, of_flags;
        struct pmu_hw_events *events = cpu_pmu->get_hw_events();
 
        ien = xscale2pmu_read_int_enable();
@@ -672,26 +678,31 @@ xscale2pmu_disable_event(struct hw_perf_event *hwc, int idx)
        switch (idx) {
        case XSCALE_CYCLE_COUNTER:
                ien &= ~XSCALE2_CCOUNT_INT_EN;
+               of_flags = XSCALE2_CCOUNT_OVERFLOW;
                break;
        case XSCALE_COUNTER0:
                ien &= ~XSCALE2_COUNT0_INT_EN;
                evtsel &= ~XSCALE2_COUNT0_EVT_MASK;
                evtsel |= XSCALE_PERFCTR_UNUSED << XSCALE2_COUNT0_EVT_SHFT;
+               of_flags = XSCALE2_COUNT0_OVERFLOW;
                break;
        case XSCALE_COUNTER1:
                ien &= ~XSCALE2_COUNT1_INT_EN;
                evtsel &= ~XSCALE2_COUNT1_EVT_MASK;
                evtsel |= XSCALE_PERFCTR_UNUSED << XSCALE2_COUNT1_EVT_SHFT;
+               of_flags = XSCALE2_COUNT1_OVERFLOW;
                break;
        case XSCALE_COUNTER2:
                ien &= ~XSCALE2_COUNT2_INT_EN;
                evtsel &= ~XSCALE2_COUNT2_EVT_MASK;
                evtsel |= XSCALE_PERFCTR_UNUSED << XSCALE2_COUNT2_EVT_SHFT;
+               of_flags = XSCALE2_COUNT2_OVERFLOW;
                break;
        case XSCALE_COUNTER3:
                ien &= ~XSCALE2_COUNT3_INT_EN;
                evtsel &= ~XSCALE2_COUNT3_EVT_MASK;
                evtsel |= XSCALE_PERFCTR_UNUSED << XSCALE2_COUNT3_EVT_SHFT;
+               of_flags = XSCALE2_COUNT3_OVERFLOW;
                break;
        default:
                WARN_ONCE(1, "invalid counter number (%d)\n", idx);
@@ -701,6 +712,7 @@ xscale2pmu_disable_event(struct hw_perf_event *hwc, int idx)
        raw_spin_lock_irqsave(&events->pmu_lock, flags);
        xscale2pmu_write_event_select(evtsel);
        xscale2pmu_write_int_enable(ien);
+       xscale2pmu_write_overflow_flags(of_flags);
        raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
 }
 
index b7582dd10dc3bd86c577a59b5ef3c1be3269dd23..96e2adcd5a841907be15beda7bdbb67dd87b5259 100644 (file)
 #if defined(CONFIG_AT_HDMAC) || defined(CONFIG_AT_HDMAC_MODULE)
 static u64 hdmac_dmamask = DMA_BIT_MASK(32);
 
-static struct at_dma_platform_data atdma_pdata = {
-       .nr_channels    = 8,
-};
-
 static struct resource hdmac_resources[] = {
        [0] = {
                .start  = AT91SAM9G45_BASE_DMA,
@@ -56,12 +52,11 @@ static struct resource hdmac_resources[] = {
 };
 
 static struct platform_device at_hdmac_device = {
-       .name           = "at_hdmac",
+       .name           = "at91sam9g45_dma",
        .id             = -1,
        .dev            = {
                                .dma_mask               = &hdmac_dmamask,
                                .coherent_dma_mask      = DMA_BIT_MASK(32),
-                               .platform_data          = &atdma_pdata,
        },
        .resource       = hdmac_resources,
        .num_resources  = ARRAY_SIZE(hdmac_resources),
@@ -69,9 +64,15 @@ static struct platform_device at_hdmac_device = {
 
 void __init at91_add_device_hdmac(void)
 {
-       dma_cap_set(DMA_MEMCPY, atdma_pdata.cap_mask);
-       dma_cap_set(DMA_SLAVE, atdma_pdata.cap_mask);
-       platform_device_register(&at_hdmac_device);
+#if defined(CONFIG_OF)
+       struct device_node *of_node =
+               of_find_node_by_name(NULL, "dma-controller");
+
+       if (of_node)
+               of_node_put(of_node);
+       else
+#endif
+               platform_device_register(&at_hdmac_device);
 }
 #else
 void __init at91_add_device_hdmac(void) {}
index 61908dce978447156f557866055fe93da689fe52..9be71c11d0f098ddaadf4528cc2cdc1d17b52a3c 100644 (file)
 #if defined(CONFIG_AT_HDMAC) || defined(CONFIG_AT_HDMAC_MODULE)
 static u64 hdmac_dmamask = DMA_BIT_MASK(32);
 
-static struct at_dma_platform_data atdma_pdata = {
-       .nr_channels    = 2,
-};
-
 static struct resource hdmac_resources[] = {
        [0] = {
                .start  = AT91SAM9RL_BASE_DMA,
@@ -51,12 +47,11 @@ static struct resource hdmac_resources[] = {
 };
 
 static struct platform_device at_hdmac_device = {
-       .name           = "at_hdmac",
+       .name           = "at91sam9rl_dma",
        .id             = -1,
        .dev            = {
                                .dma_mask               = &hdmac_dmamask,
                                .coherent_dma_mask      = DMA_BIT_MASK(32),
-                               .platform_data          = &atdma_pdata,
        },
        .resource       = hdmac_resources,
        .num_resources  = ARRAY_SIZE(hdmac_resources),
@@ -64,7 +59,6 @@ static struct platform_device at_hdmac_device = {
 
 void __init at91_add_device_hdmac(void)
 {
-       dma_cap_set(DMA_MEMCPY, atdma_pdata.cap_mask);
        platform_device_register(&at_hdmac_device);
 }
 #else
index d5fb44f16d317e4796e9c2c08fae5cd16344f4d3..d67d0b4feb6f3fa2266e66cb878444724d97c069 100644 (file)
@@ -34,6 +34,7 @@
 #include <mach/ep93xx_spi.h>
 #include <mach/gpio-ep93xx.h>
 
+#include <asm/hardware/vic.h>
 #include <asm/mach-types.h>
 #include <asm/mach/map.h>
 #include <asm/mach/arch.h>
@@ -361,6 +362,7 @@ MACHINE_START(VISION_EP9307, "Vision Engraving Systems EP9307")
        .atag_offset    = 0x100,
        .map_io         = vision_map_io,
        .init_irq       = ep93xx_init_irq,
+       .handle_irq     = vic_handle_irq,
        .timer          = &ep93xx_timer,
        .init_machine   = vision_init_machine,
        .restart        = ep93xx_restart,
index 0fc65ffde8ff7526f0f9362c8e18e3e27e3c6539..38939956c34f7097958eda9fcd8690feac4e84ba 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/i2c.h>
 #include <linux/gpio_keys.h>
 #include <linux/gpio.h>
+#include <linux/interrupt.h>
 #include <linux/fb.h>
 #include <linux/mfd/max8998.h>
 #include <linux/regulator/machine.h>
@@ -595,6 +596,7 @@ static struct mxt_platform_data qt602240_platform_data = {
        .threshold      = 0x28,
        .voltage        = 2800000,              /* 2.8V */
        .orient         = MXT_DIAGONAL,
+       .irqflags       = IRQF_TRIGGER_FALLING,
 };
 
 static struct i2c_board_info i2c3_devs[] __initdata = {
index 2667f52e3b04da128e9ab7feef4c2fdb13b45fb1..9e3b90df32e1626c3858367910a2b446369d279d 100644 (file)
@@ -61,7 +61,7 @@
  */
 #define IRQ_LPC32XX_JTAG_COMM_TX       LPC32XX_SIC1_IRQ(1)
 #define IRQ_LPC32XX_JTAG_COMM_RX       LPC32XX_SIC1_IRQ(2)
-#define IRQ_LPC32XX_GPI_11             LPC32XX_SIC1_IRQ(4)
+#define IRQ_LPC32XX_GPI_28             LPC32XX_SIC1_IRQ(4)
 #define IRQ_LPC32XX_TS_P               LPC32XX_SIC1_IRQ(6)
 #define IRQ_LPC32XX_TS_IRQ             LPC32XX_SIC1_IRQ(7)
 #define IRQ_LPC32XX_TS_AUX             LPC32XX_SIC1_IRQ(8)
index 4eae566dfdc710934e7e834cabd7b2e83c1184cd..c74de01ab5b61bf2cd95dbdb6559545ab85e8f96 100644 (file)
@@ -118,6 +118,10 @@ static const struct lpc32xx_event_info lpc32xx_events[NR_IRQS] = {
                .event_group = &lpc32xx_event_pin_regs,
                .mask = LPC32XX_CLKPWR_EXTSRC_GPI_06_BIT,
        },
+       [IRQ_LPC32XX_GPI_28] = {
+               .event_group = &lpc32xx_event_pin_regs,
+               .mask = LPC32XX_CLKPWR_EXTSRC_GPI_28_BIT,
+       },
        [IRQ_LPC32XX_GPIO_00] = {
                .event_group = &lpc32xx_event_int_regs,
                .mask = LPC32XX_CLKPWR_INTSRC_GPIO_00_BIT,
@@ -305,9 +309,18 @@ static int lpc32xx_irq_wake(struct irq_data *d, unsigned int state)
 
                if (state)
                        eventreg |= lpc32xx_events[d->irq].mask;
-               else
+               else {
                        eventreg &= ~lpc32xx_events[d->irq].mask;
 
+                       /*
+                        * When disabling the wakeup, clear the latched
+                        * event
+                        */
+                       __raw_writel(lpc32xx_events[d->irq].mask,
+                               lpc32xx_events[d->irq].
+                               event_group->rawstat_reg);
+               }
+
                __raw_writel(eventreg,
                        lpc32xx_events[d->irq].event_group->enab_reg);
 
@@ -380,13 +393,15 @@ void __init lpc32xx_init_irq(void)
 
        /* Setup SIC1 */
        __raw_writel(0, LPC32XX_INTC_MASK(LPC32XX_SIC1_BASE));
-       __raw_writel(MIC_APR_DEFAULT, LPC32XX_INTC_POLAR(LPC32XX_SIC1_BASE));
-       __raw_writel(MIC_ATR_DEFAULT, LPC32XX_INTC_ACT_TYPE(LPC32XX_SIC1_BASE));
+       __raw_writel(SIC1_APR_DEFAULT, LPC32XX_INTC_POLAR(LPC32XX_SIC1_BASE));
+       __raw_writel(SIC1_ATR_DEFAULT,
+                               LPC32XX_INTC_ACT_TYPE(LPC32XX_SIC1_BASE));
 
        /* Setup SIC2 */
        __raw_writel(0, LPC32XX_INTC_MASK(LPC32XX_SIC2_BASE));
-       __raw_writel(MIC_APR_DEFAULT, LPC32XX_INTC_POLAR(LPC32XX_SIC2_BASE));
-       __raw_writel(MIC_ATR_DEFAULT, LPC32XX_INTC_ACT_TYPE(LPC32XX_SIC2_BASE));
+       __raw_writel(SIC2_APR_DEFAULT, LPC32XX_INTC_POLAR(LPC32XX_SIC2_BASE));
+       __raw_writel(SIC2_ATR_DEFAULT,
+                               LPC32XX_INTC_ACT_TYPE(LPC32XX_SIC2_BASE));
 
        /* Configure supported IRQ's */
        for (i = 0; i < NR_IRQS; i++) {
index 429cfdbb2b3d60c29f4c3fc12d4a5001aa2dd219..f2735281616a1d8a9e008c09d7483fa637a314cf 100644 (file)
@@ -88,6 +88,7 @@ struct uartinit {
        char *uart_ck_name;
        u32 ck_mode_mask;
        void __iomem *pdiv_clk_reg;
+       resource_size_t mapbase;
 };
 
 static struct uartinit uartinit_data[] __initdata = {
@@ -97,6 +98,7 @@ static struct uartinit uartinit_data[] __initdata = {
                .ck_mode_mask =
                        LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 5),
                .pdiv_clk_reg = LPC32XX_CLKPWR_UART5_CLK_CTRL,
+               .mapbase = LPC32XX_UART5_BASE,
        },
 #endif
 #ifdef CONFIG_ARCH_LPC32XX_UART3_SELECT
@@ -105,6 +107,7 @@ static struct uartinit uartinit_data[] __initdata = {
                .ck_mode_mask =
                        LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 3),
                .pdiv_clk_reg = LPC32XX_CLKPWR_UART3_CLK_CTRL,
+               .mapbase = LPC32XX_UART3_BASE,
        },
 #endif
 #ifdef CONFIG_ARCH_LPC32XX_UART4_SELECT
@@ -113,6 +116,7 @@ static struct uartinit uartinit_data[] __initdata = {
                .ck_mode_mask =
                        LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 4),
                .pdiv_clk_reg = LPC32XX_CLKPWR_UART4_CLK_CTRL,
+               .mapbase = LPC32XX_UART4_BASE,
        },
 #endif
 #ifdef CONFIG_ARCH_LPC32XX_UART6_SELECT
@@ -121,6 +125,7 @@ static struct uartinit uartinit_data[] __initdata = {
                .ck_mode_mask =
                        LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 6),
                .pdiv_clk_reg = LPC32XX_CLKPWR_UART6_CLK_CTRL,
+               .mapbase = LPC32XX_UART6_BASE,
        },
 #endif
 };
@@ -165,11 +170,24 @@ void __init lpc32xx_serial_init(void)
 
                /* pre-UART clock divider set to 1 */
                __raw_writel(0x0101, uartinit_data[i].pdiv_clk_reg);
+
+               /*
+                * Force a flush of the RX FIFOs to work around a
+                * HW bug
+                */
+               puart = uartinit_data[i].mapbase;
+               __raw_writel(0xC1, LPC32XX_UART_IIR_FCR(puart));
+               __raw_writel(0x00, LPC32XX_UART_DLL_FIFO(puart));
+               j = LPC32XX_SUART_FIFO_SIZE;
+               while (j--)
+                       tmp = __raw_readl(
+                               LPC32XX_UART_DLL_FIFO(puart));
+               __raw_writel(0, LPC32XX_UART_IIR_FCR(puart));
        }
 
        /* This needs to be done after all UART clocks are setup */
        __raw_writel(clkmodes, LPC32XX_UARTCTL_CLKMODE);
-       for (i = 0; i < ARRAY_SIZE(uartinit_data) - 1; i++) {
+       for (i = 0; i < ARRAY_SIZE(uartinit_data); i++) {
                /* Force a flush of the RX FIFOs to work around a HW bug */
                puart = serial_std_platform_data[i].mapbase;
                __raw_writel(0xC1, LPC32XX_UART_IIR_FCR(puart));
index 17cb76060125ef0be126d5cc7f8d8c843e390f38..3588a55841532f4dc0c6c5268ec87b0e0c40319a 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/nand.h>
 #include <linux/interrupt.h>
-#include <linux/gpio.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
index 7bc17eaa12eba3835392554aa893aff71641fdac..ada1213982b4a6da1d3abae4235385a724c3e235 100644 (file)
@@ -24,7 +24,6 @@
 #include <mach/dma.h>
 #include <mach/devices.h>
 #include <mach/mfp.h>
-#include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #include <mach/pxa168.h>
 
index 8e3b5af04a57127aafbc7ee8f892828905835ddb..bc97170125bf6b410d04af230c2961d9739d2714 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/smc91x.h>
-#include <linux/gpio.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
index 309369ea6978e59367e7e884875706b52f85478d..be2002f42dea61fec5ba1c1285c995266b42cdee 100644 (file)
@@ -416,13 +416,13 @@ static void __init innovator_init(void)
 #ifdef CONFIG_ARCH_OMAP15XX
        if (cpu_is_omap1510()) {
                omap1_usb_init(&innovator1510_usb_config);
-               innovator_config[1].data = &innovator1510_lcd_config;
+               innovator_config[0].data = &innovator1510_lcd_config;
        }
 #endif
 #ifdef CONFIG_ARCH_OMAP16XX
        if (cpu_is_omap1610()) {
                omap1_usb_init(&h2_usb_config);
-               innovator_config[1].data = &innovator1610_lcd_config;
+               innovator_config[0].data = &innovator1610_lcd_config;
        }
 #endif
        omap_board_config = innovator_config;
index d965da45160e67c4e03056a7d8c0d72178575042..e20c8ab80b0e189e4960599a1b7ee79875815a9f 100644 (file)
@@ -364,8 +364,8 @@ config OMAP3_SDRC_AC_TIMING
          going on could result in system crashes;
 
 config OMAP4_ERRATA_I688
-       bool "OMAP4 errata: Async Bridge Corruption (BROKEN)"
-       depends on ARCH_OMAP4 && BROKEN
+       bool "OMAP4 errata: Async Bridge Corruption"
+       depends on ARCH_OMAP4
        select ARCH_HAS_BARRIERS
        help
          If a data is stalled inside asynchronous bridge because of back
index 42a4d11fad23de92c36cec7a87fe5ebfd34e4bbe..672262717601e012affe2a2f7e952c917ec22871 100644 (file)
@@ -371,7 +371,11 @@ static void n8x0_mmc_callback(void *data, u8 card_mask)
        else
                *openp = 0;
 
+#ifdef CONFIG_MMC_OMAP
        omap_mmc_notify_cover_event(mmc_device, index, *openp);
+#else
+       pr_warn("MMC: notify cover event not available\n");
+#endif
 }
 
 static int n8x0_mmc_late_init(struct device *dev)
index c775bead1497c3f487e22696bee4b59c6c46eeed..c877236a8442d235a4803c0903eb913d69ca3096 100644 (file)
@@ -381,7 +381,7 @@ static int omap3evm_twl_gpio_setup(struct device *dev,
        gpio_request_one(gpio + 7, GPIOF_OUT_INIT_LOW, "EN_DVI");
 
        /* TWL4030_GPIO_MAX + 1 == ledB (out, active low LED) */
-       gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1;
+       gpio_leds[0].gpio = gpio + TWL4030_GPIO_MAX + 1;
 
        platform_device_register(&leds_gpio);
 
index febffde2ff109ed4682fe0e311f93ee23aee2cbd..7e9338e8d684c7ff442a517be55de218ba34e8c7 100644 (file)
@@ -132,6 +132,7 @@ void omap3_map_io(void);
 void am33xx_map_io(void);
 void omap4_map_io(void);
 void ti81xx_map_io(void);
+void omap_barriers_init(void);
 
 /**
  * omap_test_timeout - busy-loop, testing a condition
index cfdbb86bc84e5aae04357abce9b46d690ab0ccd7..72e018b9b260db422108f7d70084c7ae8d41ba2b 100644 (file)
@@ -65,7 +65,6 @@ static int omap4_enter_idle(struct cpuidle_device *dev,
        struct timespec ts_preidle, ts_postidle, ts_idle;
        u32 cpu1_state;
        int idle_time;
-       int new_state_idx;
        int cpu_id = smp_processor_id();
 
        /* Used to keep track of the total time in idle */
@@ -84,8 +83,8 @@ static int omap4_enter_idle(struct cpuidle_device *dev,
         */
        cpu1_state = pwrdm_read_pwrst(cpu1_pd);
        if (cpu1_state != PWRDM_POWER_OFF) {
-               new_state_idx = drv->safe_state_index;
-               cx = cpuidle_get_statedata(&dev->states_usage[new_state_idx]);
+               index = drv->safe_state_index;
+               cx = cpuidle_get_statedata(&dev->states_usage[index]);
        }
 
        if (index > 0)
index 997033129d2642fc022702c316c71e4376679fb1..bbb870c04a5e3ed3aa4f61777c187f3e33358ee9 100644 (file)
@@ -19,6 +19,8 @@
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/smsc911x.h>
+#include <linux/regulator/fixed.h>
+#include <linux/regulator/machine.h>
 
 #include <plat/board.h>
 #include <plat/gpmc.h>
@@ -42,6 +44,50 @@ static struct smsc911x_platform_config gpmc_smsc911x_config = {
        .flags          = SMSC911X_USE_16BIT,
 };
 
+static struct regulator_consumer_supply gpmc_smsc911x_supply[] = {
+       REGULATOR_SUPPLY("vddvario", "smsc911x.0"),
+       REGULATOR_SUPPLY("vdd33a", "smsc911x.0"),
+};
+
+/* Generic regulator definition to satisfy smsc911x */
+static struct regulator_init_data gpmc_smsc911x_reg_init_data = {
+       .constraints = {
+               .min_uV                 = 3300000,
+               .max_uV                 = 3300000,
+               .valid_modes_mask       = REGULATOR_MODE_NORMAL
+                                       | REGULATOR_MODE_STANDBY,
+               .valid_ops_mask         = REGULATOR_CHANGE_MODE
+                                       | REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies  = ARRAY_SIZE(gpmc_smsc911x_supply),
+       .consumer_supplies      = gpmc_smsc911x_supply,
+};
+
+static struct fixed_voltage_config gpmc_smsc911x_fixed_reg_data = {
+       .supply_name            = "gpmc_smsc911x",
+       .microvolts             = 3300000,
+       .gpio                   = -EINVAL,
+       .startup_delay          = 0,
+       .enable_high            = 0,
+       .enabled_at_boot        = 1,
+       .init_data              = &gpmc_smsc911x_reg_init_data,
+};
+
+/*
+ * Platform device id of 42 is a temporary fix to avoid conflicts
+ * with other reg-fixed-voltage devices. The real fix should
+ * involve the driver core providing a way of dynamically
+ * assigning a unique id on registration for platform devices
+ * in the same name space.
+ */
+static struct platform_device gpmc_smsc911x_regulator = {
+       .name           = "reg-fixed-voltage",
+       .id             = 42,
+       .dev = {
+               .platform_data  = &gpmc_smsc911x_fixed_reg_data,
+       },
+};
+
 /*
  * Initialize smsc911x device connected to the GPMC. Note that we
  * assume that pin multiplexing is done in the board-*.c file,
@@ -55,6 +101,12 @@ void __init gpmc_smsc911x_init(struct omap_smsc911x_platform_data *board_data)
 
        gpmc_cfg = board_data;
 
+       ret = platform_device_register(&gpmc_smsc911x_regulator);
+       if (ret < 0) {
+               pr_err("Unable to register smsc911x regulators: %d\n", ret);
+               return;
+       }
+
        if (gpmc_cs_request(gpmc_cfg->cs, SZ_16M, &cs_mem_base) < 0) {
                pr_err("Failed to request GPMC mem region\n");
                return;
index b40c288952987a2327d950abbfe374193f8f59e7..19dd1657245c58634dc3ac1e8005e823e7360dd5 100644 (file)
@@ -428,6 +428,7 @@ static int omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c,
        return 0;
 }
 
+static int omap_hsmmc_done;
 #define MAX_OMAP_MMC_HWMOD_NAME_LEN            16
 
 void omap_init_hsmmc(struct omap2_hsmmc_info *hsmmcinfo, int ctrl_nr)
@@ -491,6 +492,11 @@ void omap2_hsmmc_init(struct omap2_hsmmc_info *controllers)
 {
        u32 reg;
 
+       if (omap_hsmmc_done)
+               return;
+
+       omap_hsmmc_done = 1;
+
        if (!cpu_is_omap44xx()) {
                if (cpu_is_omap2430()) {
                        control_pbias_offset = OMAP243X_CONTROL_PBIAS_LITE;
index 6c5826605eaec5792b5f93c137fc9e32c2bc9f9f..719ee423abe22be6439cb4b3dd0ce78dcecb41b5 100644 (file)
@@ -343,6 +343,7 @@ static void __init omap3_check_revision(const char **cpu_rev)
        case 0xb944:
                omap_revision = AM335X_REV_ES1_0;
                *cpu_rev = "1.0";
+               break;
        case 0xb8f2:
                switch (rev) {
                case 0:
index eb50c29fb6448e1404eef693e8f74c5e10641aed..fb11b44fbdecc77d6c8b5ce41e5da4f0aeecc1fc 100644 (file)
@@ -307,6 +307,7 @@ void __init omapam33xx_map_common_io(void)
 void __init omap44xx_map_common_io(void)
 {
        iotable_init(omap44xx_io_desc, ARRAY_SIZE(omap44xx_io_desc));
+       omap_barriers_init();
 }
 #endif
 
index 609ea2ded7e388a22ed9c9d59ba888672ebb13ab..415a6f1cf419dc8a5ab86f2ccff1bce06324b3c0 100644 (file)
@@ -281,8 +281,16 @@ static struct omap_mbox mbox_iva_info = {
        .ops    = &omap2_mbox_ops,
        .priv   = &omap2_mbox_iva_priv,
 };
+#endif
 
-struct omap_mbox *omap2_mboxes[] = { &mbox_dsp_info, &mbox_iva_info, NULL };
+#ifdef CONFIG_ARCH_OMAP2
+struct omap_mbox *omap2_mboxes[] = {
+       &mbox_dsp_info,
+#ifdef CONFIG_SOC_OMAP2420
+       &mbox_iva_info,
+#endif
+       NULL
+};
 #endif
 
 #if defined(CONFIG_ARCH_OMAP4)
index fb8bc9fa43b140fbfd5050ebc478833877b8066f..611a0e3d54ca34c47f8180faed43932191df26cf 100644 (file)
@@ -218,7 +218,7 @@ static int _omap_mux_get_by_name(struct omap_mux_partition *partition,
        return -ENODEV;
 }
 
-static int __init
+static int
 omap_mux_get_by_name(const char *muxname,
                        struct omap_mux_partition **found_partition,
                        struct omap_mux **found_mux)
index b8822048e409c490c949bd8eb4e7329967ac12c9..ac49384d028521deceb8e11355b46fbd4a2ec1b9 100644 (file)
@@ -150,7 +150,8 @@ err_out:
                platform_device_put(omap_iommu_pdev[i]);
        return err;
 }
-module_init(omap_iommu_init);
+/* must be ready before omap3isp is probed */
+subsys_initcall(omap_iommu_init);
 
 static void __exit omap_iommu_exit(void)
 {
index 40a8fbc07e4b766717b35e8b69f88794c1335df7..70de277f5c152199a66a7b9682acdc51a386bdc6 100644 (file)
 
 #include <plat/irqs.h>
 #include <plat/sram.h>
+#include <plat/omap-secure.h>
 
 #include <mach/hardware.h>
 #include <mach/omap-wakeupgen.h>
 
 #include "common.h"
 #include "omap4-sar-layout.h"
+#include <linux/export.h>
 
 #ifdef CONFIG_CACHE_L2X0
 static void __iomem *l2cache_base;
@@ -43,6 +45,9 @@ static void __iomem *sar_ram_base;
 
 void __iomem *dram_sync, *sram_sync;
 
+static phys_addr_t paddr;
+static u32 size;
+
 void omap_bus_sync(void)
 {
        if (dram_sync && sram_sync) {
@@ -51,19 +56,22 @@ void omap_bus_sync(void)
                isb();
        }
 }
+EXPORT_SYMBOL(omap_bus_sync);
 
-static int __init omap_barriers_init(void)
+/* Steal one page physical memory for barrier implementation */
+int __init omap_barrier_reserve_memblock(void)
 {
-       struct map_desc dram_io_desc[1];
-       phys_addr_t paddr;
-       u32 size;
-
-       if (!cpu_is_omap44xx())
-               return -ENODEV;
 
        size = ALIGN(PAGE_SIZE, SZ_1M);
        paddr = arm_memblock_steal(size, SZ_1M);
 
+       return 0;
+}
+
+void __init omap_barriers_init(void)
+{
+       struct map_desc dram_io_desc[1];
+
        dram_io_desc[0].virtual = OMAP4_DRAM_BARRIER_VA;
        dram_io_desc[0].pfn = __phys_to_pfn(paddr);
        dram_io_desc[0].length = size;
@@ -75,9 +83,10 @@ static int __init omap_barriers_init(void)
        pr_info("OMAP4: Map 0x%08llx to 0x%08lx for dram barrier\n",
                (long long) paddr, dram_io_desc[0].virtual);
 
-       return 0;
 }
-core_initcall(omap_barriers_init);
+#else
+void __init omap_barriers_init(void)
+{}
 #endif
 
 void __init gic_init_irq(void)
index 1881fe9151495ba4fd542146fcee7c208565cb63..5a65dd04aa38ba8298168a5cb80e1d50766f1136 100644 (file)
@@ -174,14 +174,17 @@ static int __init omap2_set_init_voltage(char *vdd_name, char *clk_name,
        freq = clk->rate;
        clk_put(clk);
 
+       rcu_read_lock();
        opp = opp_find_freq_ceil(dev, &freq);
        if (IS_ERR(opp)) {
+               rcu_read_unlock();
                pr_err("%s: unable to find boot up OPP for vdd_%s\n",
                        __func__, vdd_name);
                goto exit;
        }
 
        bootup_volt = opp_get_voltage(opp);
+       rcu_read_unlock();
        if (!bootup_volt) {
                pr_err("%s: unable to find voltage corresponding "
                        "to the bootup OPP for vdd_%s\n", __func__, vdd_name);
index 10b20c652e5dc390026bc1eec5042ff351c387f4..4b57757bf9d1200cf4e47e099734ec424cad47d2 100644 (file)
@@ -270,7 +270,6 @@ static struct regulator_init_data omap4_vusb_idata = {
        .constraints = {
                .min_uV                 = 3300000,
                .max_uV                 = 3300000,
-               .apply_uV               = true,
                .valid_modes_mask       = REGULATOR_MODE_NORMAL
                                        | REGULATOR_MODE_STANDBY,
                .valid_ops_mask         = REGULATOR_CHANGE_MODE
index 771dc781b746377707c23f01b2cff2516711f6ec..f51348dafafdfb8ec85f48af6740fef8629f42b4 100644 (file)
@@ -486,7 +486,7 @@ static void setup_4430ohci_io_mux(const enum usbhs_omap_port_mode *port_mode)
 void __init usbhs_init(const struct usbhs_omap_board_data *pdata)
 {
        struct omap_hwmod       *oh[2];
-       struct omap_device      *od;
+       struct platform_device  *pdev;
        int                     bus_id = -1;
        int                     i;
 
@@ -522,11 +522,11 @@ void __init usbhs_init(const struct usbhs_omap_board_data *pdata)
                return;
        }
 
-       od = omap_device_build_ss(OMAP_USBHS_DEVICE, bus_id, oh, 2,
+       pdev = omap_device_build_ss(OMAP_USBHS_DEVICE, bus_id, oh, 2,
                                (void *)&usbhs_data, sizeof(usbhs_data),
                                omap_uhhtll_latency,
                                ARRAY_SIZE(omap_uhhtll_latency), false);
-       if (IS_ERR(od)) {
+       if (IS_ERR(pdev)) {
                pr_err("Could not build hwmod devices %s,%s\n",
                        USBHS_UHH_HWMODNAME, USBHS_TLL_HWMODNAME);
                return;
index 0d729e6619dfb411c6b4a5e875cc4e75a1928731..42d5cca66257bd1be97cb0c0b37c8569476d0795 100644 (file)
@@ -49,7 +49,6 @@ extern unsigned pxa3xx_get_clk_frequency_khz(int);
 #endif
 
 extern struct syscore_ops pxa_irq_syscore_ops;
-extern struct syscore_ops pxa_gpio_syscore_ops;
 extern struct syscore_ops pxa2xx_mfp_syscore_ops;
 extern struct syscore_ops pxa3xx_mfp_syscore_ops;
 
index fb9b62dcf4ca44099bbbca6cc02f750cd451384c..208eef1c04858a8ec76c40adcaddc131e5b5fb7f 100644 (file)
@@ -45,6 +45,7 @@
 #include <mach/hx4700.h>
 #include <mach/irda.h>
 
+#include <sound/ak4641.h>
 #include <video/platform_lcd.h>
 #include <video/w100fb.h>
 
@@ -764,6 +765,28 @@ static struct i2c_board_info __initdata pi2c_board_info[] = {
        },
 };
 
+/*
+ * Asahi Kasei AK4641 on I2C
+ */
+
+static struct ak4641_platform_data ak4641_info = {
+       .gpio_power = GPIO27_HX4700_CODEC_ON,
+       .gpio_npdn  = GPIO109_HX4700_CODEC_nPDN,
+};
+
+static struct i2c_board_info i2c_board_info[] __initdata = {
+       {
+               I2C_BOARD_INFO("ak4641", 0x12),
+               .platform_data = &ak4641_info,
+       },
+};
+
+static struct platform_device audio = {
+       .name   = "hx4700-audio",
+       .id     = -1,
+};
+
+
 /*
  * PCMCIA
  */
@@ -790,6 +813,7 @@ static struct platform_device *devices[] __initdata = {
        &gpio_vbus,
        &power_supply,
        &strataflash,
+       &audio,
        &pcmcia,
 };
 
@@ -827,6 +851,7 @@ static void __init hx4700_init(void)
        pxa_set_ficp_info(&ficp_info);
        pxa27x_set_i2c_power_info(NULL);
        pxa_set_i2c_info(NULL);
+       i2c_register_board_info(0, ARRAY_AND_SIZE(i2c_board_info));
        i2c_register_board_info(1, ARRAY_AND_SIZE(pi2c_board_info));
        pxa2xx_set_spi_info(2, &pxa_ssp2_master_info);
        spi_register_board_info(ARRAY_AND_SIZE(tsc2046_board_info));
index f14775536b8385172e929791a627c3a689fb94ac..29b62afc6f7ca3d219b4f4498c4b62b3a6fee223 100644 (file)
@@ -226,6 +226,12 @@ static void __init pxa25x_mfp_init(void)
 {
        int i;
 
+       /* running before pxa_gpio_probe() */
+#ifdef CONFIG_CPU_PXA26x
+       pxa_last_gpio = 89;
+#else
+       pxa_last_gpio = 84;
+#endif
        for (i = 0; i <= pxa_last_gpio; i++)
                gpio_desc[i].valid = 1;
 
@@ -295,6 +301,7 @@ static void __init pxa27x_mfp_init(void)
 {
        int i, gpio;
 
+       pxa_last_gpio = 120;    /* running before pxa_gpio_probe() */
        for (i = 0; i <= pxa_last_gpio; i++) {
                /* skip GPIO2, 5, 6, 7, 8, they are not
                 * valid pins allow configuration
index 91e4f6c037661420e5f3e02e30af9174eef9edfd..3352b37b60cf8218025ab54df4af1358ed62ae1f 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/suspend.h>
 #include <linux/syscore_ops.h>
 #include <linux/irq.h>
-#include <linux/gpio.h>
 
 #include <asm/mach/map.h>
 #include <asm/suspend.h>
@@ -209,6 +208,7 @@ static struct clk_lookup pxa25x_clkregs[] = {
        INIT_CLKREG(&clk_pxa25x_gpio11, NULL, "GPIO11_CLK"),
        INIT_CLKREG(&clk_pxa25x_gpio12, NULL, "GPIO12_CLK"),
        INIT_CLKREG(&clk_pxa25x_mem, "pxa2xx-pcmcia", NULL),
+       INIT_CLKREG(&clk_dummy, "pxa-gpio", NULL),
 };
 
 static struct clk_lookup pxa25x_hwuart_clkreg =
@@ -368,7 +368,6 @@ static int __init pxa25x_init(void)
 
                register_syscore_ops(&pxa_irq_syscore_ops);
                register_syscore_ops(&pxa2xx_mfp_syscore_ops);
-               register_syscore_ops(&pxa_gpio_syscore_ops);
                register_syscore_ops(&pxa2xx_clock_syscore_ops);
 
                ret = platform_add_devices(pxa25x_devices,
index aed6cbcf386641e45147d67cb036301e9a6a54e6..6bce78edce7a3c070b197b57f1fcb16197c3ba7f 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/i2c/pxa-i2c.h>
-#include <linux/gpio.h>
 
 #include <asm/mach/map.h>
 #include <mach/hardware.h>
@@ -230,6 +229,7 @@ static struct clk_lookup pxa27x_clkregs[] = {
        INIT_CLKREG(&clk_pxa27x_im, NULL, "IMCLK"),
        INIT_CLKREG(&clk_pxa27x_memc, NULL, "MEMCLK"),
        INIT_CLKREG(&clk_pxa27x_mem, "pxa2xx-pcmcia", NULL),
+       INIT_CLKREG(&clk_dummy, "pxa-gpio", NULL),
 };
 
 #ifdef CONFIG_PM
@@ -456,7 +456,6 @@ static int __init pxa27x_init(void)
 
                register_syscore_ops(&pxa_irq_syscore_ops);
                register_syscore_ops(&pxa2xx_mfp_syscore_ops);
-               register_syscore_ops(&pxa_gpio_syscore_ops);
                register_syscore_ops(&pxa2xx_clock_syscore_ops);
 
                ret = platform_add_devices(devices, ARRAY_SIZE(devices));
index 4f402afa6609c0ed584100d951347ec1272f8531..3918a672238e4a368f0474c699ebc1c2cb680bb7 100644 (file)
@@ -462,7 +462,6 @@ static int __init pxa3xx_init(void)
 
                register_syscore_ops(&pxa_irq_syscore_ops);
                register_syscore_ops(&pxa3xx_mfp_syscore_ops);
-               register_syscore_ops(&pxa_gpio_syscore_ops);
                register_syscore_ops(&pxa3xx_clock_syscore_ops);
 
                ret = platform_add_devices(devices, ARRAY_SIZE(devices));
index d082a583df78a14c0bc4074db270bb8ce2393ca1..5ce434b95e87a52941f38ca8e023753b940802e5 100644 (file)
@@ -283,7 +283,6 @@ static int __init pxa95x_init(void)
                        return ret;
 
                register_syscore_ops(&pxa_irq_syscore_ops);
-               register_syscore_ops(&pxa_gpio_syscore_ops);
                register_syscore_ops(&pxa3xx_clock_syscore_ops);
 
                ret = platform_add_devices(devices, ARRAY_SIZE(devices));
index febc809ed5a6bd0657054bb78f59804e2a354f0a..5aded5e6148f55927f426d7abc46dcbacb372d38 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/i2c.h>
 #include <linux/i2c/pxa-i2c.h>
 #include <linux/mfd/88pm860x.h>
-#include <linux/gpio.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
index 8d5168d253a9c8829b54c2b09ea6b4e57b8c5fe5..30989baf7f2aa93a9cc0bd3e60c909a4b9f17e80 100644 (file)
@@ -168,6 +168,7 @@ struct battery_thresh sharpsl_battery_levels_noac[] = {
 #define MAXCTRL_SEL_SH   4
 #define MAXCTRL_STR      (1u << 7)
 
+extern int max1111_read_channel(int);
 /*
  * Read MAX1111 ADC
  */
@@ -177,8 +178,6 @@ int sharpsl_pm_pxa_read_max1111(int channel)
        if (machine_is_tosa())
            return 0;
 
-       extern int max1111_read_channel(int);
-
        /* max1111 accepts channels from 0-3, however,
         * it is encoded from 0-7 here in the code.
         */
index 34cbdac51525524517bbedd355df413e9b9c89a1..438f02fe122a6d1d727671675af53b7564b99ae4 100644 (file)
@@ -172,10 +172,9 @@ static int spitz_should_wakeup(unsigned int resume_on_alarm)
 static unsigned long spitz_charger_wakeup(void)
 {
        unsigned long ret;
-       ret = (!gpio_get_value(SPITZ_GPIO_KEY_INT)
+       ret = ((!gpio_get_value(SPITZ_GPIO_KEY_INT)
                << GPIO_bit(SPITZ_GPIO_KEY_INT))
-               | (!gpio_get_value(SPITZ_GPIO_SYNC)
-               << GPIO_bit(SPITZ_GPIO_SYNC));
+               | gpio_get_value(SPITZ_GPIO_SYNC));
        return ret;
 }
 
index db8a98ac68c54dea4e51e526fa0f7ed809e4e8c7..0c1eb1dfc534ac3d564d660d855d8ab32bea4a73 100644 (file)
@@ -12,6 +12,6 @@
 #ifndef __ARCH_ARM_MACH_S3C2440_COMMON_H
 #define __ARCH_ARM_MACH_S3C2440_COMMON_H
 
-void s3c2440_restart(char mode, const char *cmd);
+void s3c244x_restart(char mode, const char *cmd);
 
 #endif /* __ARCH_ARM_MACH_S3C2440_COMMON_H */
index 24569550de1aa4967d9c2748310496c7425500b6..19b577bc09b80cbc3789c511c9f0c9d19c618c1e 100644 (file)
@@ -487,5 +487,5 @@ MACHINE_START(ANUBIS, "Simtec-Anubis")
        .init_machine   = anubis_init,
        .init_irq       = s3c24xx_init_irq,
        .timer          = &s3c24xx_timer,
-       .restart        = s3c2440_restart,
+       .restart        = s3c244x_restart,
 MACHINE_END
index d6a9763110cdccaa22e543eeea09d1d8faa6a321..d7ae49c90118443cf0cc218f04a687945b6d1ab4 100644 (file)
@@ -222,5 +222,5 @@ MACHINE_START(AT2440EVB, "AT2440EVB")
        .init_machine   = at2440evb_init,
        .init_irq       = s3c24xx_init_irq,
        .timer          = &s3c24xx_timer,
-       .restart        = s3c2440_restart,
+       .restart        = s3c244x_restart,
 MACHINE_END
index 5859e609d28c51382009a01a9ced278054985987..9a4a5bc008e66149433ca0edc9147f14cfdc96f6 100644 (file)
@@ -601,5 +601,5 @@ MACHINE_START(NEO1973_GTA02, "GTA02")
        .init_irq       = s3c24xx_init_irq,
        .init_machine   = gta02_machine_init,
        .timer          = &s3c24xx_timer,
-       .restart        = s3c2440_restart,
+       .restart        = s3c244x_restart,
 MACHINE_END
index adbbb85bc4cdd636f4196c4bf50468a21d7f0974..5d66fb218a41bcb121c5845e201009ffe0a0bbab 100644 (file)
@@ -701,5 +701,5 @@ MACHINE_START(MINI2440, "MINI2440")
        .init_machine   = mini2440_init,
        .init_irq       = s3c24xx_init_irq,
        .timer          = &s3c24xx_timer,
-       .restart        = s3c2440_restart,
+       .restart        = s3c244x_restart,
 MACHINE_END
index 40eaf844bc1f61aa92b4dd33250850025bf380e8..5198e3e1c5bedb1fcf5d60820d6ffd4ef30675a1 100644 (file)
@@ -158,5 +158,5 @@ MACHINE_START(NEXCODER_2440, "NexVision - Nexcoder 2440")
        .init_machine   = nexcoder_init,
        .init_irq       = s3c24xx_init_irq,
        .timer          = &s3c24xx_timer,
-       .restart        = s3c2440_restart,
+       .restart        = s3c244x_restart,
 MACHINE_END
index 4c480ef734f64ed97d5a8953f632ceb877464147..c5daeb612a88a35235c0f879e6789e0a94f0c1c1 100644 (file)
@@ -436,5 +436,5 @@ MACHINE_START(OSIRIS, "Simtec-OSIRIS")
        .init_irq       = s3c24xx_init_irq,
        .init_machine   = osiris_init,
        .timer          = &s3c24xx_timer,
-       .restart        = s3c2440_restart,
+       .restart        = s3c244x_restart,
 MACHINE_END
index 80077f6472ee7d7d4acfc1084a10ca94a85b0bbf..6f68abf44fab75156f6be5b69f7b32ba07582780 100644 (file)
@@ -822,5 +822,5 @@ MACHINE_START(RX1950, "HP iPAQ RX1950")
        .init_irq = s3c24xx_init_irq,
        .init_machine = rx1950_init_machine,
        .timer = &s3c24xx_timer,
-       .restart        = s3c2440_restart,
+       .restart        = s3c244x_restart,
 MACHINE_END
index 20103bafbd4bfa34b2e6d58e14b0d10d4486b3cd..56af354475984edf7af488359991fb6041baef9b 100644 (file)
@@ -213,5 +213,5 @@ MACHINE_START(RX3715, "IPAQ-RX3715")
        .init_irq       = rx3715_init_irq,
        .init_machine   = rx3715_init_machine,
        .timer          = &s3c24xx_timer,
-       .restart        = s3c2440_restart,
+       .restart        = s3c244x_restart,
 MACHINE_END
index 1deb60d12a60612284c3e1c0e6c141f5509dd9e4..83a1036d7dcbe5a7d329ba1f12856ccf4d657795 100644 (file)
@@ -183,5 +183,5 @@ MACHINE_START(S3C2440, "SMDK2440")
        .map_io         = smdk2440_map_io,
        .init_machine   = smdk2440_machine_init,
        .timer          = &s3c24xx_timer,
-       .restart        = s3c2440_restart,
+       .restart        = s3c244x_restart,
 MACHINE_END
index 517623a09fc5464f9c7209baa7ef3d8e0aa9fcce..2b3dddb49af75939d397d1f395cf2cc068ded504 100644 (file)
@@ -35,7 +35,6 @@
 #include <plat/cpu.h>
 #include <plat/s3c244x.h>
 #include <plat/pm.h>
-#include <plat/watchdog-reset.h>
 
 #include <plat/gpio-core.h>
 #include <plat/gpio-cfg.h>
@@ -74,15 +73,3 @@ void __init s3c2440_map_io(void)
        s3c24xx_gpiocfg_default.set_pull = s3c24xx_gpio_setpull_1up;
        s3c24xx_gpiocfg_default.get_pull = s3c24xx_gpio_getpull_1up;
 }
-
-void s3c2440_restart(char mode, const char *cmd)
-{
-       if (mode == 's') {
-               soft_restart(0);
-       }
-
-       arch_wdt_reset();
-
-       /* we'll take a jump through zero as a poor second */
-       soft_restart(0);
-}
index 36bc60f61d0a46b9dfa9d74fd4a91d5be0425485..d15852f642b7db8ca5fe5169a36a02fe29eb067a 100644 (file)
@@ -46,6 +46,7 @@
 #include <plat/pm.h>
 #include <plat/pll.h>
 #include <plat/nand-core.h>
+#include <plat/watchdog-reset.h>
 
 static struct map_desc s3c244x_iodesc[] __initdata = {
        IODESC_ENT(CLKPWR),
@@ -196,3 +197,14 @@ struct syscore_ops s3c244x_pm_syscore_ops = {
        .suspend        = s3c244x_suspend,
        .resume         = s3c244x_resume,
 };
+
+void s3c244x_restart(char mode, const char *cmd)
+{
+       if (mode == 's')
+               soft_restart(0);
+
+       arch_wdt_reset();
+
+       /* we'll take a jump through zero as a poor second */
+       soft_restart(0);
+}
index 52af00446a6335ff9fd5bb1fccbd9a3d8805caae..c59e8b892d6b9af1781f62666be3992885c6cfcf 100644 (file)
@@ -5,7 +5,7 @@ config UX500_SOC_COMMON
        default y
        select ARM_GIC
        select HAS_MTU
-       select ARM_ERRATA_753970
+       select PL310_ERRATA_753970
        select ARM_ERRATA_754322
        select ARM_ERRATA_764369
 
index 9b3d0fbaee729564f34a11749795d59577961bec..88c3ba151e8716c93abbabebc8265f81db806ea8 100644 (file)
@@ -7,7 +7,7 @@ config ARCH_VEXPRESS_CA9X4
        select ARM_GIC
        select ARM_ERRATA_720789
        select ARM_ERRATA_751472
-       select ARM_ERRATA_753970
+       select PL310_ERRATA_753970
        select HAVE_SMP
        select MIGHT_HAVE_CACHE_L2X0
 
index 0404ccbb8aa3ee39f0a8084c55879fb464115ca2..f1c8486f750169b0ffe8974b35e1b5555e53ad32 100644 (file)
@@ -230,9 +230,7 @@ __v7_setup:
        mcreq   p15, 0, r10, c15, c0, 1         @ write diagnostic register
 #endif
 #ifdef CONFIG_ARM_ERRATA_743622
-       teq     r6, #0x20                       @ present in r2p0
-       teqne   r6, #0x21                       @ present in r2p1
-       teqne   r6, #0x22                       @ present in r2p2
+       teq     r5, #0x00200000                 @ only present in r2p*
        mrceq   p15, 0, r10, c15, c0, 1         @ read diagnostic register
        orreq   r10, r10, #1 << 6               @ set bit #6
        mcreq   p15, 0, r10, c15, c0, 1         @ write diagnostic register
index 06383b51e6553b0aab931cab4f700972e9e52514..4de7d1e79e73d68615ccb8cc4d6c0c91b10f685e 100644 (file)
@@ -69,6 +69,7 @@ void __init omap_reserve(void)
        omap_vram_reserve_sdram_memblock();
        omap_dsp_reserve_sdram_memblock();
        omap_secure_ram_reserve_memblock();
+       omap_barrier_reserve_memblock();
 }
 
 void __init omap_init_consistent_dma_size(void)
index 2efd6454bce0db2086af97eb8dac43c54f6d8ab1..37bbbbb981b222ac001f958a59b5c69d3683c6b5 100644 (file)
 #define OMAP_GPMC_NR_IRQS      8
 #define OMAP_GPMC_IRQ_END      (OMAP_GPMC_IRQ_BASE + OMAP_GPMC_NR_IRQS)
 
+/* PRCM IRQ handler */
+#ifdef CONFIG_ARCH_OMAP2PLUS
+#define OMAP_PRCM_IRQ_BASE     (OMAP_GPMC_IRQ_END)
+#define OMAP_PRCM_NR_IRQS      64
+#define OMAP_PRCM_IRQ_END      (OMAP_PRCM_IRQ_BASE + OMAP_PRCM_NR_IRQS)
+#else
+#define OMAP_PRCM_IRQ_END      OMAP_GPMC_IRQ_END
+#endif
 
-#define NR_IRQS                        OMAP_GPMC_IRQ_END
+#define NR_IRQS                        OMAP_PRCM_IRQ_END
 
 #define OMAP_IRQ_BIT(irq)      (1 << ((irq) % 32))
 
index 3047ff923a63cc62747d38aa51686f2a2e2cdc64..8c7994ce9869a98fc7b673d6ebfcc0b4d63187c0 100644 (file)
@@ -10,4 +10,10 @@ static inline void omap_secure_ram_reserve_memblock(void)
 { }
 #endif
 
+#ifdef CONFIG_OMAP4_ERRATA_I688
+extern int omap_barrier_reserve_memblock(void);
+#else
+static inline void omap_barrier_reserve_memblock(void)
+{ }
+#endif
 #endif /* __OMAP_SECURE_H__ */
index 9fe35348e03b433d5294cfcd02c1742c268f3391..2bab4c99a2342218fff937cbe5bc701149f76d0c 100644 (file)
@@ -1249,7 +1249,7 @@ static void s3c2410_dma_resume(void)
        struct s3c2410_dma_chan *cp = s3c2410_chans + dma_channels - 1;
        int channel;
 
-       for (channel = dma_channels - 1; channel >= 0; cp++, channel--)
+       for (channel = dma_channels - 1; channel >= 0; cp--, channel--)
                s3c2410_dma_resume_chan(cp);
 }
 
index f10768e988d480d8e49758d900ba890a3649099a..d21d744e4d99d9d9623bb9d26cfb628e87c82a63 100644 (file)
@@ -1409,7 +1409,7 @@ void __init s5p_ehci_set_platdata(struct s5p_ehci_platdata *pd)
 
 #ifdef CONFIG_S3C_DEV_USB_HSOTG
 static struct resource s3c_usb_hsotg_resources[] = {
-       [0] = DEFINE_RES_MEM(S3C_PA_USB_HSOTG, SZ_16K),
+       [0] = DEFINE_RES_MEM(S3C_PA_USB_HSOTG, SZ_128K),
        [1] = DEFINE_RES_IRQ(IRQ_OTG),
 };
 
index 0c77e42986758554bc25931cc6ed88287353a9b9..abb5bdecd509acbe13f0b70c78b65a2607becd1d 100644 (file)
@@ -145,11 +145,13 @@ static void clockevent_set_mode(enum clock_event_mode mode,
 static int clockevent_next_event(unsigned long cycles,
                                 struct clock_event_device *clk_event_dev)
 {
-       u16 val;
+       u16 val = readw(gpt_base + CR(CLKEVT));
+
+       if (val & CTRL_ENABLE)
+               writew(val & ~CTRL_ENABLE, gpt_base + CR(CLKEVT));
 
        writew(cycles, gpt_base + LOAD(CLKEVT));
 
-       val = readw(gpt_base + CR(CLKEVT));
        val |= CTRL_ENABLE | CTRL_INT_ENABLE;
        writew(val, gpt_base + CR(CLKEVT));
 
index 8154c4ee8c9c24c3680b291dc034bcc2c4f35518..77ecbded1f370d07b5d736c22dde0b2a52a29222 100644 (file)
@@ -122,8 +122,8 @@ extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
 extern unsigned long get_wchan(struct task_struct *p);
 
-#define KSTK_EIP(tsk)  (task_pt_regs(task)->pc)
-#define        KSTK_ESP(tsk)   (task_pt_regs(task)->sp)
+#define KSTK_EIP(task) (task_pt_regs(task)->pc)
+#define KSTK_ESP(task) (task_pt_regs(task)->sp)
 
 #define cpu_relax()            do { } while (0)
 
index 7da4d0081487b73f341cd4a51f6ef5efe33141ae..a7193ae13a5d2d6ab8df643a76c6b33cd9621421 100644 (file)
@@ -146,7 +146,7 @@ static int __init alchemy_time_init(unsigned int m2int)
        cd->shift = 32;
        cd->mult = div_sc(32768, NSEC_PER_SEC, cd->shift);
        cd->max_delta_ns = clockevent_delta2ns(0xffffffff, cd);
-       cd->min_delta_ns = clockevent_delta2ns(8, cd);  /* ~0.25ms */
+       cd->min_delta_ns = clockevent_delta2ns(9, cd);  /* ~0.28ms */
        clockevents_register_device(cd);
        setup_irq(m2int, &au1x_rtcmatch2_irqaction);
 
index 24f546985b69b5b572e60dfc60be97a92a726483..e21507052066fbfe5aaec7185286376f2eaf4d02 100644 (file)
@@ -96,7 +96,7 @@ void __init ath79_register_wmac(u8 *cal_data)
 {
        if (soc_is_ar913x())
                ar913x_wmac_setup();
-       if (soc_is_ar933x())
+       else if (soc_is_ar933x())
                ar933x_wmac_setup();
        else
                BUG();
index 4add17349ff9549a264da1814249ae533144e042..4389de182eb476a5cf3ff50565e7f13b86585611 100644 (file)
@@ -3,5 +3,5 @@
 # under Linux.
 #
 
-obj-y                          += gpio.o irq.o nvram.o prom.o serial.o setup.o time.o
+obj-y                          += gpio.o irq.o nvram.o prom.o serial.o setup.o time.o sprom.o
 obj-$(CONFIG_BCM47XX_SSB)      += wgt634u.o
index a84e3bb7387f685bc7025e689e01e57cfa97bd21..d43ceff5be4782b7024ae0f04ad73f278d4d7486 100644 (file)
@@ -107,8 +107,7 @@ int nvram_getenv(char *name, char *val, size_t val_len)
                value = eq + 1;
                if ((eq - var) == strlen(name) &&
                        strncmp(var, name, (eq - var)) == 0) {
-                       snprintf(val, val_len, "%s", value);
-                       return 0;
+                       return snprintf(val, val_len, "%s", value);
                }
        }
        return NVRAM_ERR_ENVNOTFOUND;
index aab6b0c40a7569b54767c5e473e75da5ba5b8563..19780aa917081e0ce547c63e1ffc8fff9d8723be 100644 (file)
@@ -3,7 +3,7 @@
  *  Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
  *  Copyright (C) 2006 Michael Buesch <m@bues.ch>
  *  Copyright (C) 2010 Waldemar Brodkorb <wbx@openadk.org>
- *  Copyright (C) 2010-2011 Hauke Mehrtens <hauke@hauke-m.de>
+ *  Copyright (C) 2010-2012 Hauke Mehrtens <hauke@hauke-m.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
@@ -85,156 +85,7 @@ static void bcm47xx_machine_halt(void)
 }
 
 #ifdef CONFIG_BCM47XX_SSB
-#define READ_FROM_NVRAM(_outvar, name, buf) \
-       if (nvram_getprefix(prefix, name, buf, sizeof(buf)) >= 0)\
-               sprom->_outvar = simple_strtoul(buf, NULL, 0);
-
-#define READ_FROM_NVRAM2(_outvar, name1, name2, buf) \
-       if (nvram_getprefix(prefix, name1, buf, sizeof(buf)) >= 0 || \
-           nvram_getprefix(prefix, name2, buf, sizeof(buf)) >= 0)\
-               sprom->_outvar = simple_strtoul(buf, NULL, 0);
-
-static inline int nvram_getprefix(const char *prefix, char *name,
-                                 char *buf, int len)
-{
-       if (prefix) {
-               char key[100];
-
-               snprintf(key, sizeof(key), "%s%s", prefix, name);
-               return nvram_getenv(key, buf, len);
-       }
-
-       return nvram_getenv(name, buf, len);
-}
-
-static u32 nvram_getu32(const char *name, char *buf, int len)
-{
-       int rv;
-       char key[100];
-       u16 var0, var1;
-
-       snprintf(key, sizeof(key), "%s0", name);
-       rv = nvram_getenv(key, buf, len);
-       /* return 0 here so this looks like unset */
-       if (rv < 0)
-               return 0;
-       var0 = simple_strtoul(buf, NULL, 0);
-
-       snprintf(key, sizeof(key), "%s1", name);
-       rv = nvram_getenv(key, buf, len);
-       if (rv < 0)
-               return 0;
-       var1 = simple_strtoul(buf, NULL, 0);
-       return var1 << 16 | var0;
-}
-
-static void bcm47xx_fill_sprom(struct ssb_sprom *sprom, const char *prefix)
-{
-       char buf[100];
-       u32 boardflags;
-
-       memset(sprom, 0, sizeof(struct ssb_sprom));
-
-       sprom->revision = 1; /* Fallback: Old hardware does not define this. */
-       READ_FROM_NVRAM(revision, "sromrev", buf);
-       if (nvram_getprefix(prefix, "il0macaddr", buf, sizeof(buf)) >= 0 ||
-           nvram_getprefix(prefix, "macaddr", buf, sizeof(buf)) >= 0)
-               nvram_parse_macaddr(buf, sprom->il0mac);
-       if (nvram_getprefix(prefix, "et0macaddr", buf, sizeof(buf)) >= 0)
-               nvram_parse_macaddr(buf, sprom->et0mac);
-       if (nvram_getprefix(prefix, "et1macaddr", buf, sizeof(buf)) >= 0)
-               nvram_parse_macaddr(buf, sprom->et1mac);
-       READ_FROM_NVRAM(et0phyaddr, "et0phyaddr", buf);
-       READ_FROM_NVRAM(et1phyaddr, "et1phyaddr", buf);
-       READ_FROM_NVRAM(et0mdcport, "et0mdcport", buf);
-       READ_FROM_NVRAM(et1mdcport, "et1mdcport", buf);
-       READ_FROM_NVRAM(board_rev, "boardrev", buf);
-       READ_FROM_NVRAM(country_code, "ccode", buf);
-       READ_FROM_NVRAM(ant_available_a, "aa5g", buf);
-       READ_FROM_NVRAM(ant_available_bg, "aa2g", buf);
-       READ_FROM_NVRAM(pa0b0, "pa0b0", buf);
-       READ_FROM_NVRAM(pa0b1, "pa0b1", buf);
-       READ_FROM_NVRAM(pa0b2, "pa0b2", buf);
-       READ_FROM_NVRAM(pa1b0, "pa1b0", buf);
-       READ_FROM_NVRAM(pa1b1, "pa1b1", buf);
-       READ_FROM_NVRAM(pa1b2, "pa1b2", buf);
-       READ_FROM_NVRAM(pa1lob0, "pa1lob0", buf);
-       READ_FROM_NVRAM(pa1lob2, "pa1lob1", buf);
-       READ_FROM_NVRAM(pa1lob1, "pa1lob2", buf);
-       READ_FROM_NVRAM(pa1hib0, "pa1hib0", buf);
-       READ_FROM_NVRAM(pa1hib2, "pa1hib1", buf);
-       READ_FROM_NVRAM(pa1hib1, "pa1hib2", buf);
-       READ_FROM_NVRAM2(gpio0, "ledbh0", "wl0gpio0", buf);
-       READ_FROM_NVRAM2(gpio1, "ledbh1", "wl0gpio1", buf);
-       READ_FROM_NVRAM2(gpio2, "ledbh2", "wl0gpio2", buf);
-       READ_FROM_NVRAM2(gpio3, "ledbh3", "wl0gpio3", buf);
-       READ_FROM_NVRAM2(maxpwr_bg, "maxp2ga0", "pa0maxpwr", buf);
-       READ_FROM_NVRAM2(maxpwr_al, "maxp5gla0", "pa1lomaxpwr", buf);
-       READ_FROM_NVRAM2(maxpwr_a, "maxp5ga0", "pa1maxpwr", buf);
-       READ_FROM_NVRAM2(maxpwr_ah, "maxp5gha0", "pa1himaxpwr", buf);
-       READ_FROM_NVRAM2(itssi_bg, "itt5ga0", "pa0itssit", buf);
-       READ_FROM_NVRAM2(itssi_a, "itt2ga0", "pa1itssit", buf);
-       READ_FROM_NVRAM(tri2g, "tri2g", buf);
-       READ_FROM_NVRAM(tri5gl, "tri5gl", buf);
-       READ_FROM_NVRAM(tri5g, "tri5g", buf);
-       READ_FROM_NVRAM(tri5gh, "tri5gh", buf);
-       READ_FROM_NVRAM(txpid2g[0], "txpid2ga0", buf);
-       READ_FROM_NVRAM(txpid2g[1], "txpid2ga1", buf);
-       READ_FROM_NVRAM(txpid2g[2], "txpid2ga2", buf);
-       READ_FROM_NVRAM(txpid2g[3], "txpid2ga3", buf);
-       READ_FROM_NVRAM(txpid5g[0], "txpid5ga0", buf);
-       READ_FROM_NVRAM(txpid5g[1], "txpid5ga1", buf);
-       READ_FROM_NVRAM(txpid5g[2], "txpid5ga2", buf);
-       READ_FROM_NVRAM(txpid5g[3], "txpid5ga3", buf);
-       READ_FROM_NVRAM(txpid5gl[0], "txpid5gla0", buf);
-       READ_FROM_NVRAM(txpid5gl[1], "txpid5gla1", buf);
-       READ_FROM_NVRAM(txpid5gl[2], "txpid5gla2", buf);
-       READ_FROM_NVRAM(txpid5gl[3], "txpid5gla3", buf);
-       READ_FROM_NVRAM(txpid5gh[0], "txpid5gha0", buf);
-       READ_FROM_NVRAM(txpid5gh[1], "txpid5gha1", buf);
-       READ_FROM_NVRAM(txpid5gh[2], "txpid5gha2", buf);
-       READ_FROM_NVRAM(txpid5gh[3], "txpid5gha3", buf);
-       READ_FROM_NVRAM(rxpo2g, "rxpo2g", buf);
-       READ_FROM_NVRAM(rxpo5g, "rxpo5g", buf);
-       READ_FROM_NVRAM(rssisav2g, "rssisav2g", buf);
-       READ_FROM_NVRAM(rssismc2g, "rssismc2g", buf);
-       READ_FROM_NVRAM(rssismf2g, "rssismf2g", buf);
-       READ_FROM_NVRAM(bxa2g, "bxa2g", buf);
-       READ_FROM_NVRAM(rssisav5g, "rssisav5g", buf);
-       READ_FROM_NVRAM(rssismc5g, "rssismc5g", buf);
-       READ_FROM_NVRAM(rssismf5g, "rssismf5g", buf);
-       READ_FROM_NVRAM(bxa5g, "bxa5g", buf);
-       READ_FROM_NVRAM(cck2gpo, "cck2gpo", buf);
-
-       sprom->ofdm2gpo = nvram_getu32("ofdm2gpo", buf, sizeof(buf));
-       sprom->ofdm5glpo = nvram_getu32("ofdm5glpo", buf, sizeof(buf));
-       sprom->ofdm5gpo = nvram_getu32("ofdm5gpo", buf, sizeof(buf));
-       sprom->ofdm5ghpo = nvram_getu32("ofdm5ghpo", buf, sizeof(buf));
-
-       READ_FROM_NVRAM(antenna_gain.ghz24.a0, "ag0", buf);
-       READ_FROM_NVRAM(antenna_gain.ghz24.a1, "ag1", buf);
-       READ_FROM_NVRAM(antenna_gain.ghz24.a2, "ag2", buf);
-       READ_FROM_NVRAM(antenna_gain.ghz24.a3, "ag3", buf);
-       memcpy(&sprom->antenna_gain.ghz5, &sprom->antenna_gain.ghz24,
-              sizeof(sprom->antenna_gain.ghz5));
-
-       if (nvram_getprefix(prefix, "boardflags", buf, sizeof(buf)) >= 0) {
-               boardflags = simple_strtoul(buf, NULL, 0);
-               if (boardflags) {
-                       sprom->boardflags_lo = (boardflags & 0x0000FFFFU);
-                       sprom->boardflags_hi = (boardflags & 0xFFFF0000U) >> 16;
-               }
-       }
-       if (nvram_getprefix(prefix, "boardflags2", buf, sizeof(buf)) >= 0) {
-               boardflags = simple_strtoul(buf, NULL, 0);
-               if (boardflags) {
-                       sprom->boardflags2_lo = (boardflags & 0x0000FFFFU);
-                       sprom->boardflags2_hi = (boardflags & 0xFFFF0000U) >> 16;
-               }
-       }
-}
-
-int bcm47xx_get_sprom(struct ssb_bus *bus, struct ssb_sprom *out)
+static int bcm47xx_get_sprom_ssb(struct ssb_bus *bus, struct ssb_sprom *out)
 {
        char prefix[10];
 
@@ -251,7 +102,7 @@ int bcm47xx_get_sprom(struct ssb_bus *bus, struct ssb_sprom *out)
 }
 
 static int bcm47xx_get_invariants(struct ssb_bus *bus,
-                                  struct ssb_init_invariants *iv)
+                                 struct ssb_init_invariants *iv)
 {
        char buf[20];
 
@@ -281,7 +132,7 @@ static void __init bcm47xx_register_ssb(void)
        char buf[100];
        struct ssb_mipscore *mcore;
 
-       err = ssb_arch_register_fallback_sprom(&bcm47xx_get_sprom);
+       err = ssb_arch_register_fallback_sprom(&bcm47xx_get_sprom_ssb);
        if (err)
                printk(KERN_WARNING "bcm47xx: someone else already registered"
                        " a ssb SPROM callback handler (err %d)\n", err);
@@ -308,10 +159,41 @@ static void __init bcm47xx_register_ssb(void)
 #endif
 
 #ifdef CONFIG_BCM47XX_BCMA
+static int bcm47xx_get_sprom_bcma(struct bcma_bus *bus, struct ssb_sprom *out)
+{
+       char prefix[10];
+       struct bcma_device *core;
+
+       switch (bus->hosttype) {
+       case BCMA_HOSTTYPE_PCI:
+               snprintf(prefix, sizeof(prefix), "pci/%u/%u/",
+                        bus->host_pci->bus->number + 1,
+                        PCI_SLOT(bus->host_pci->devfn));
+               bcm47xx_fill_sprom(out, prefix);
+               return 0;
+       case BCMA_HOSTTYPE_SOC:
+               bcm47xx_fill_sprom_ethernet(out, NULL);
+               core = bcma_find_core(bus, BCMA_CORE_80211);
+               if (core) {
+                       snprintf(prefix, sizeof(prefix), "sb/%u/",
+                                core->core_index);
+                       bcm47xx_fill_sprom(out, prefix);
+               }
+               return 0;
+       default:
+               pr_warn("bcm47xx: unable to fill SPROM for given bustype.\n");
+               return -EINVAL;
+       }
+}
+
 static void __init bcm47xx_register_bcma(void)
 {
        int err;
 
+       err = bcma_arch_register_fallback_sprom(&bcm47xx_get_sprom_bcma);
+       if (err)
+               pr_warn("bcm47xx: someone else already registered a bcma SPROM callback handler (err %d)\n", err);
+
        err = bcma_host_soc_register(&bcm47xx_bus.bcma);
        if (err)
                panic("Failed to initialize BCMA bus (err %d)", err);
diff --git a/arch/mips/bcm47xx/sprom.c b/arch/mips/bcm47xx/sprom.c
new file mode 100644 (file)
index 0000000..5c8dcd2
--- /dev/null
@@ -0,0 +1,620 @@
+/*
+ *  Copyright (C) 2004 Florian Schirmer <jolt@tuxbox.org>
+ *  Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
+ *  Copyright (C) 2006 Michael Buesch <m@bues.ch>
+ *  Copyright (C) 2010 Waldemar Brodkorb <wbx@openadk.org>
+ *  Copyright (C) 2010-2012 Hauke Mehrtens <hauke@hauke-m.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.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <bcm47xx.h>
+#include <nvram.h>
+
+static void create_key(const char *prefix, const char *postfix,
+                      const char *name, char *buf, int len)
+{
+       if (prefix && postfix)
+               snprintf(buf, len, "%s%s%s", prefix, name, postfix);
+       else if (prefix)
+               snprintf(buf, len, "%s%s", prefix, name);
+       else if (postfix)
+               snprintf(buf, len, "%s%s", name, postfix);
+       else
+               snprintf(buf, len, "%s", name);
+}
+
+#define NVRAM_READ_VAL(type)                                           \
+static void nvram_read_ ## type (const char *prefix,                   \
+                                const char *postfix, const char *name, \
+                                type *val, type allset)                \
+{                                                                      \
+       char buf[100];                                                  \
+       char key[40];                                                   \
+       int err;                                                        \
+       type var;                                                       \
+                                                                       \
+       create_key(prefix, postfix, name, key, sizeof(key));            \
+                                                                       \
+       err = nvram_getenv(key, buf, sizeof(buf));                      \
+       if (err < 0)                                                    \
+               return;                                                 \
+       err = kstrto ## type (buf, 0, &var);                            \
+       if (err) {                                                      \
+               pr_warn("can not parse nvram name %s with value %s"     \
+                       " got %i", key, buf, err);                      \
+               return;                                                 \
+       }                                                               \
+       if (allset && var == allset)                                    \
+               return;                                                 \
+       *val = var;                                                     \
+}
+
+NVRAM_READ_VAL(u8)
+NVRAM_READ_VAL(s8)
+NVRAM_READ_VAL(u16)
+NVRAM_READ_VAL(u32)
+
+#undef NVRAM_READ_VAL
+
+static void nvram_read_u32_2(const char *prefix, const char *name,
+                            u16 *val_lo, u16 *val_hi)
+{
+       char buf[100];
+       char key[40];
+       int err;
+       u32 val;
+
+       create_key(prefix, NULL, name, key, sizeof(key));
+
+       err = nvram_getenv(key, buf, sizeof(buf));
+       if (err < 0)
+               return;
+       err = kstrtou32(buf, 0, &val);
+       if (err) {
+               pr_warn("can not parse nvram name %s with value %s got %i",
+                       key, buf, err);
+               return;
+       }
+       *val_lo = (val & 0x0000FFFFU);
+       *val_hi = (val & 0xFFFF0000U) >> 16;
+}
+
+static void nvram_read_leddc(const char *prefix, const char *name,
+                            u8 *leddc_on_time, u8 *leddc_off_time)
+{
+       char buf[100];
+       char key[40];
+       int err;
+       u32 val;
+
+       create_key(prefix, NULL, name, key, sizeof(key));
+
+       err = nvram_getenv(key, buf, sizeof(buf));
+       if (err < 0)
+               return;
+       err = kstrtou32(buf, 0, &val);
+       if (err) {
+               pr_warn("can not parse nvram name %s with value %s got %i",
+                       key, buf, err);
+               return;
+       }
+
+       if (val == 0xffff || val == 0xffffffff)
+               return;
+
+       *leddc_on_time = val & 0xff;
+       *leddc_off_time = (val >> 16) & 0xff;
+}
+
+static void nvram_read_macaddr(const char *prefix, const char *name,
+                              u8 (*val)[6])
+{
+       char buf[100];
+       char key[40];
+       int err;
+
+       create_key(prefix, NULL, name, key, sizeof(key));
+
+       err = nvram_getenv(key, buf, sizeof(buf));
+       if (err < 0)
+               return;
+       nvram_parse_macaddr(buf, *val);
+}
+
+static void nvram_read_alpha2(const char *prefix, const char *name,
+                            char (*val)[2])
+{
+       char buf[10];
+       char key[40];
+       int err;
+
+       create_key(prefix, NULL, name, key, sizeof(key));
+
+       err = nvram_getenv(key, buf, sizeof(buf));
+       if (err < 0)
+               return;
+       if (buf[0] == '0')
+               return;
+       if (strlen(buf) > 2) {
+               pr_warn("alpha2 is too long %s", buf);
+               return;
+       }
+       memcpy(val, buf, sizeof(val));
+}
+
+static void bcm47xx_fill_sprom_r1234589(struct ssb_sprom *sprom,
+                                       const char *prefix)
+{
+       nvram_read_u16(prefix, NULL, "boardrev", &sprom->board_rev, 0);
+       nvram_read_u16(prefix, NULL, "boardnum", &sprom->board_num, 0);
+       nvram_read_u8(prefix, NULL, "ledbh0", &sprom->gpio0, 0xff);
+       nvram_read_u8(prefix, NULL, "ledbh1", &sprom->gpio1, 0xff);
+       nvram_read_u8(prefix, NULL, "ledbh2", &sprom->gpio2, 0xff);
+       nvram_read_u8(prefix, NULL, "ledbh3", &sprom->gpio3, 0xff);
+       nvram_read_u8(prefix, NULL, "aa2g", &sprom->ant_available_bg, 0);
+       nvram_read_u8(prefix, NULL, "aa5g", &sprom->ant_available_a, 0);
+       nvram_read_s8(prefix, NULL, "ag0", &sprom->antenna_gain.a0, 0);
+       nvram_read_s8(prefix, NULL, "ag1", &sprom->antenna_gain.a1, 0);
+       nvram_read_alpha2(prefix, "ccode", &sprom->alpha2);
+}
+
+static void bcm47xx_fill_sprom_r12389(struct ssb_sprom *sprom,
+                                     const char *prefix)
+{
+       nvram_read_u16(prefix, NULL, "pa0b0", &sprom->pa0b0, 0);
+       nvram_read_u16(prefix, NULL, "pa0b1", &sprom->pa0b1, 0);
+       nvram_read_u16(prefix, NULL, "pa0b2", &sprom->pa0b2, 0);
+       nvram_read_u8(prefix, NULL, "pa0itssit", &sprom->itssi_bg, 0);
+       nvram_read_u8(prefix, NULL, "pa0maxpwr", &sprom->maxpwr_bg, 0);
+       nvram_read_u16(prefix, NULL, "pa1b0", &sprom->pa1b0, 0);
+       nvram_read_u16(prefix, NULL, "pa1b1", &sprom->pa1b1, 0);
+       nvram_read_u16(prefix, NULL, "pa1b2", &sprom->pa1b2, 0);
+       nvram_read_u8(prefix, NULL, "pa1itssit", &sprom->itssi_a, 0);
+       nvram_read_u8(prefix, NULL, "pa1maxpwr", &sprom->maxpwr_a, 0);
+}
+
+static void bcm47xx_fill_sprom_r1(struct ssb_sprom *sprom, const char *prefix)
+{
+       nvram_read_u16(prefix, NULL, "boardflags", &sprom->boardflags_lo, 0);
+       nvram_read_u8(prefix, NULL, "cc", &sprom->country_code, 0);
+}
+
+static void bcm47xx_fill_sprom_r2389(struct ssb_sprom *sprom,
+                                    const char *prefix)
+{
+       nvram_read_u8(prefix, NULL, "opo", &sprom->opo, 0);
+       nvram_read_u16(prefix, NULL, "pa1lob0", &sprom->pa1lob0, 0);
+       nvram_read_u16(prefix, NULL, "pa1lob1", &sprom->pa1lob1, 0);
+       nvram_read_u16(prefix, NULL, "pa1lob2", &sprom->pa1lob2, 0);
+       nvram_read_u16(prefix, NULL, "pa1hib0", &sprom->pa1hib0, 0);
+       nvram_read_u16(prefix, NULL, "pa1hib1", &sprom->pa1hib1, 0);
+       nvram_read_u16(prefix, NULL, "pa1hib2", &sprom->pa1hib2, 0);
+       nvram_read_u8(prefix, NULL, "pa1lomaxpwr", &sprom->maxpwr_al, 0);
+       nvram_read_u8(prefix, NULL, "pa1himaxpwr", &sprom->maxpwr_ah, 0);
+}
+
+static void bcm47xx_fill_sprom_r2(struct ssb_sprom *sprom, const char *prefix)
+{
+       nvram_read_u32_2(prefix, "boardflags", &sprom->boardflags_lo,
+                        &sprom->boardflags_hi);
+       nvram_read_u16(prefix, NULL, "boardtype", &sprom->board_type, 0);
+}
+
+static void bcm47xx_fill_sprom_r389(struct ssb_sprom *sprom, const char *prefix)
+{
+       nvram_read_u8(prefix, NULL, "bxa2g", &sprom->bxa2g, 0);
+       nvram_read_u8(prefix, NULL, "rssisav2g", &sprom->rssisav2g, 0);
+       nvram_read_u8(prefix, NULL, "rssismc2g", &sprom->rssismc2g, 0);
+       nvram_read_u8(prefix, NULL, "rssismf2g", &sprom->rssismf2g, 0);
+       nvram_read_u8(prefix, NULL, "bxa5g", &sprom->bxa5g, 0);
+       nvram_read_u8(prefix, NULL, "rssisav5g", &sprom->rssisav5g, 0);
+       nvram_read_u8(prefix, NULL, "rssismc5g", &sprom->rssismc5g, 0);
+       nvram_read_u8(prefix, NULL, "rssismf5g", &sprom->rssismf5g, 0);
+       nvram_read_u8(prefix, NULL, "tri2g", &sprom->tri2g, 0);
+       nvram_read_u8(prefix, NULL, "tri5g", &sprom->tri5g, 0);
+       nvram_read_u8(prefix, NULL, "tri5gl", &sprom->tri5gl, 0);
+       nvram_read_u8(prefix, NULL, "tri5gh", &sprom->tri5gh, 0);
+       nvram_read_s8(prefix, NULL, "rxpo2g", &sprom->rxpo2g, 0);
+       nvram_read_s8(prefix, NULL, "rxpo5g", &sprom->rxpo5g, 0);
+}
+
+static void bcm47xx_fill_sprom_r3(struct ssb_sprom *sprom, const char *prefix)
+{
+       nvram_read_u32_2(prefix, "boardflags", &sprom->boardflags_lo,
+                        &sprom->boardflags_hi);
+       nvram_read_u16(prefix, NULL, "boardtype", &sprom->board_type, 0);
+       nvram_read_u8(prefix, NULL, "regrev", &sprom->regrev, 0);
+       nvram_read_leddc(prefix, "leddc", &sprom->leddc_on_time,
+                        &sprom->leddc_off_time);
+}
+
+static void bcm47xx_fill_sprom_r4589(struct ssb_sprom *sprom,
+                                    const char *prefix)
+{
+       nvram_read_u32_2(prefix, "boardflags", &sprom->boardflags_lo,
+                        &sprom->boardflags_hi);
+       nvram_read_u32_2(prefix, "boardflags2", &sprom->boardflags2_lo,
+                        &sprom->boardflags2_hi);
+       nvram_read_u16(prefix, NULL, "boardtype", &sprom->board_type, 0);
+       nvram_read_u8(prefix, NULL, "regrev", &sprom->regrev, 0);
+       nvram_read_s8(prefix, NULL, "ag2", &sprom->antenna_gain.a2, 0);
+       nvram_read_s8(prefix, NULL, "ag3", &sprom->antenna_gain.a3, 0);
+       nvram_read_u8(prefix, NULL, "txchain", &sprom->txchain, 0xf);
+       nvram_read_u8(prefix, NULL, "rxchain", &sprom->rxchain, 0xf);
+       nvram_read_u8(prefix, NULL, "antswitch", &sprom->antswitch, 0xff);
+       nvram_read_leddc(prefix, "leddc", &sprom->leddc_on_time,
+                        &sprom->leddc_off_time);
+}
+
+static void bcm47xx_fill_sprom_r458(struct ssb_sprom *sprom, const char *prefix)
+{
+       nvram_read_u16(prefix, NULL, "cck2gpo", &sprom->cck2gpo, 0);
+       nvram_read_u32(prefix, NULL, "ofdm2gpo", &sprom->ofdm2gpo, 0);
+       nvram_read_u32(prefix, NULL, "ofdm5gpo", &sprom->ofdm5gpo, 0);
+       nvram_read_u32(prefix, NULL, "ofdm5glpo", &sprom->ofdm5glpo, 0);
+       nvram_read_u32(prefix, NULL, "ofdm5ghpo", &sprom->ofdm5ghpo, 0);
+       nvram_read_u16(prefix, NULL, "cddpo", &sprom->cddpo, 0);
+       nvram_read_u16(prefix, NULL, "stbcpo", &sprom->stbcpo, 0);
+       nvram_read_u16(prefix, NULL, "bw40po", &sprom->bw40po, 0);
+       nvram_read_u16(prefix, NULL, "bwduppo", &sprom->bwduppo, 0);
+       nvram_read_u16(prefix, NULL, "mcs2gpo0", &sprom->mcs2gpo[0], 0);
+       nvram_read_u16(prefix, NULL, "mcs2gpo1", &sprom->mcs2gpo[1], 0);
+       nvram_read_u16(prefix, NULL, "mcs2gpo2", &sprom->mcs2gpo[2], 0);
+       nvram_read_u16(prefix, NULL, "mcs2gpo3", &sprom->mcs2gpo[3], 0);
+       nvram_read_u16(prefix, NULL, "mcs2gpo4", &sprom->mcs2gpo[4], 0);
+       nvram_read_u16(prefix, NULL, "mcs2gpo5", &sprom->mcs2gpo[5], 0);
+       nvram_read_u16(prefix, NULL, "mcs2gpo6", &sprom->mcs2gpo[6], 0);
+       nvram_read_u16(prefix, NULL, "mcs2gpo7", &sprom->mcs2gpo[7], 0);
+       nvram_read_u16(prefix, NULL, "mcs5gpo0", &sprom->mcs5gpo[0], 0);
+       nvram_read_u16(prefix, NULL, "mcs5gpo1", &sprom->mcs5gpo[1], 0);
+       nvram_read_u16(prefix, NULL, "mcs5gpo2", &sprom->mcs5gpo[2], 0);
+       nvram_read_u16(prefix, NULL, "mcs5gpo3", &sprom->mcs5gpo[3], 0);
+       nvram_read_u16(prefix, NULL, "mcs5gpo4", &sprom->mcs5gpo[4], 0);
+       nvram_read_u16(prefix, NULL, "mcs5gpo5", &sprom->mcs5gpo[5], 0);
+       nvram_read_u16(prefix, NULL, "mcs5gpo6", &sprom->mcs5gpo[6], 0);
+       nvram_read_u16(prefix, NULL, "mcs5gpo7", &sprom->mcs5gpo[7], 0);
+       nvram_read_u16(prefix, NULL, "mcs5glpo0", &sprom->mcs5glpo[0], 0);
+       nvram_read_u16(prefix, NULL, "mcs5glpo1", &sprom->mcs5glpo[1], 0);
+       nvram_read_u16(prefix, NULL, "mcs5glpo2", &sprom->mcs5glpo[2], 0);
+       nvram_read_u16(prefix, NULL, "mcs5glpo3", &sprom->mcs5glpo[3], 0);
+       nvram_read_u16(prefix, NULL, "mcs5glpo4", &sprom->mcs5glpo[4], 0);
+       nvram_read_u16(prefix, NULL, "mcs5glpo5", &sprom->mcs5glpo[5], 0);
+       nvram_read_u16(prefix, NULL, "mcs5glpo6", &sprom->mcs5glpo[6], 0);
+       nvram_read_u16(prefix, NULL, "mcs5glpo7", &sprom->mcs5glpo[7], 0);
+       nvram_read_u16(prefix, NULL, "mcs5ghpo0", &sprom->mcs5ghpo[0], 0);
+       nvram_read_u16(prefix, NULL, "mcs5ghpo1", &sprom->mcs5ghpo[1], 0);
+       nvram_read_u16(prefix, NULL, "mcs5ghpo2", &sprom->mcs5ghpo[2], 0);
+       nvram_read_u16(prefix, NULL, "mcs5ghpo3", &sprom->mcs5ghpo[3], 0);
+       nvram_read_u16(prefix, NULL, "mcs5ghpo4", &sprom->mcs5ghpo[4], 0);
+       nvram_read_u16(prefix, NULL, "mcs5ghpo5", &sprom->mcs5ghpo[5], 0);
+       nvram_read_u16(prefix, NULL, "mcs5ghpo6", &sprom->mcs5ghpo[6], 0);
+       nvram_read_u16(prefix, NULL, "mcs5ghpo7", &sprom->mcs5ghpo[7], 0);
+}
+
+static void bcm47xx_fill_sprom_r45(struct ssb_sprom *sprom, const char *prefix)
+{
+       nvram_read_u8(prefix, NULL, "txpid2ga0", &sprom->txpid2g[0], 0);
+       nvram_read_u8(prefix, NULL, "txpid2ga1", &sprom->txpid2g[1], 0);
+       nvram_read_u8(prefix, NULL, "txpid2ga2", &sprom->txpid2g[2], 0);
+       nvram_read_u8(prefix, NULL, "txpid2ga3", &sprom->txpid2g[3], 0);
+       nvram_read_u8(prefix, NULL, "txpid5ga0", &sprom->txpid5g[0], 0);
+       nvram_read_u8(prefix, NULL, "txpid5ga1", &sprom->txpid5g[1], 0);
+       nvram_read_u8(prefix, NULL, "txpid5ga2", &sprom->txpid5g[2], 0);
+       nvram_read_u8(prefix, NULL, "txpid5ga3", &sprom->txpid5g[3], 0);
+       nvram_read_u8(prefix, NULL, "txpid5gla0", &sprom->txpid5gl[0], 0);
+       nvram_read_u8(prefix, NULL, "txpid5gla1", &sprom->txpid5gl[1], 0);
+       nvram_read_u8(prefix, NULL, "txpid5gla2", &sprom->txpid5gl[2], 0);
+       nvram_read_u8(prefix, NULL, "txpid5gla3", &sprom->txpid5gl[3], 0);
+       nvram_read_u8(prefix, NULL, "txpid5gha0", &sprom->txpid5gh[0], 0);
+       nvram_read_u8(prefix, NULL, "txpid5gha1", &sprom->txpid5gh[1], 0);
+       nvram_read_u8(prefix, NULL, "txpid5gha2", &sprom->txpid5gh[2], 0);
+       nvram_read_u8(prefix, NULL, "txpid5gha3", &sprom->txpid5gh[3], 0);
+}
+
+static void bcm47xx_fill_sprom_r89(struct ssb_sprom *sprom, const char *prefix)
+{
+       nvram_read_u8(prefix, NULL, "tssipos2g", &sprom->fem.ghz2.tssipos, 0);
+       nvram_read_u8(prefix, NULL, "extpagain2g",
+                     &sprom->fem.ghz2.extpa_gain, 0);
+       nvram_read_u8(prefix, NULL, "pdetrange2g",
+                     &sprom->fem.ghz2.pdet_range, 0);
+       nvram_read_u8(prefix, NULL, "triso2g", &sprom->fem.ghz2.tr_iso, 0);
+       nvram_read_u8(prefix, NULL, "antswctl2g", &sprom->fem.ghz2.antswlut, 0);
+       nvram_read_u8(prefix, NULL, "tssipos5g", &sprom->fem.ghz5.tssipos, 0);
+       nvram_read_u8(prefix, NULL, "extpagain5g",
+                     &sprom->fem.ghz5.extpa_gain, 0);
+       nvram_read_u8(prefix, NULL, "pdetrange5g",
+                     &sprom->fem.ghz5.pdet_range, 0);
+       nvram_read_u8(prefix, NULL, "triso5g", &sprom->fem.ghz5.tr_iso, 0);
+       nvram_read_u8(prefix, NULL, "antswctl5g", &sprom->fem.ghz5.antswlut, 0);
+       nvram_read_u8(prefix, NULL, "tempthresh", &sprom->tempthresh, 0);
+       nvram_read_u8(prefix, NULL, "tempoffset", &sprom->tempoffset, 0);
+       nvram_read_u16(prefix, NULL, "rawtempsense", &sprom->rawtempsense, 0);
+       nvram_read_u8(prefix, NULL, "measpower", &sprom->measpower, 0);
+       nvram_read_u8(prefix, NULL, "tempsense_slope",
+                     &sprom->tempsense_slope, 0);
+       nvram_read_u8(prefix, NULL, "tempcorrx", &sprom->tempcorrx, 0);
+       nvram_read_u8(prefix, NULL, "tempsense_option",
+                     &sprom->tempsense_option, 0);
+       nvram_read_u8(prefix, NULL, "freqoffset_corr",
+                     &sprom->freqoffset_corr, 0);
+       nvram_read_u8(prefix, NULL, "iqcal_swp_dis", &sprom->iqcal_swp_dis, 0);
+       nvram_read_u8(prefix, NULL, "hw_iqcal_en", &sprom->hw_iqcal_en, 0);
+       nvram_read_u8(prefix, NULL, "elna2g", &sprom->elna2g, 0);
+       nvram_read_u8(prefix, NULL, "elna5g", &sprom->elna5g, 0);
+       nvram_read_u8(prefix, NULL, "phycal_tempdelta",
+                     &sprom->phycal_tempdelta, 0);
+       nvram_read_u8(prefix, NULL, "temps_period", &sprom->temps_period, 0);
+       nvram_read_u8(prefix, NULL, "temps_hysteresis",
+                     &sprom->temps_hysteresis, 0);
+       nvram_read_u8(prefix, NULL, "measpower1", &sprom->measpower1, 0);
+       nvram_read_u8(prefix, NULL, "measpower2", &sprom->measpower2, 0);
+       nvram_read_u8(prefix, NULL, "rxgainerr2ga0",
+                     &sprom->rxgainerr2ga[0], 0);
+       nvram_read_u8(prefix, NULL, "rxgainerr2ga1",
+                     &sprom->rxgainerr2ga[1], 0);
+       nvram_read_u8(prefix, NULL, "rxgainerr2ga2",
+                     &sprom->rxgainerr2ga[2], 0);
+       nvram_read_u8(prefix, NULL, "rxgainerr5gla0",
+                     &sprom->rxgainerr5gla[0], 0);
+       nvram_read_u8(prefix, NULL, "rxgainerr5gla1",
+                     &sprom->rxgainerr5gla[1], 0);
+       nvram_read_u8(prefix, NULL, "rxgainerr5gla2",
+                     &sprom->rxgainerr5gla[2], 0);
+       nvram_read_u8(prefix, NULL, "rxgainerr5gma0",
+                     &sprom->rxgainerr5gma[0], 0);
+       nvram_read_u8(prefix, NULL, "rxgainerr5gma1",
+                     &sprom->rxgainerr5gma[1], 0);
+       nvram_read_u8(prefix, NULL, "rxgainerr5gma2",
+                     &sprom->rxgainerr5gma[2], 0);
+       nvram_read_u8(prefix, NULL, "rxgainerr5gha0",
+                     &sprom->rxgainerr5gha[0], 0);
+       nvram_read_u8(prefix, NULL, "rxgainerr5gha1",
+                     &sprom->rxgainerr5gha[1], 0);
+       nvram_read_u8(prefix, NULL, "rxgainerr5gha2",
+                     &sprom->rxgainerr5gha[2], 0);
+       nvram_read_u8(prefix, NULL, "rxgainerr5gua0",
+                     &sprom->rxgainerr5gua[0], 0);
+       nvram_read_u8(prefix, NULL, "rxgainerr5gua1",
+                     &sprom->rxgainerr5gua[1], 0);
+       nvram_read_u8(prefix, NULL, "rxgainerr5gua2",
+                     &sprom->rxgainerr5gua[2], 0);
+       nvram_read_u8(prefix, NULL, "noiselvl2ga0", &sprom->noiselvl2ga[0], 0);
+       nvram_read_u8(prefix, NULL, "noiselvl2ga1", &sprom->noiselvl2ga[1], 0);
+       nvram_read_u8(prefix, NULL, "noiselvl2ga2", &sprom->noiselvl2ga[2], 0);
+       nvram_read_u8(prefix, NULL, "noiselvl5gla0",
+                     &sprom->noiselvl5gla[0], 0);
+       nvram_read_u8(prefix, NULL, "noiselvl5gla1",
+                     &sprom->noiselvl5gla[1], 0);
+       nvram_read_u8(prefix, NULL, "noiselvl5gla2",
+                     &sprom->noiselvl5gla[2], 0);
+       nvram_read_u8(prefix, NULL, "noiselvl5gma0",
+                     &sprom->noiselvl5gma[0], 0);
+       nvram_read_u8(prefix, NULL, "noiselvl5gma1",
+                     &sprom->noiselvl5gma[1], 0);
+       nvram_read_u8(prefix, NULL, "noiselvl5gma2",
+                     &sprom->noiselvl5gma[2], 0);
+       nvram_read_u8(prefix, NULL, "noiselvl5gha0",
+                     &sprom->noiselvl5gha[0], 0);
+       nvram_read_u8(prefix, NULL, "noiselvl5gha1",
+                     &sprom->noiselvl5gha[1], 0);
+       nvram_read_u8(prefix, NULL, "noiselvl5gha2",
+                     &sprom->noiselvl5gha[2], 0);
+       nvram_read_u8(prefix, NULL, "noiselvl5gua0",
+                     &sprom->noiselvl5gua[0], 0);
+       nvram_read_u8(prefix, NULL, "noiselvl5gua1",
+                     &sprom->noiselvl5gua[1], 0);
+       nvram_read_u8(prefix, NULL, "noiselvl5gua2",
+                     &sprom->noiselvl5gua[2], 0);
+       nvram_read_u8(prefix, NULL, "pcieingress_war",
+                     &sprom->pcieingress_war, 0);
+}
+
+static void bcm47xx_fill_sprom_r9(struct ssb_sprom *sprom, const char *prefix)
+{
+       nvram_read_u16(prefix, NULL, "cckbw202gpo", &sprom->cckbw202gpo, 0);
+       nvram_read_u16(prefix, NULL, "cckbw20ul2gpo", &sprom->cckbw20ul2gpo, 0);
+       nvram_read_u32(prefix, NULL, "legofdmbw202gpo",
+                      &sprom->legofdmbw202gpo, 0);
+       nvram_read_u32(prefix, NULL, "legofdmbw20ul2gpo",
+                      &sprom->legofdmbw20ul2gpo, 0);
+       nvram_read_u32(prefix, NULL, "legofdmbw205glpo",
+                      &sprom->legofdmbw205glpo, 0);
+       nvram_read_u32(prefix, NULL, "legofdmbw20ul5glpo",
+                      &sprom->legofdmbw20ul5glpo, 0);
+       nvram_read_u32(prefix, NULL, "legofdmbw205gmpo",
+                      &sprom->legofdmbw205gmpo, 0);
+       nvram_read_u32(prefix, NULL, "legofdmbw20ul5gmpo",
+                      &sprom->legofdmbw20ul5gmpo, 0);
+       nvram_read_u32(prefix, NULL, "legofdmbw205ghpo",
+                      &sprom->legofdmbw205ghpo, 0);
+       nvram_read_u32(prefix, NULL, "legofdmbw20ul5ghpo",
+                      &sprom->legofdmbw20ul5ghpo, 0);
+       nvram_read_u32(prefix, NULL, "mcsbw202gpo", &sprom->mcsbw202gpo, 0);
+       nvram_read_u32(prefix, NULL, "mcsbw20ul2gpo", &sprom->mcsbw20ul2gpo, 0);
+       nvram_read_u32(prefix, NULL, "mcsbw402gpo", &sprom->mcsbw402gpo, 0);
+       nvram_read_u32(prefix, NULL, "mcsbw205glpo", &sprom->mcsbw205glpo, 0);
+       nvram_read_u32(prefix, NULL, "mcsbw20ul5glpo",
+                      &sprom->mcsbw20ul5glpo, 0);
+       nvram_read_u32(prefix, NULL, "mcsbw405glpo", &sprom->mcsbw405glpo, 0);
+       nvram_read_u32(prefix, NULL, "mcsbw205gmpo", &sprom->mcsbw205gmpo, 0);
+       nvram_read_u32(prefix, NULL, "mcsbw20ul5gmpo",
+                      &sprom->mcsbw20ul5gmpo, 0);
+       nvram_read_u32(prefix, NULL, "mcsbw405gmpo", &sprom->mcsbw405gmpo, 0);
+       nvram_read_u32(prefix, NULL, "mcsbw205ghpo", &sprom->mcsbw205ghpo, 0);
+       nvram_read_u32(prefix, NULL, "mcsbw20ul5ghpo",
+                      &sprom->mcsbw20ul5ghpo, 0);
+       nvram_read_u32(prefix, NULL, "mcsbw405ghpo", &sprom->mcsbw405ghpo, 0);
+       nvram_read_u16(prefix, NULL, "mcs32po", &sprom->mcs32po, 0);
+       nvram_read_u16(prefix, NULL, "legofdm40duppo",
+                      &sprom->legofdm40duppo, 0);
+       nvram_read_u8(prefix, NULL, "sar2g", &sprom->sar2g, 0);
+       nvram_read_u8(prefix, NULL, "sar5g", &sprom->sar5g, 0);
+}
+
+static void bcm47xx_fill_sprom_path_r4589(struct ssb_sprom *sprom,
+                                         const char *prefix)
+{
+       char postfix[2];
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(sprom->core_pwr_info); i++) {
+               struct ssb_sprom_core_pwr_info *pwr_info = &sprom->core_pwr_info[i];
+               snprintf(postfix, sizeof(postfix), "%i", i);
+               nvram_read_u8(prefix, postfix, "maxp2ga",
+                             &pwr_info->maxpwr_2g, 0);
+               nvram_read_u8(prefix, postfix, "itt2ga",
+                             &pwr_info->itssi_2g, 0);
+               nvram_read_u8(prefix, postfix, "itt5ga",
+                             &pwr_info->itssi_5g, 0);
+               nvram_read_u16(prefix, postfix, "pa2gw0a",
+                              &pwr_info->pa_2g[0], 0);
+               nvram_read_u16(prefix, postfix, "pa2gw1a",
+                              &pwr_info->pa_2g[1], 0);
+               nvram_read_u16(prefix, postfix, "pa2gw2a",
+                              &pwr_info->pa_2g[2], 0);
+               nvram_read_u8(prefix, postfix, "maxp5ga",
+                             &pwr_info->maxpwr_5g, 0);
+               nvram_read_u8(prefix, postfix, "maxp5gha",
+                             &pwr_info->maxpwr_5gh, 0);
+               nvram_read_u8(prefix, postfix, "maxp5gla",
+                             &pwr_info->maxpwr_5gl, 0);
+               nvram_read_u16(prefix, postfix, "pa5gw0a",
+                              &pwr_info->pa_5g[0], 0);
+               nvram_read_u16(prefix, postfix, "pa5gw1a",
+                              &pwr_info->pa_5g[1], 0);
+               nvram_read_u16(prefix, postfix, "pa5gw2a",
+                              &pwr_info->pa_5g[2], 0);
+               nvram_read_u16(prefix, postfix, "pa5glw0a",
+                              &pwr_info->pa_5gl[0], 0);
+               nvram_read_u16(prefix, postfix, "pa5glw1a",
+                              &pwr_info->pa_5gl[1], 0);
+               nvram_read_u16(prefix, postfix, "pa5glw2a",
+                              &pwr_info->pa_5gl[2], 0);
+               nvram_read_u16(prefix, postfix, "pa5ghw0a",
+                              &pwr_info->pa_5gh[0], 0);
+               nvram_read_u16(prefix, postfix, "pa5ghw1a",
+                              &pwr_info->pa_5gh[1], 0);
+               nvram_read_u16(prefix, postfix, "pa5ghw2a",
+                              &pwr_info->pa_5gh[2], 0);
+       }
+}
+
+static void bcm47xx_fill_sprom_path_r45(struct ssb_sprom *sprom,
+                                       const char *prefix)
+{
+       char postfix[2];
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(sprom->core_pwr_info); i++) {
+               struct ssb_sprom_core_pwr_info *pwr_info = &sprom->core_pwr_info[i];
+               snprintf(postfix, sizeof(postfix), "%i", i);
+               nvram_read_u16(prefix, postfix, "pa2gw3a",
+                              &pwr_info->pa_2g[3], 0);
+               nvram_read_u16(prefix, postfix, "pa5gw3a",
+                              &pwr_info->pa_5g[3], 0);
+               nvram_read_u16(prefix, postfix, "pa5glw3a",
+                              &pwr_info->pa_5gl[3], 0);
+               nvram_read_u16(prefix, postfix, "pa5ghw3a",
+                              &pwr_info->pa_5gh[3], 0);
+       }
+}
+
+void bcm47xx_fill_sprom_ethernet(struct ssb_sprom *sprom, const char *prefix)
+{
+       nvram_read_macaddr(prefix, "et0macaddr", &sprom->et0mac);
+       nvram_read_u8(prefix, NULL, "et0mdcport", &sprom->et0mdcport, 0);
+       nvram_read_u8(prefix, NULL, "et0phyaddr", &sprom->et0phyaddr, 0);
+
+       nvram_read_macaddr(prefix, "et1macaddr", &sprom->et1mac);
+       nvram_read_u8(prefix, NULL, "et1mdcport", &sprom->et1mdcport, 0);
+       nvram_read_u8(prefix, NULL, "et1phyaddr", &sprom->et1phyaddr, 0);
+
+       nvram_read_macaddr(prefix, "macaddr", &sprom->il0mac);
+       nvram_read_macaddr(prefix, "il0macaddr", &sprom->il0mac);
+}
+
+void bcm47xx_fill_sprom(struct ssb_sprom *sprom, const char *prefix)
+{
+       memset(sprom, 0, sizeof(struct ssb_sprom));
+
+       bcm47xx_fill_sprom_ethernet(sprom, prefix);
+
+       nvram_read_u8(prefix, NULL, "sromrev", &sprom->revision, 0);
+
+       switch (sprom->revision) {
+       case 1:
+               bcm47xx_fill_sprom_r1234589(sprom, prefix);
+               bcm47xx_fill_sprom_r12389(sprom, prefix);
+               bcm47xx_fill_sprom_r1(sprom, prefix);
+               break;
+       case 2:
+               bcm47xx_fill_sprom_r1234589(sprom, prefix);
+               bcm47xx_fill_sprom_r12389(sprom, prefix);
+               bcm47xx_fill_sprom_r2389(sprom, prefix);
+               bcm47xx_fill_sprom_r2(sprom, prefix);
+               break;
+       case 3:
+               bcm47xx_fill_sprom_r1234589(sprom, prefix);
+               bcm47xx_fill_sprom_r12389(sprom, prefix);
+               bcm47xx_fill_sprom_r2389(sprom, prefix);
+               bcm47xx_fill_sprom_r389(sprom, prefix);
+               bcm47xx_fill_sprom_r3(sprom, prefix);
+               break;
+       case 4:
+       case 5:
+               bcm47xx_fill_sprom_r1234589(sprom, prefix);
+               bcm47xx_fill_sprom_r4589(sprom, prefix);
+               bcm47xx_fill_sprom_r458(sprom, prefix);
+               bcm47xx_fill_sprom_r45(sprom, prefix);
+               bcm47xx_fill_sprom_path_r4589(sprom, prefix);
+               bcm47xx_fill_sprom_path_r45(sprom, prefix);
+               break;
+       case 8:
+               bcm47xx_fill_sprom_r1234589(sprom, prefix);
+               bcm47xx_fill_sprom_r12389(sprom, prefix);
+               bcm47xx_fill_sprom_r2389(sprom, prefix);
+               bcm47xx_fill_sprom_r389(sprom, prefix);
+               bcm47xx_fill_sprom_r4589(sprom, prefix);
+               bcm47xx_fill_sprom_r458(sprom, prefix);
+               bcm47xx_fill_sprom_r89(sprom, prefix);
+               bcm47xx_fill_sprom_path_r4589(sprom, prefix);
+               break;
+       case 9:
+               bcm47xx_fill_sprom_r1234589(sprom, prefix);
+               bcm47xx_fill_sprom_r12389(sprom, prefix);
+               bcm47xx_fill_sprom_r2389(sprom, prefix);
+               bcm47xx_fill_sprom_r389(sprom, prefix);
+               bcm47xx_fill_sprom_r4589(sprom, prefix);
+               bcm47xx_fill_sprom_r89(sprom, prefix);
+               bcm47xx_fill_sprom_r9(sprom, prefix);
+               bcm47xx_fill_sprom_path_r4589(sprom, prefix);
+               break;
+       default:
+               pr_warn("Unsupported SPROM revision %d detected. Will extract"
+                       " v1\n", sprom->revision);
+               sprom->revision = 1;
+               bcm47xx_fill_sprom_r1234589(sprom, prefix);
+               bcm47xx_fill_sprom_r12389(sprom, prefix);
+               bcm47xx_fill_sprom_r1(sprom, prefix);
+       }
+}
index 4479fd669ac1877a4d84a65284c714bd68310633..28c6b276c21624a4550c2411042065936464d19c 100644 (file)
@@ -8,7 +8,7 @@ CONFIG_HIGH_RES_TIMERS=y
 # CONFIG_SECCOMP is not set
 CONFIG_USE_OF=y
 CONFIG_EXPERIMENTAL=y
-CONFIG_CROSS_COMPILE="mips-linux-gnu-"
+CONFIG_CROSS_COMPILE=""
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
@@ -22,7 +22,7 @@ CONFIG_AUDIT=y
 CONFIG_CGROUPS=y
 CONFIG_NAMESPACES=y
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE="usr/dev_file_list usr/rootfs.xlp"
+CONFIG_INITRAMFS_SOURCE=""
 CONFIG_RD_BZIP2=y
 CONFIG_RD_LZMA=y
 CONFIG_INITRAMFS_COMPRESSION_LZMA=y
index 7c68666fdd646c3354f872ffc91eeeecfa4785d3..d0b857d98c91703b01950f9d1a705c1048cd7ac0 100644 (file)
@@ -8,7 +8,7 @@ CONFIG_HIGH_RES_TIMERS=y
 CONFIG_PREEMPT_VOLUNTARY=y
 CONFIG_KEXEC=y
 CONFIG_EXPERIMENTAL=y
-CONFIG_CROSS_COMPILE="mips-linux-gnu-"
+CONFIG_CROSS_COMPILE=""
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
@@ -22,7 +22,7 @@ CONFIG_AUDIT=y
 CONFIG_NAMESPACES=y
 CONFIG_SCHED_AUTOGROUP=y
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE="usr/dev_file_list usr/rootfs.xlr"
+CONFIG_INITRAMFS_SOURCE=""
 CONFIG_RD_BZIP2=y
 CONFIG_RD_LZMA=y
 CONFIG_INITRAMFS_COMPRESSION_GZIP=y
index 3b0b6e8c85334d610099d554f5a7a72b941ffee9..7fda0ce5f692cd51ed8b06f788bffc6a14f866f7 100644 (file)
@@ -6,7 +6,7 @@ CONFIG_HZ_1000=y
 CONFIG_PREEMPT=y
 # CONFIG_SECCOMP is not set
 CONFIG_EXPERIMENTAL=y
-CONFIG_CROSS_COMPILE="mips-linux-"
+CONFIG_CROSS_COMPILE=""
 # CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=16
index 556e1be20bf63862bacf3fcb464b6b87418c50eb..fb9975c74c571a01526f42667a8f0d7cbedf235e 100644 (file)
@@ -11,6 +11,9 @@
 #include <asm/io.h>
 #include <asm/mach-au1x00/au1000.h>
 
+struct gpio;
+struct gpio_chip;
+
 /* with the current GPIC design, up to 128 GPIOs are possible.
  * The only implementation so far is in the Au1300, which has 75 externally
  * available GPIOs.
@@ -203,7 +206,22 @@ static inline int gpio_request(unsigned int gpio, const char *label)
        return 0;
 }
 
-static inline void gpio_free(unsigned int gpio)
+static inline int gpio_request_one(unsigned gpio,
+                                       unsigned long flags, const char *label)
+{
+       return 0;
+}
+
+static inline int gpio_request_array(struct gpio *array, size_t num)
+{
+       return 0;
+}
+
+static inline void gpio_free(unsigned gpio)
+{
+}
+
+static inline void gpio_free_array(struct gpio *array, size_t num)
 {
 }
 
index de95e0723e2bb058d3164a54c6cc9a1153b9b6e0..5ecaf47b34d2c965dac18d212497dcaf1c71a562 100644 (file)
@@ -44,4 +44,7 @@ union bcm47xx_bus {
 extern union bcm47xx_bus bcm47xx_bus;
 extern enum bcm47xx_bus_type bcm47xx_bus_type;
 
+void bcm47xx_fill_sprom(struct ssb_sprom *sprom, const char *prefix);
+void bcm47xx_fill_sprom_ethernet(struct ssb_sprom *sprom, const char *prefix);
+
 #endif /* __ASM_BCM47XX_H */
index 184d5ecb5f51bbec1f7b0584adfe0e273a383a42..69ef3efe06e7ab40f5a168a5ec766031177df2d6 100644 (file)
@@ -37,7 +37,7 @@ struct nvram_header {
 
 extern int nvram_getenv(char *name, char *val, size_t val_len);
 
-static inline void nvram_parse_macaddr(char *buf, u8 *macaddr)
+static inline void nvram_parse_macaddr(char *buf, u8 macaddr[6])
 {
        if (strchr(buf, ':'))
                sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &macaddr[0],
index d41790928c648de70fb02a7404517f1fc7a94fba..da9bd7d270d18a761f74f6168653d2eb16da7118 100644 (file)
@@ -39,9 +39,6 @@
 #define HPAGE_MASK     (~(HPAGE_SIZE - 1))
 #define HUGETLB_PAGE_ORDER     (HPAGE_SHIFT - PAGE_SHIFT)
 #else /* !CONFIG_HUGETLB_PAGE */
-# ifndef BUILD_BUG
-#  define BUILD_BUG() do { extern void __build_bug(void); __build_bug(); } while (0)
-# endif
 #define HPAGE_SHIFT    ({BUILD_BUG(); 0; })
 #define HPAGE_SIZE     ({BUILD_BUG(); 0; })
 #define HPAGE_MASK     ({BUILD_BUG(); 0; })
index 58fe71afd8797dd37e1cf0442f1b360082af63a2..d5e950ab852792b15c2226f193f55061719f0e20 100644 (file)
@@ -8,7 +8,6 @@
  * SMP support for BMIPS
  */
 
-#include <linux/version.h>
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
index cc4a3f120f54d6f036e66812cf47e5c35e7dbff9..d79ae5437b5871efda13f052c5f7511ccf9587b9 100644 (file)
@@ -1135,7 +1135,7 @@ asmlinkage void do_mt(struct pt_regs *regs)
                printk(KERN_DEBUG "YIELD Scheduler Exception\n");
                break;
        case 5:
-               printk(KERN_DEBUG "Gating Storage Schedulier Exception\n");
+               printk(KERN_DEBUG "Gating Storage Scheduler Exception\n");
                break;
        default:
                printk(KERN_DEBUG "*** UNKNOWN THREAD EXCEPTION %d ***\n",
index a81176f44c74d4e39be2eaf8d939ccdf1aa5157b..924da5eb7031498ea93dc050a7492aa78f5bb0ec 100644 (file)
@@ -69,7 +69,6 @@ SECTIONS
        RODATA
 
        /* writeable */
-       _sdata = .;                             /* Start of data section */
        .data : {       /* Data */
                . = . + DATAOFFSET;             /* for CONFIG_MAPPED_KERNEL */
 
index 937cf3368164c6f6d4a6db4b1867ca5866a36ed7..69ebd586d7ffbef5029b8540ae3d021135035295 100644 (file)
@@ -42,6 +42,8 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, unsigned long writ
        const int field = sizeof(unsigned long) * 2;
        siginfo_t info;
        int fault;
+       unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
+                                                (write ? FAULT_FLAG_WRITE : 0);
 
 #if 0
        printk("Cpu%d[%s:%d:%0*lx:%ld:%0*lx]\n", raw_smp_processor_id(),
@@ -91,6 +93,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, unsigned long writ
        if (in_atomic() || !mm)
                goto bad_area_nosemaphore;
 
+retry:
        down_read(&mm->mmap_sem);
        vma = find_vma(mm, address);
        if (!vma)
@@ -144,7 +147,11 @@ good_area:
         * make sure we exit gracefully rather than endlessly redo
         * the fault.
         */
-       fault = handle_mm_fault(mm, vma, address, write ? FAULT_FLAG_WRITE : 0);
+       fault = handle_mm_fault(mm, vma, address, flags);
+
+       if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
+               return;
+
        perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
        if (unlikely(fault & VM_FAULT_ERROR)) {
                if (fault & VM_FAULT_OOM)
@@ -153,12 +160,27 @@ good_area:
                        goto do_sigbus;
                BUG();
        }
-       if (fault & VM_FAULT_MAJOR) {
-               perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, regs, address);
-               tsk->maj_flt++;
-       } else {
-               perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, regs, address);
-               tsk->min_flt++;
+       if (flags & FAULT_FLAG_ALLOW_RETRY) {
+               if (fault & VM_FAULT_MAJOR) {
+                       perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1,
+                                                 regs, address);
+                       tsk->maj_flt++;
+               } else {
+                       perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1,
+                                                 regs, address);
+                       tsk->min_flt++;
+               }
+               if (fault & VM_FAULT_RETRY) {
+                       flags &= ~FAULT_FLAG_ALLOW_RETRY;
+
+                       /*
+                        * No need to up_read(&mm->mmap_sem) as we would
+                        * have already released it in __lock_page_or_retry
+                        * in mm/filemap.c.
+                        */
+
+                       goto retry;
+               }
        }
 
        up_read(&mm->mmap_sem);
index aec2b111d35b0131f805e736bd80c2ca19d59cbf..15521505ebe80a4a6975f11905e4694111474a08 100644 (file)
@@ -279,7 +279,6 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus)
 {
        /* Propagate hose info into the subordinate devices.  */
 
-       struct list_head *ln;
        struct pci_dev *dev = bus->self;
 
        if (pci_probe_only && dev &&
@@ -288,9 +287,7 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus)
                pcibios_fixup_device_resources(dev, bus);
        }
 
-       for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
-               dev = pci_dev_b(ln);
-
+       list_for_each_entry(dev, &bus->devices, bus_list) {
                if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
                        pcibios_fixup_device_resources(dev, bus);
        }
index 86b98e98fb4f2f09906a8ee271550e1ab9b961c9..62ead6601c69437aeaafe5dcd3bc7c895fcee5f1 100644 (file)
  */
 void __init titan_ht_pcibios_fixup_bus(struct pci_bus *bus)
 {
-       struct pci_bus *current_bus = bus;
-       struct pci_dev *devices;
-       struct list_head *devices_link;
-
-       list_for_each(devices_link, &(current_bus->devices)) {
-               devices = pci_dev_b(devices_link);
-               if (devices == NULL)
-                       continue;
-       }
-
        /*
         * PLX and SPKT related changes go here
         */
index 8e93b21225249fe489b8666b94a4ac407b43406b..4642f56e70e54c38aca1d98df27fee53b7761402 100644 (file)
@@ -102,7 +102,7 @@ static int __init tx_7segled_init_sysfs(void)
                        break;
                }
                dev->id = i;
-               dev->dev = &tx_7segled_subsys;
+               dev->bus = &tx_7segled_subsys;
                error = device_register(dev);
                if (!error) {
                        device_create_file(dev, &dev_attr_ascii);
index 054537c5f9c9c002a29ed1808b21f66b9a102fad..e612ce4512c73db468d6597673d87fa729b24226 100644 (file)
@@ -77,7 +77,6 @@ struct pt_regs {
        long  syscallno;        /* Syscall number (used by strace) */
        long dummy;             /* Cheap alignment fix */
 };
-#endif /* __ASSEMBLY__ */
 
 /* TODO: Rename this to REDZONE because that's what it is */
 #define STACK_FRAME_OVERHEAD  128  /* size of minimum stack frame */
@@ -87,6 +86,13 @@ struct pt_regs {
 #define user_stack_pointer(regs)       ((unsigned long)(regs)->sp)
 #define profile_pc(regs)               instruction_pointer(regs)
 
+static inline long regs_return_value(struct pt_regs *regs)
+{
+       return regs->gpr[11];
+}
+
+#endif /* __ASSEMBLY__ */
+
 /*
  * Offsets used by 'ptrace' system call interface.
  */
index 45744a384927976998c77c876077ad3c6559e7e6..ca534082d5f317566e5958c3337321852e1c72ca 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <linux/init_task.h>
 #include <linux/mqueue.h>
+#include <linux/export.h>
 
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
index 59b302338331395f568c22b81486b09bacfcf1b8..4bfead220956e2be70146f6a209a1c6cebd1b125 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/irq.h>
 #include <linux/seq_file.h>
 #include <linux/kernel_stat.h>
+#include <linux/export.h>
 
 #include <linux/irqflags.h>
 
index 656b94beab891ecd982ceb4e4e8a2c68cf907354..7259047d5f9dbd21cc8529119dfc21f61cd2b840 100644 (file)
@@ -188,11 +188,9 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
                 */
                ret = -1L;
 
-       /* Are these regs right??? */
-       if (unlikely(current->audit_context))
-               audit_syscall_entry(audit_arch(), regs->syscallno,
-                                   regs->gpr[3], regs->gpr[4],
-                                   regs->gpr[5], regs->gpr[6]);
+       audit_syscall_entry(audit_arch(), regs->syscallno,
+                           regs->gpr[3], regs->gpr[4],
+                           regs->gpr[5], regs->gpr[6]);
 
        return ret ? : regs->syscallno;
 }
@@ -201,9 +199,7 @@ asmlinkage void do_syscall_trace_leave(struct pt_regs *regs)
 {
        int step;
 
-       if (unlikely(current->audit_context))
-               audit_syscall_exit(AUDITSC_RESULT(regs->gpr[11]),
-                                  regs->gpr[11]);
+       audit_syscall_exit(regs);
 
        step = test_thread_flag(TIF_SINGLESTEP);
        if (step || test_thread_flag(TIF_SYSCALL_TRACE))
index 55cca1dac431bc80c1e9ea5f34274be2022e4494..19ab7b2ea1cd6b899531bc528cbf4d91b7fc11f4 100644 (file)
@@ -31,7 +31,11 @@ ifdef CONFIG_64BIT
 UTS_MACHINE    := parisc64
 CHECKFLAGS     += -D__LP64__=1 -m64
 WIDTH          := 64
+
+# FIXME: if no default set, should really try to locate dynamically
+ifeq ($(CROSS_COMPILE),)
 CROSS_COMPILE  := hppa64-linux-gnu-
+endif
 else # 32-bit
 WIDTH          :=
 endif
index 2a56a0dbd1f7e1ae87b7bd10c6200158e49662fa..74876f73740711e39a62b5f41cb4108a68834cb8 100644 (file)
 
                        EMAC0: ethernet@ef600c00 {
                                device_type = "network";
-                               compatible = "ibm,emac4sync";
+                               compatible = "ibm,emac-apm821xx", "ibm,emac4sync";
                                interrupt-parent = <&EMAC0>;
                                interrupts = <0x0 0x1>;
                                #interrupt-cells = <1>;
index d1727584230a66b504ae1e9e0beed8f3522c5b23..6d99a5fcc09030114dd8d475e6fe54184fc59814 100644 (file)
@@ -227,6 +227,9 @@ config COMPAT
 config SYSVIPC_COMPAT
        def_bool y if COMPAT && SYSVIPC
 
+config KEYS_COMPAT
+       def_bool y if COMPAT && KEYS
+
 config AUDIT_ARCH
        def_bool y
 
index 2e49748b27dab5ca3e62c2b4f63909c50058a593..234f1d859cea07c4f0cd31be401448fc8fe0870e 100644 (file)
@@ -172,13 +172,6 @@ static inline int is_compat_task(void)
        return is_32bit_task();
 }
 
-#else
-
-static inline int is_compat_task(void)
-{
-       return 0;
-}
-
 #endif
 
 static inline void __user *arch_compat_alloc_user_space(long len)
index 39f8fd4438fc8a3810333a6e659e60dce4ea04aa..c383ce440d99952149895b0094d6794a22af2d5c 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/module.h>
 #include <linux/gfp.h>
 #include <linux/slab.h>
-#include <linux/crash_dump.h>
 #include <linux/bootmem.h>
 #include <linux/elf.h>
 #include <asm/ipl.h>
index 4261aa799774f5972940f22ebd1b7c7ea29220f8..e795933eb2cbaaf446d5ea62c0b43976d38479f0 100644 (file)
@@ -29,7 +29,6 @@
 #include <asm/irq.h>
 #include <asm/timer.h>
 #include <asm/nmi.h>
-#include <asm/compat.h>
 #include <asm/smp.h>
 #include "entry.h"
 
index 9d82ed4bcb273a91bd6c4875d204218da2d420a2..61f95489d70c2539068a6cfc2dc3acc55d4a3cac 100644 (file)
@@ -20,8 +20,8 @@
 #include <linux/regset.h>
 #include <linux/tracehook.h>
 #include <linux/seccomp.h>
+#include <linux/compat.h>
 #include <trace/syscall.h>
-#include <asm/compat.h>
 #include <asm/segment.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
index 354de0763efff361972fae399064b4f786cc5a0c..3b2efc81f34e849f0a00bf464c133a5e4add9ade 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/kexec.h>
 #include <linux/crash_dump.h>
 #include <linux/memory.h>
+#include <linux/compat.h>
 
 #include <asm/ipl.h>
 #include <asm/uaccess.h>
@@ -59,7 +60,6 @@
 #include <asm/ptrace.h>
 #include <asm/sections.h>
 #include <asm/ebcdic.h>
-#include <asm/compat.h>
 #include <asm/kvm_virtio.h>
 #include <asm/diag.h>
 
index a8ba840294ff0524c66262bc1f438a1ac995d7bc..2d421d90fada708248c8e678be34d92b08c0cef0 100644 (file)
@@ -30,7 +30,6 @@
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include <asm/lowcore.h>
-#include <asm/compat.h>
 #include "entry.h"
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
index 354dd39073efec6c1a1bf034ab63c4e82dcc824c..e8fcd928dc78005599f0b07aad6142052193f16d 100644 (file)
@@ -36,7 +36,6 @@
 #include <asm/pgtable.h>
 #include <asm/irq.h>
 #include <asm/mmu_context.h>
-#include <asm/compat.h>
 #include "../kernel/entry.h"
 
 #ifndef CONFIG_64BIT
index 5d633019d8f3f86fb4da43a1c04ad060a6f2e83f..50236610de83cc0cb8d76ca34bbd2cd0f5c0e0aa 100644 (file)
@@ -223,16 +223,38 @@ void free_initrd_mem(unsigned long start, unsigned long end)
 #ifdef CONFIG_MEMORY_HOTPLUG
 int arch_add_memory(int nid, u64 start, u64 size)
 {
-       struct pglist_data *pgdat;
+       unsigned long zone_start_pfn, zone_end_pfn, nr_pages;
+       unsigned long start_pfn = PFN_DOWN(start);
+       unsigned long size_pages = PFN_DOWN(size);
        struct zone *zone;
        int rc;
 
-       pgdat = NODE_DATA(nid);
-       zone = pgdat->node_zones + ZONE_MOVABLE;
        rc = vmem_add_mapping(start, size);
        if (rc)
                return rc;
-       rc = __add_pages(nid, zone, PFN_DOWN(start), PFN_DOWN(size));
+       for_each_zone(zone) {
+               if (zone_idx(zone) != ZONE_MOVABLE) {
+                       /* Add range within existing zone limits */
+                       zone_start_pfn = zone->zone_start_pfn;
+                       zone_end_pfn = zone->zone_start_pfn +
+                                      zone->spanned_pages;
+               } else {
+                       /* Add remaining range to ZONE_MOVABLE */
+                       zone_start_pfn = start_pfn;
+                       zone_end_pfn = start_pfn + size_pages;
+               }
+               if (start_pfn < zone_start_pfn || start_pfn >= zone_end_pfn)
+                       continue;
+               nr_pages = (start_pfn + size_pages > zone_end_pfn) ?
+                          zone_end_pfn - start_pfn : size_pages;
+               rc = __add_pages(nid, zone, start_pfn, nr_pages);
+               if (rc)
+                       break;
+               start_pfn += nr_pages;
+               size_pages -= nr_pages;
+               if (!size_pages)
+                       break;
+       }
        if (rc)
                vmem_remove_mapping(start, size);
        return rc;
index f09c74881b7e5b2c12d323265f289e0681eec66b..a0155c02e324900ae54745ae4024c3b384b51740 100644 (file)
@@ -29,8 +29,8 @@
 #include <linux/mman.h>
 #include <linux/module.h>
 #include <linux/random.h>
+#include <linux/compat.h>
 #include <asm/pgalloc.h>
-#include <asm/compat.h>
 
 static unsigned long stack_maxrandom_size(void)
 {
index fd843877e84152d87d437fca5173b858336a104a..39e49091f64841873ee1d79d768aa677832c500f 100644 (file)
@@ -315,6 +315,13 @@ static int load_aout_binary(struct linux_binprm *bprm, struct pt_regs *regs)
        current->mm->free_area_cache = TASK_UNMAPPED_BASE;
        current->mm->cached_hole_size = 0;
 
+       retval = setup_arg_pages(bprm, IA32_STACK_TOP, EXSTACK_DEFAULT);
+       if (retval < 0) {
+               /* Someone check-me: is this error path enough? */
+               send_sig(SIGKILL, current, 0);
+               return retval;
+       }
+
        install_exec_creds(bprm);
        current->flags &= ~PF_FORKNOEXEC;
 
@@ -410,13 +417,6 @@ beyond_if:
 
        set_brk(current->mm->start_brk, current->mm->brk);
 
-       retval = setup_arg_pages(bprm, IA32_STACK_TOP, EXSTACK_DEFAULT);
-       if (retval < 0) {
-               /* Someone check-me: is this error path enough? */
-               send_sig(SIGKILL, current, 0);
-               return retval;
-       }
-
        current->mm->start_stack =
                (unsigned long)create_aout_tables((char __user *)bprm->p, bprm);
        /* start thread */
index 096c975e099fee9ed2578b9ca4d9f77d9ef56006..461ce432b1c2755c6d0f70e00e3ac9f3993ecba1 100644 (file)
@@ -242,4 +242,12 @@ static inline void perf_get_x86_pmu_capability(struct x86_pmu_capability *cap)
 static inline void perf_events_lapic_init(void)        { }
 #endif
 
+#if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_AMD)
+ extern void amd_pmu_enable_virt(void);
+ extern void amd_pmu_disable_virt(void);
+#else
+ static inline void amd_pmu_enable_virt(void) { }
+ static inline void amd_pmu_disable_virt(void) { }
+#endif
+
 #endif /* _ASM_X86_PERF_EVENT_H */
index 6b45e5e7a9015203085c5d09b4de04e6918b46eb..73d08ed98a64fc8beafb3c2e6768d19f02c09f89 100644 (file)
@@ -326,8 +326,7 @@ static void __cpuinit amd_calc_l3_indices(struct amd_northbridge *nb)
        l3->indices = (max(max3(sc0, sc1, sc2), sc3) << 10) - 1;
 }
 
-static void __cpuinit amd_init_l3_cache(struct _cpuid4_info_regs *this_leaf,
-                                       int index)
+static void __cpuinit amd_init_l3_cache(struct _cpuid4_info_regs *this_leaf, int index)
 {
        int node;
 
@@ -725,14 +724,16 @@ static DEFINE_PER_CPU(struct _cpuid4_info *, ici_cpuid4_info);
 #define CPUID4_INFO_IDX(x, y)  (&((per_cpu(ici_cpuid4_info, x))[y]))
 
 #ifdef CONFIG_SMP
-static void __cpuinit cache_shared_cpu_map_setup(unsigned int cpu, int index)
+
+static int __cpuinit cache_shared_amd_cpu_map_setup(unsigned int cpu, int index)
 {
-       struct _cpuid4_info     *this_leaf, *sibling_leaf;
-       unsigned long num_threads_sharing;
-       int index_msb, i, sibling;
+       struct _cpuid4_info *this_leaf;
+       int ret, i, sibling;
        struct cpuinfo_x86 *c = &cpu_data(cpu);
 
-       if ((index == 3) && (c->x86_vendor == X86_VENDOR_AMD)) {
+       ret = 0;
+       if (index == 3) {
+               ret = 1;
                for_each_cpu(i, cpu_llc_shared_mask(cpu)) {
                        if (!per_cpu(ici_cpuid4_info, i))
                                continue;
@@ -743,8 +744,35 @@ static void __cpuinit cache_shared_cpu_map_setup(unsigned int cpu, int index)
                                set_bit(sibling, this_leaf->shared_cpu_map);
                        }
                }
-               return;
+       } else if ((c->x86 == 0x15) && ((index == 1) || (index == 2))) {
+               ret = 1;
+               for_each_cpu(i, cpu_sibling_mask(cpu)) {
+                       if (!per_cpu(ici_cpuid4_info, i))
+                               continue;
+                       this_leaf = CPUID4_INFO_IDX(i, index);
+                       for_each_cpu(sibling, cpu_sibling_mask(cpu)) {
+                               if (!cpu_online(sibling))
+                                       continue;
+                               set_bit(sibling, this_leaf->shared_cpu_map);
+                       }
+               }
        }
+
+       return ret;
+}
+
+static void __cpuinit cache_shared_cpu_map_setup(unsigned int cpu, int index)
+{
+       struct _cpuid4_info *this_leaf, *sibling_leaf;
+       unsigned long num_threads_sharing;
+       int index_msb, i;
+       struct cpuinfo_x86 *c = &cpu_data(cpu);
+
+       if (c->x86_vendor == X86_VENDOR_AMD) {
+               if (cache_shared_amd_cpu_map_setup(cpu, index))
+                       return;
+       }
+
        this_leaf = CPUID4_INFO_IDX(cpu, index);
        num_threads_sharing = 1 + this_leaf->base.eax.split.num_threads_sharing;
 
index 786e76a86322c99ffd67a6fd9ebf03f85b1d36a3..e4eeaaf58a470a841d612724b5ef8f523fb3adb6 100644 (file)
@@ -528,6 +528,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank)
 
        sprintf(name, "threshold_bank%i", bank);
 
+#ifdef CONFIG_SMP
        if (cpu_data(cpu).cpu_core_id && shared_bank[bank]) {   /* symlink */
                i = cpumask_first(cpu_llc_shared_mask(cpu));
 
@@ -553,6 +554,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank)
 
                goto out;
        }
+#endif
 
        b = kzalloc(sizeof(struct threshold_bank), GFP_KERNEL);
        if (!b) {
index 8944062f46e284faaa65ec043403352ea7c5f14c..c30c807ddc7236e444508357e8186bd4d504bd6f 100644 (file)
@@ -147,7 +147,9 @@ struct cpu_hw_events {
        /*
         * AMD specific bits
         */
-       struct amd_nb           *amd_nb;
+       struct amd_nb                   *amd_nb;
+       /* Inverted mask of bits to clear in the perf_ctr ctrl registers */
+       u64                             perf_ctr_virt_mask;
 
        void                            *kfree_on_online;
 };
@@ -417,9 +419,11 @@ void x86_pmu_disable_all(void);
 static inline void __x86_pmu_enable_event(struct hw_perf_event *hwc,
                                          u64 enable_mask)
 {
+       u64 disable_mask = __this_cpu_read(cpu_hw_events.perf_ctr_virt_mask);
+
        if (hwc->extra_reg.reg)
                wrmsrl(hwc->extra_reg.reg, hwc->extra_reg.config);
-       wrmsrl(hwc->config_base, hwc->config | enable_mask);
+       wrmsrl(hwc->config_base, (hwc->config | enable_mask) & ~disable_mask);
 }
 
 void x86_pmu_enable_all(int added);
index 0397b23be8e9006c0171bb092b2e5a8f7249e709..67250a52430bfd9a3d0cf89fa38408d0e8cd793a 100644 (file)
@@ -1,4 +1,5 @@
 #include <linux/perf_event.h>
+#include <linux/export.h>
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -357,7 +358,9 @@ static void amd_pmu_cpu_starting(int cpu)
        struct amd_nb *nb;
        int i, nb_id;
 
-       if (boot_cpu_data.x86_max_cores < 2)
+       cpuc->perf_ctr_virt_mask = AMD_PERFMON_EVENTSEL_HOSTONLY;
+
+       if (boot_cpu_data.x86_max_cores < 2 || boot_cpu_data.x86 == 0x15)
                return;
 
        nb_id = amd_get_nb_id(cpu);
@@ -587,9 +590,9 @@ static __initconst const struct x86_pmu amd_pmu_f15h = {
        .put_event_constraints  = amd_put_event_constraints,
 
        .cpu_prepare            = amd_pmu_cpu_prepare,
-       .cpu_starting           = amd_pmu_cpu_starting,
        .cpu_dead               = amd_pmu_cpu_dead,
 #endif
+       .cpu_starting           = amd_pmu_cpu_starting,
 };
 
 __init int amd_pmu_init(void)
@@ -621,3 +624,33 @@ __init int amd_pmu_init(void)
 
        return 0;
 }
+
+void amd_pmu_enable_virt(void)
+{
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+
+       cpuc->perf_ctr_virt_mask = 0;
+
+       /* Reload all events */
+       x86_pmu_disable_all();
+       x86_pmu_enable_all(0);
+}
+EXPORT_SYMBOL_GPL(amd_pmu_enable_virt);
+
+void amd_pmu_disable_virt(void)
+{
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+
+       /*
+        * We only mask out the Host-only bit so that host-only counting works
+        * when SVM is disabled. If someone sets up a guest-only counter when
+        * SVM is disabled the Guest-only bits still gets set and the counter
+        * will not count anything.
+        */
+       cpuc->perf_ctr_virt_mask = AMD_PERFMON_EVENTSEL_HOSTONLY;
+
+       /* Reload all events */
+       x86_pmu_disable_all();
+       x86_pmu_enable_all(0);
+}
+EXPORT_SYMBOL_GPL(amd_pmu_disable_virt);
index 3fe8239fd8fbd8ef692f57517d0d1dbd37f284ae..1333d9851778ab282c3cc7a282ec9368c1e26035 100644 (file)
@@ -1531,11 +1531,18 @@ ENTRY(nmi)
        /* Use %rdx as out temp variable throughout */
        pushq_cfi %rdx
 
+       /*
+        * If %cs was not the kernel segment, then the NMI triggered in user
+        * space, which means it is definitely not nested.
+        */
+       cmpl $__KERNEL_CS, 16(%rsp)
+       jne first_nmi
+
        /*
         * Check the special variable on the stack to see if NMIs are
         * executing.
         */
-       cmp $1, -8(%rsp)
+       cmpl $1, -8(%rsp)
        je nested_nmi
 
        /*
index ac0417be9131a8d59cd834a61b629dd36ddec5b5..73465aab28f87c09b5313e81e79d54a31afff1f1 100644 (file)
@@ -360,7 +360,6 @@ out:
 static enum ucode_state
 request_microcode_user(int cpu, const void __user *buf, size_t size)
 {
-       pr_info("AMD microcode update via /dev/cpu/microcode not supported\n");
        return UCODE_ERROR;
 }
 
index 5fa553babe566876d70115d1d259bd2d1a4925a6..e385214711cbcf005846c1d0e335502a6c7d9709 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/ftrace_event.h>
 #include <linux/slab.h>
 
+#include <asm/perf_event.h>
 #include <asm/tlbflush.h>
 #include <asm/desc.h>
 #include <asm/kvm_para.h>
@@ -575,6 +576,8 @@ static void svm_hardware_disable(void *garbage)
                wrmsrl(MSR_AMD64_TSC_RATIO, TSC_RATIO_DEFAULT);
 
        cpu_svm_disable();
+
+       amd_pmu_disable_virt();
 }
 
 static int svm_hardware_enable(void *garbage)
@@ -622,6 +625,8 @@ static int svm_hardware_enable(void *garbage)
 
        svm_init_erratum_383();
 
+       amd_pmu_enable_virt();
+
        return 0;
 }
 
index fc45ba887d051e504dd592be40ec2e78d70eea33..e395693abdb16068cd2b268f258d9c79d3d0f3f3 100644 (file)
@@ -48,9 +48,9 @@ static void delay_loop(unsigned long loops)
 }
 
 /* TSC based delay: */
-static void delay_tsc(unsigned long loops)
+static void delay_tsc(unsigned long __loops)
 {
-       unsigned long bclock, now;
+       u32 bclock, now, loops = __loops;
        int cpu;
 
        preempt_disable();
index f581a18c0d4d7d07aac5cdfa8fb443106e3d5e92..8ecbb4bba4b3b44241b64b46079476ad90f7aad4 100644 (file)
@@ -333,13 +333,15 @@ try_again:
                 * Lookup failure means no vma is above this address,
                 * i.e. return with success:
                 */
-               if (!(vma = find_vma_prev(mm, addr, &prev_vma)))
+               vma = find_vma(mm, addr);
+               if (!vma)
                        return addr;
 
                /*
                 * new region fits between prev_vma->vm_end and
                 * vma->vm_start, use it:
                 */
+               prev_vma = vma->vm_prev;
                if (addr + len <= vma->vm_start &&
                            (!prev_vma || (addr >= prev_vma->vm_end))) {
                        /* remember the address as a hint for next time */
index a312e76063a7c4b1320eb80718cf81c33e7361dc..49a5cb55429b6ae51696f43c5a05c63a07df5566 100644 (file)
@@ -60,6 +60,16 @@ static const struct dmi_system_id pci_use_crs_table[] __initconst = {
                        DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
                },
        },
+       /* https://bugzilla.kernel.org/show_bug.cgi?id=42619 */
+       {
+               .callback = set_use_crs,
+               .ident = "MSI MS-7253",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"),
+                       DMI_MATCH(DMI_BOARD_NAME, "MS-7253"),
+                       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies, LTD"),
+               },
+       },
 
        /* Now for the blacklist.. */
 
@@ -282,9 +292,6 @@ static void add_resources(struct pci_root_info *info)
        int i;
        struct resource *res, *root, *conflict;
 
-       if (!pci_use_crs)
-               return;
-
        coalesce_windows(info, IORESOURCE_MEM);
        coalesce_windows(info, IORESOURCE_IO);
 
@@ -336,8 +343,13 @@ get_current_resources(struct acpi_device *device, int busnum,
        acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource,
                                &info);
 
-       add_resources(&info);
-       return;
+       if (pci_use_crs) {
+               add_resources(&info);
+
+               return;
+       }
+
+       kfree(info.name);
 
 name_alloc_fail:
        kfree(info.res);
index 12eb07bfb267ee6747abbd4192fab3f9f5c1f44e..4172af8ceeb363d06912af15bf89e8508752b794 100644 (file)
@@ -1141,7 +1141,9 @@ asmlinkage void __init xen_start_kernel(void)
 
        /* Prevent unwanted bits from being set in PTEs. */
        __supported_pte_mask &= ~_PAGE_GLOBAL;
+#if 0
        if (!xen_initial_domain())
+#endif
                __supported_pte_mask &= ~(_PAGE_PWT | _PAGE_PCD);
 
        __supported_pte_mask |= _PAGE_IOMAP;
@@ -1204,10 +1206,6 @@ asmlinkage void __init xen_start_kernel(void)
 
        pgd = (pgd_t *)xen_start_info->pt_base;
 
-       if (!xen_initial_domain())
-               __supported_pte_mask &= ~(_PAGE_PWT | _PAGE_PCD);
-
-       __supported_pte_mask |= _PAGE_IOMAP;
        /* Don't do the full vcpu_info placement stuff until we have a
           possible map and a non-dummy shared_info. */
        per_cpu(xen_vcpu, 0) = &HYPERVISOR_shared_info->vcpu_info[0];
index 58a0e46c404dc417c9af3cf9a08856096ebc99cf..95c1cf60c6694a0ff569e47012b9b30f2a73c97a 100644 (file)
@@ -415,13 +415,13 @@ static pteval_t iomap_pte(pteval_t val)
 static pteval_t xen_pte_val(pte_t pte)
 {
        pteval_t pteval = pte.pte;
-
+#if 0
        /* If this is a WC pte, convert back from Xen WC to Linux WC */
        if ((pteval & (_PAGE_PAT | _PAGE_PCD | _PAGE_PWT)) == _PAGE_PAT) {
                WARN_ON(!pat_enabled);
                pteval = (pteval & ~_PAGE_PAT) | _PAGE_PWT;
        }
-
+#endif
        if (xen_initial_domain() && (pteval & _PAGE_IOMAP))
                return pteval;
 
@@ -463,7 +463,7 @@ void xen_set_pat(u64 pat)
 static pte_t xen_make_pte(pteval_t pte)
 {
        phys_addr_t addr = (pte & PTE_PFN_MASK);
-
+#if 0
        /* If Linux is trying to set a WC pte, then map to the Xen WC.
         * If _PAGE_PAT is set, then it probably means it is really
         * _PAGE_PSE, so avoid fiddling with the PAT mapping and hope
@@ -476,7 +476,7 @@ static pte_t xen_make_pte(pteval_t pte)
                if ((pte & (_PAGE_PCD | _PAGE_PWT)) == _PAGE_PWT)
                        pte = (pte & ~(_PAGE_PCD | _PAGE_PWT)) | _PAGE_PAT;
        }
-
+#endif
        /*
         * Unprivileged domains are allowed to do IOMAPpings for
         * PCI passthrough, but not map ISA space.  The ISA
index bd8ae788f689129a1ae6cc75c4687655031a868d..e507cfbd044e6b864f09baf10c192aa53689b087 100644 (file)
@@ -2,7 +2,7 @@
  * ldm - Support for Windows Logical Disk Manager (Dynamic Disks)
  *
  * Copyright (C) 2001,2002 Richard Russon <ldm@flatcap.org>
- * Copyright (c) 2001-2007 Anton Altaparmakov
+ * Copyright (c) 2001-2012 Anton Altaparmakov
  * Copyright (C) 2001,2002 Jakob Kemi <jakob.kemi@telia.com>
  *
  * Documentation is available at http://www.linux-ntfs.org/doku.php?id=downloads 
@@ -1341,20 +1341,17 @@ found:
                ldm_error("REC value (%d) exceeds NUM value (%d)", rec, f->num);
                return false;
        }
-
        if (f->map & (1 << rec)) {
                ldm_error ("Duplicate VBLK, part %d.", rec);
                f->map &= 0x7F;                 /* Mark the group as broken */
                return false;
        }
-
        f->map |= (1 << rec);
-
+       if (!rec)
+               memcpy(f->data, data, VBLK_SIZE_HEAD);
        data += VBLK_SIZE_HEAD;
        size -= VBLK_SIZE_HEAD;
-
-       memcpy (f->data+rec*(size-VBLK_SIZE_HEAD)+VBLK_SIZE_HEAD, data, size);
-
+       memcpy(f->data + VBLK_SIZE_HEAD + rec * size, data, size);
        return true;
 }
 
index 800163c8c2e7a046a4aa1219e6d7c876be0be19b..a058842f14fdf54b92b495f01c34a02ed2b74bcc 100644 (file)
@@ -80,6 +80,7 @@ static void bcma_pmu_resources_init(struct bcma_drv_cc *cc)
                min_msk = 0x200D;
                max_msk = 0xFFFF;
                break;
+       case 0x4331:
        case 43224:
        case 43225:
                break;
index b8379b90d045c85b1581e3b97b9f4bcb42aff2e1..7e138ec21357bb460e69f5aaed01d09307605709 100644 (file)
@@ -61,7 +61,7 @@ static struct bus_type bcma_bus_type = {
        .dev_attrs      = bcma_device_attrs,
 };
 
-static struct bcma_device *bcma_find_core(struct bcma_bus *bus, u16 coreid)
+struct bcma_device *bcma_find_core(struct bcma_bus *bus, u16 coreid)
 {
        struct bcma_device *core;
 
@@ -71,6 +71,7 @@ static struct bcma_device *bcma_find_core(struct bcma_bus *bus, u16 coreid)
        }
        return NULL;
 }
+EXPORT_SYMBOL_GPL(bcma_find_core);
 
 static void bcma_release_core_dev(struct device *dev)
 {
index ca7752510d5b3a943bb2b5feb28a98ae54708318..cdcf75c0954febe06c4ac04f030568470284c160 100644 (file)
@@ -2,6 +2,8 @@
  * Broadcom specific AMBA
  * SPROM reading
  *
+ * Copyright 2011, 2012, Hauke Mehrtens <hauke@hauke-m.de>
+ *
  * Licensed under the GNU/GPL. See COPYING for details.
  */
 
 #include <linux/dma-mapping.h>
 #include <linux/slab.h>
 
+static int(*get_fallback_sprom)(struct bcma_bus *dev, struct ssb_sprom *out);
+
+/**
+ * bcma_arch_register_fallback_sprom - Registers a method providing a
+ * fallback SPROM if no SPROM is found.
+ *
+ * @sprom_callback: The callback function.
+ *
+ * With this function the architecture implementation may register a
+ * callback handler which fills the SPROM data structure. The fallback is
+ * used for PCI based BCMA devices, where no valid SPROM can be found
+ * in the shadow registers and to provide the SPROM for SoCs where BCMA is
+ * to controll the system bus.
+ *
+ * This function is useful for weird architectures that have a half-assed
+ * BCMA device hardwired to their PCI bus.
+ *
+ * This function is available for architecture code, only. So it is not
+ * exported.
+ */
+int bcma_arch_register_fallback_sprom(int (*sprom_callback)(struct bcma_bus *bus,
+                                    struct ssb_sprom *out))
+{
+       if (get_fallback_sprom)
+               return -EEXIST;
+       get_fallback_sprom = sprom_callback;
+
+       return 0;
+}
+
+static int bcma_fill_sprom_with_fallback(struct bcma_bus *bus,
+                                        struct ssb_sprom *out)
+{
+       int err;
+
+       if (!get_fallback_sprom) {
+               err = -ENOENT;
+               goto fail;
+       }
+
+       err = get_fallback_sprom(bus, out);
+       if (err)
+               goto fail;
+
+       pr_debug("Using SPROM revision %d provided by"
+                " platform.\n", bus->sprom.revision);
+       return 0;
+fail:
+       pr_warn("Using fallback SPROM failed (err %d)\n", err);
+       return err;
+}
+
 /**************************************************
  * R/W ops.
  **************************************************/
@@ -246,23 +300,128 @@ static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
             SSB_SROM8_FEM_ANTSWLUT_SHIFT);
 }
 
+/*
+ * Indicates the presence of external SPROM.
+ */
+static bool bcma_sprom_ext_available(struct bcma_bus *bus)
+{
+       u32 chip_status;
+       u32 srom_control;
+       u32 present_mask;
+
+       if (bus->drv_cc.core->id.rev >= 31) {
+               if (!(bus->drv_cc.capabilities & BCMA_CC_CAP_SPROM))
+                       return false;
+
+               srom_control = bcma_read32(bus->drv_cc.core,
+                                          BCMA_CC_SROM_CONTROL);
+               return srom_control & BCMA_CC_SROM_CONTROL_PRESENT;
+       }
+
+       /* older chipcommon revisions use chip status register */
+       chip_status = bcma_read32(bus->drv_cc.core, BCMA_CC_CHIPSTAT);
+       switch (bus->chipinfo.id) {
+       case 0x4313:
+               present_mask = BCMA_CC_CHIPST_4313_SPROM_PRESENT;
+               break;
+
+       case 0x4331:
+               present_mask = BCMA_CC_CHIPST_4331_SPROM_PRESENT;
+               break;
+
+       default:
+               return true;
+       }
+
+       return chip_status & present_mask;
+}
+
+/*
+ * Indicates that on-chip OTP memory is present and enabled.
+ */
+static bool bcma_sprom_onchip_available(struct bcma_bus *bus)
+{
+       u32 chip_status;
+       u32 otpsize = 0;
+       bool present;
+
+       chip_status = bcma_read32(bus->drv_cc.core, BCMA_CC_CHIPSTAT);
+       switch (bus->chipinfo.id) {
+       case 0x4313:
+               present = chip_status & BCMA_CC_CHIPST_4313_OTP_PRESENT;
+               break;
+
+       case 0x4331:
+               present = chip_status & BCMA_CC_CHIPST_4331_OTP_PRESENT;
+               break;
+
+       case 43224:
+       case 43225:
+               /* for these chips OTP is always available */
+               present = true;
+               break;
+
+       default:
+               present = false;
+               break;
+       }
+
+       if (present) {
+               otpsize = bus->drv_cc.capabilities & BCMA_CC_CAP_OTPS;
+               otpsize >>= BCMA_CC_CAP_OTPS_SHIFT;
+       }
+
+       return otpsize != 0;
+}
+
+/*
+ * Verify OTP is filled and determine the byte
+ * offset where SPROM data is located.
+ *
+ * On error, returns 0; byte offset otherwise.
+ */
+static int bcma_sprom_onchip_offset(struct bcma_bus *bus)
+{
+       struct bcma_device *cc = bus->drv_cc.core;
+       u32 offset;
+
+       /* verify OTP status */
+       if ((bcma_read32(cc, BCMA_CC_OTPS) & BCMA_CC_OTPS_GU_PROG_HW) == 0)
+               return 0;
+
+       /* obtain bit offset from otplayout register */
+       offset = (bcma_read32(cc, BCMA_CC_OTPL) & BCMA_CC_OTPL_GURGN_OFFSET);
+       return BCMA_CC_SPROM + (offset >> 3);
+}
+
 int bcma_sprom_get(struct bcma_bus *bus)
 {
-       u16 offset;
+       u16 offset = BCMA_CC_SPROM;
        u16 *sprom;
-       u32 sromctrl;
        int err = 0;
 
        if (!bus->drv_cc.core)
                return -EOPNOTSUPP;
 
-       if (!(bus->drv_cc.capabilities & BCMA_CC_CAP_SPROM))
-               return -ENOENT;
-
-       if (bus->drv_cc.core->id.rev >= 32) {
-               sromctrl = bcma_read32(bus->drv_cc.core, BCMA_CC_SROM_CONTROL);
-               if (!(sromctrl & BCMA_CC_SROM_CONTROL_PRESENT))
-                       return -ENOENT;
+       if (!bcma_sprom_ext_available(bus)) {
+               /*
+                * External SPROM takes precedence so check
+                * on-chip OTP only when no external SPROM
+                * is present.
+                */
+               if (bcma_sprom_onchip_available(bus)) {
+                       /* determine offset */
+                       offset = bcma_sprom_onchip_offset(bus);
+               }
+               if (!offset) {
+                       /*
+                        * Maybe there is no SPROM on the device?
+                        * Now we ask the arch code if there is some sprom
+                        * available for this device in some other storage.
+                        */
+                       err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
+                       return err;
+               }
        }
 
        sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
@@ -273,11 +432,6 @@ int bcma_sprom_get(struct bcma_bus *bus)
        if (bus->chipinfo.id == 0x4331)
                bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
 
-       /* Most cards have SPROM moved by additional offset 0x30 (48 dwords).
-        * According to brcm80211 this applies to cards with PCIe rev >= 6
-        * TODO: understand this condition and use it */
-       offset = (bus->chipinfo.id == 0x4331) ? BCMA_CC_SPROM :
-               BCMA_CC_SPROM_PCIE6;
        pr_debug("SPROM offset 0x%x\n", offset);
        bcma_sprom_read(bus, offset, sprom);
 
index 9baf11e8636205c413bd5c00498baab628657b44..744f078f4dd8311caed330939afbcdc29c2da913 100644 (file)
@@ -3832,7 +3832,7 @@ static int __floppy_read_block_0(struct block_device *bdev)
        bio.bi_size = size;
        bio.bi_bdev = bdev;
        bio.bi_sector = 0;
-       bio.bi_flags = BIO_QUIET;
+       bio.bi_flags = (1 << BIO_QUIET);
        init_completion(&complete);
        bio.bi_private = &complete;
        bio.bi_end_io = floppy_rb0_complete;
index 07f14d10ea49ef33ed73d6d9c9b84b32093fb08b..48442476ec005415ec0d51c79c48e305ed31fb69 100644 (file)
@@ -65,12 +65,14 @@ static struct usb_device_id ath3k_table[] = {
        { USB_DEVICE(0x0CF3, 0x3002) },
        { USB_DEVICE(0x13d3, 0x3304) },
        { USB_DEVICE(0x0930, 0x0215) },
+       { USB_DEVICE(0x0489, 0xE03D) },
 
        /* Atheros AR9285 Malbec with sflash firmware */
        { USB_DEVICE(0x03F0, 0x311D) },
 
        /* Atheros AR3012 with sflash firmware*/
        { USB_DEVICE(0x0CF3, 0x3004) },
+       { USB_DEVICE(0x13d3, 0x3375) },
 
        /* Atheros AR5BBU12 with sflash firmware */
        { USB_DEVICE(0x0489, 0xE02C) },
@@ -87,6 +89,7 @@ static struct usb_device_id ath3k_blist_tbl[] = {
 
        /* Atheros AR3012 with sflash firmware*/
        { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
 
        { }     /* Terminating entry */
 };
index a323baee51b03493facfb5def8708127e42d64ba..b8ac1c549a1c75507700c8f608f844233314ea7e 100644 (file)
@@ -411,7 +411,7 @@ unlock:
 
 static int bfusb_open(struct hci_dev *hdev)
 {
-       struct bfusb_data *data = hdev->driver_data;
+       struct bfusb_data *data = hci_get_drvdata(hdev);
        unsigned long flags;
        int i, err;
 
@@ -437,7 +437,7 @@ static int bfusb_open(struct hci_dev *hdev)
 
 static int bfusb_flush(struct hci_dev *hdev)
 {
-       struct bfusb_data *data = hdev->driver_data;
+       struct bfusb_data *data = hci_get_drvdata(hdev);
 
        BT_DBG("hdev %p bfusb %p", hdev, data);
 
@@ -448,7 +448,7 @@ static int bfusb_flush(struct hci_dev *hdev)
 
 static int bfusb_close(struct hci_dev *hdev)
 {
-       struct bfusb_data *data = hdev->driver_data;
+       struct bfusb_data *data = hci_get_drvdata(hdev);
        unsigned long flags;
 
        BT_DBG("hdev %p bfusb %p", hdev, data);
@@ -483,7 +483,7 @@ static int bfusb_send_frame(struct sk_buff *skb)
        if (!test_bit(HCI_RUNNING, &hdev->flags))
                return -EBUSY;
 
-       data = hdev->driver_data;
+       data = hci_get_drvdata(hdev);
 
        switch (bt_cb(skb)->pkt_type) {
        case HCI_COMMAND_PKT:
@@ -544,15 +544,6 @@ static int bfusb_send_frame(struct sk_buff *skb)
        return 0;
 }
 
-static void bfusb_destruct(struct hci_dev *hdev)
-{
-       struct bfusb_data *data = hdev->driver_data;
-
-       BT_DBG("hdev %p bfusb %p", hdev, data);
-
-       kfree(data);
-}
-
 static int bfusb_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
 {
        return -ENOIOCTLCMD;
@@ -705,18 +696,15 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
        data->hdev = hdev;
 
        hdev->bus = HCI_USB;
-       hdev->driver_data = data;
+       hci_set_drvdata(hdev, data);
        SET_HCIDEV_DEV(hdev, &intf->dev);
 
        hdev->open     = bfusb_open;
        hdev->close    = bfusb_close;
        hdev->flush    = bfusb_flush;
        hdev->send     = bfusb_send_frame;
-       hdev->destruct = bfusb_destruct;
        hdev->ioctl    = bfusb_ioctl;
 
-       hdev->owner = THIS_MODULE;
-
        if (hci_register_dev(hdev) < 0) {
                BT_ERR("Can't register HCI device");
                hci_free_dev(hdev);
@@ -753,6 +741,7 @@ static void bfusb_disconnect(struct usb_interface *intf)
 
        hci_unregister_dev(hdev);
        hci_free_dev(hdev);
+       kfree(data);
 }
 
 static struct usb_driver bfusb_driver = {
index c6a0c6103743838fef1dd30157681e9d916115c7..1fcd92380356bb70571a573cb105778d06712237 100644 (file)
@@ -561,7 +561,7 @@ static irqreturn_t bluecard_interrupt(int irq, void *dev_inst)
 
 static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud)
 {
-       bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
+       bluecard_info_t *info = hci_get_drvdata(hdev);
        struct sk_buff *skb;
 
        /* Ericsson baud rate command */
@@ -609,7 +609,7 @@ static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud)
 
 static int bluecard_hci_flush(struct hci_dev *hdev)
 {
-       bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
+       bluecard_info_t *info = hci_get_drvdata(hdev);
 
        /* Drop TX queue */
        skb_queue_purge(&(info->txq));
@@ -620,7 +620,7 @@ static int bluecard_hci_flush(struct hci_dev *hdev)
 
 static int bluecard_hci_open(struct hci_dev *hdev)
 {
-       bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
+       bluecard_info_t *info = hci_get_drvdata(hdev);
        unsigned int iobase = info->p_dev->resource[0]->start;
 
        if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state)))
@@ -640,7 +640,7 @@ static int bluecard_hci_open(struct hci_dev *hdev)
 
 static int bluecard_hci_close(struct hci_dev *hdev)
 {
-       bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
+       bluecard_info_t *info = hci_get_drvdata(hdev);
        unsigned int iobase = info->p_dev->resource[0]->start;
 
        if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
@@ -667,7 +667,7 @@ static int bluecard_hci_send_frame(struct sk_buff *skb)
                return -ENODEV;
        }
 
-       info = (bluecard_info_t *)(hdev->driver_data);
+       info = hci_get_drvdata(hdev);
 
        switch (bt_cb(skb)->pkt_type) {
        case HCI_COMMAND_PKT:
@@ -691,11 +691,6 @@ static int bluecard_hci_send_frame(struct sk_buff *skb)
 }
 
 
-static void bluecard_hci_destruct(struct hci_dev *hdev)
-{
-}
-
-
 static int bluecard_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
 {
        return -ENOIOCTLCMD;
@@ -734,18 +729,15 @@ static int bluecard_open(bluecard_info_t *info)
        info->hdev = hdev;
 
        hdev->bus = HCI_PCCARD;
-       hdev->driver_data = info;
+       hci_set_drvdata(hdev, info);
        SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
 
        hdev->open     = bluecard_hci_open;
        hdev->close    = bluecard_hci_close;
        hdev->flush    = bluecard_hci_flush;
        hdev->send     = bluecard_hci_send_frame;
-       hdev->destruct = bluecard_hci_destruct;
        hdev->ioctl    = bluecard_hci_ioctl;
 
-       hdev->owner = THIS_MODULE;
-
        id = inb(iobase + 0x30);
 
        if ((id & 0x0f) == 0x02)
index 62831603de5e91c7f4bd44774fe37647cb808795..d894340a7601ee789eff108b1dddd29e173b157f 100644 (file)
@@ -66,7 +66,7 @@ struct hci_vendor_hdr {
 
 static int bpa10x_recv(struct hci_dev *hdev, int queue, void *buf, int count)
 {
-       struct bpa10x_data *data = hdev->driver_data;
+       struct bpa10x_data *data = hci_get_drvdata(hdev);
 
        BT_DBG("%s queue %d buffer %p count %d", hdev->name,
                                                        queue, buf, count);
@@ -189,7 +189,7 @@ done:
 static void bpa10x_rx_complete(struct urb *urb)
 {
        struct hci_dev *hdev = urb->context;
-       struct bpa10x_data *data = hdev->driver_data;
+       struct bpa10x_data *data = hci_get_drvdata(hdev);
        int err;
 
        BT_DBG("%s urb %p status %d count %d", hdev->name,
@@ -219,7 +219,7 @@ static void bpa10x_rx_complete(struct urb *urb)
 
 static inline int bpa10x_submit_intr_urb(struct hci_dev *hdev)
 {
-       struct bpa10x_data *data = hdev->driver_data;
+       struct bpa10x_data *data = hci_get_drvdata(hdev);
        struct urb *urb;
        unsigned char *buf;
        unsigned int pipe;
@@ -260,7 +260,7 @@ static inline int bpa10x_submit_intr_urb(struct hci_dev *hdev)
 
 static inline int bpa10x_submit_bulk_urb(struct hci_dev *hdev)
 {
-       struct bpa10x_data *data = hdev->driver_data;
+       struct bpa10x_data *data = hci_get_drvdata(hdev);
        struct urb *urb;
        unsigned char *buf;
        unsigned int pipe;
@@ -301,7 +301,7 @@ static inline int bpa10x_submit_bulk_urb(struct hci_dev *hdev)
 
 static int bpa10x_open(struct hci_dev *hdev)
 {
-       struct bpa10x_data *data = hdev->driver_data;
+       struct bpa10x_data *data = hci_get_drvdata(hdev);
        int err;
 
        BT_DBG("%s", hdev->name);
@@ -329,7 +329,7 @@ error:
 
 static int bpa10x_close(struct hci_dev *hdev)
 {
-       struct bpa10x_data *data = hdev->driver_data;
+       struct bpa10x_data *data = hci_get_drvdata(hdev);
 
        BT_DBG("%s", hdev->name);
 
@@ -343,7 +343,7 @@ static int bpa10x_close(struct hci_dev *hdev)
 
 static int bpa10x_flush(struct hci_dev *hdev)
 {
-       struct bpa10x_data *data = hdev->driver_data;
+       struct bpa10x_data *data = hci_get_drvdata(hdev);
 
        BT_DBG("%s", hdev->name);
 
@@ -355,7 +355,7 @@ static int bpa10x_flush(struct hci_dev *hdev)
 static int bpa10x_send_frame(struct sk_buff *skb)
 {
        struct hci_dev *hdev = (struct hci_dev *) skb->dev;
-       struct bpa10x_data *data = hdev->driver_data;
+       struct bpa10x_data *data = hci_get_drvdata(hdev);
        struct usb_ctrlrequest *dr;
        struct urb *urb;
        unsigned int pipe;
@@ -432,17 +432,6 @@ static int bpa10x_send_frame(struct sk_buff *skb)
        return 0;
 }
 
-static void bpa10x_destruct(struct hci_dev *hdev)
-{
-       struct bpa10x_data *data = hdev->driver_data;
-
-       BT_DBG("%s", hdev->name);
-
-       kfree_skb(data->rx_skb[0]);
-       kfree_skb(data->rx_skb[1]);
-       kfree(data);
-}
-
 static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
        struct bpa10x_data *data;
@@ -470,7 +459,7 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *
        }
 
        hdev->bus = HCI_USB;
-       hdev->driver_data = data;
+       hci_set_drvdata(hdev, data);
 
        data->hdev = hdev;
 
@@ -480,9 +469,6 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *
        hdev->close    = bpa10x_close;
        hdev->flush    = bpa10x_flush;
        hdev->send     = bpa10x_send_frame;
-       hdev->destruct = bpa10x_destruct;
-
-       hdev->owner = THIS_MODULE;
 
        set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
 
@@ -512,6 +498,9 @@ static void bpa10x_disconnect(struct usb_interface *intf)
        hci_unregister_dev(data->hdev);
 
        hci_free_dev(data->hdev);
+       kfree_skb(data->rx_skb[0]);
+       kfree_skb(data->rx_skb[1]);
+       kfree(data);
 }
 
 static struct usb_driver bpa10x_driver = {
index 0c97e5d514b635b0574d3832d6b593263146f56e..9c09d6f05dc94e0abfbe0247bb514b203a51f819 100644 (file)
@@ -389,7 +389,7 @@ static irqreturn_t bt3c_interrupt(int irq, void *dev_inst)
 
 static int bt3c_hci_flush(struct hci_dev *hdev)
 {
-       bt3c_info_t *info = (bt3c_info_t *)(hdev->driver_data);
+       bt3c_info_t *info = hci_get_drvdata(hdev);
 
        /* Drop TX queue */
        skb_queue_purge(&(info->txq));
@@ -428,7 +428,7 @@ static int bt3c_hci_send_frame(struct sk_buff *skb)
                return -ENODEV;
        }
 
-       info = (bt3c_info_t *) (hdev->driver_data);
+       info = hci_get_drvdata(hdev);
 
        switch (bt_cb(skb)->pkt_type) {
        case HCI_COMMAND_PKT:
@@ -456,11 +456,6 @@ static int bt3c_hci_send_frame(struct sk_buff *skb)
 }
 
 
-static void bt3c_hci_destruct(struct hci_dev *hdev)
-{
-}
-
-
 static int bt3c_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
 {
        return -ENOIOCTLCMD;
@@ -580,18 +575,15 @@ static int bt3c_open(bt3c_info_t *info)
        info->hdev = hdev;
 
        hdev->bus = HCI_PCCARD;
-       hdev->driver_data = info;
+       hci_set_drvdata(hdev, info);
        SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
 
        hdev->open     = bt3c_hci_open;
        hdev->close    = bt3c_hci_close;
        hdev->flush    = bt3c_hci_flush;
        hdev->send     = bt3c_hci_send_frame;
-       hdev->destruct = bt3c_hci_destruct;
        hdev->ioctl    = bt3c_hci_ioctl;
 
-       hdev->owner = THIS_MODULE;
-
        /* Load firmware */
        err = request_firmware(&firmware, "BT3CPCC.bin", &info->p_dev->dev);
        if (err < 0) {
index 8ecf4c6c28740243979920dd98ea7bdc638e5172..6c20bbb54b71a8e51038f4ad84a59157d489dde0 100644 (file)
@@ -384,7 +384,7 @@ static const struct file_operations btmrvl_txdnldready_fops = {
 
 void btmrvl_debugfs_init(struct hci_dev *hdev)
 {
-       struct btmrvl_private *priv = hdev->driver_data;
+       struct btmrvl_private *priv = hci_get_drvdata(hdev);
        struct btmrvl_debugfs_data *dbg;
 
        if (!hdev->debugfs)
@@ -401,36 +401,34 @@ void btmrvl_debugfs_init(struct hci_dev *hdev)
        dbg->config_dir = debugfs_create_dir("config", hdev->debugfs);
 
        dbg->psmode = debugfs_create_file("psmode", 0644, dbg->config_dir,
-                               hdev->driver_data, &btmrvl_psmode_fops);
+                                         priv, &btmrvl_psmode_fops);
        dbg->pscmd = debugfs_create_file("pscmd", 0644, dbg->config_dir,
-                               hdev->driver_data, &btmrvl_pscmd_fops);
+                                        priv, &btmrvl_pscmd_fops);
        dbg->gpiogap = debugfs_create_file("gpiogap", 0644, dbg->config_dir,
-                               hdev->driver_data, &btmrvl_gpiogap_fops);
+                                          priv, &btmrvl_gpiogap_fops);
        dbg->hsmode =  debugfs_create_file("hsmode", 0644, dbg->config_dir,
-                               hdev->driver_data, &btmrvl_hsmode_fops);
+                                          priv, &btmrvl_hsmode_fops);
        dbg->hscmd = debugfs_create_file("hscmd", 0644, dbg->config_dir,
-                               hdev->driver_data, &btmrvl_hscmd_fops);
+                                        priv, &btmrvl_hscmd_fops);
        dbg->hscfgcmd = debugfs_create_file("hscfgcmd", 0644, dbg->config_dir,
-                               hdev->driver_data, &btmrvl_hscfgcmd_fops);
+                                           priv, &btmrvl_hscfgcmd_fops);
 
        dbg->status_dir = debugfs_create_dir("status", hdev->debugfs);
        dbg->curpsmode = debugfs_create_file("curpsmode", 0444,
-                                               dbg->status_dir,
-                                               hdev->driver_data,
-                                               &btmrvl_curpsmode_fops);
+                                            dbg->status_dir, priv,
+                                            &btmrvl_curpsmode_fops);
        dbg->psstate = debugfs_create_file("psstate", 0444, dbg->status_dir,
-                               hdev->driver_data, &btmrvl_psstate_fops);
+                                          priv, &btmrvl_psstate_fops);
        dbg->hsstate = debugfs_create_file("hsstate", 0444, dbg->status_dir,
-                               hdev->driver_data, &btmrvl_hsstate_fops);
+                                          priv, &btmrvl_hsstate_fops);
        dbg->txdnldready = debugfs_create_file("txdnldready", 0444,
-                                               dbg->status_dir,
-                                               hdev->driver_data,
-                                               &btmrvl_txdnldready_fops);
+                                              dbg->status_dir, priv,
+                                              &btmrvl_txdnldready_fops);
 }
 
 void btmrvl_debugfs_remove(struct hci_dev *hdev)
 {
-       struct btmrvl_private *priv = hdev->driver_data;
+       struct btmrvl_private *priv = hci_get_drvdata(hdev);
        struct btmrvl_debugfs_data *dbg = priv->debugfs_data;
 
        if (!dbg)
index 6c3defa508454e1d76937abf9235b07fc6e880a8..d1209adc882dd00ad39811f44a4fa2c076274ee9 100644 (file)
@@ -387,10 +387,6 @@ static int btmrvl_ioctl(struct hci_dev *hdev,
        return -ENOIOCTLCMD;
 }
 
-static void btmrvl_destruct(struct hci_dev *hdev)
-{
-}
-
 static int btmrvl_send_frame(struct sk_buff *skb)
 {
        struct hci_dev *hdev = (struct hci_dev *) skb->dev;
@@ -398,12 +394,13 @@ static int btmrvl_send_frame(struct sk_buff *skb)
 
        BT_DBG("type=%d, len=%d", skb->pkt_type, skb->len);
 
-       if (!hdev || !hdev->driver_data) {
+       if (!hdev) {
                BT_ERR("Frame for unknown HCI device");
                return -ENODEV;
        }
 
-       priv = (struct btmrvl_private *) hdev->driver_data;
+       priv = hci_get_drvdata(hdev);
+
        if (!test_bit(HCI_RUNNING, &hdev->flags)) {
                BT_ERR("Failed testing HCI_RUNING, flags=%lx", hdev->flags);
                print_hex_dump_bytes("data: ", DUMP_PREFIX_OFFSET,
@@ -434,7 +431,7 @@ static int btmrvl_send_frame(struct sk_buff *skb)
 
 static int btmrvl_flush(struct hci_dev *hdev)
 {
-       struct btmrvl_private *priv = hdev->driver_data;
+       struct btmrvl_private *priv = hci_get_drvdata(hdev);
 
        skb_queue_purge(&priv->adapter->tx_queue);
 
@@ -443,7 +440,7 @@ static int btmrvl_flush(struct hci_dev *hdev)
 
 static int btmrvl_close(struct hci_dev *hdev)
 {
-       struct btmrvl_private *priv = hdev->driver_data;
+       struct btmrvl_private *priv = hci_get_drvdata(hdev);
 
        if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
                return 0;
@@ -546,16 +543,14 @@ int btmrvl_register_hdev(struct btmrvl_private *priv)
        }
 
        priv->btmrvl_dev.hcidev = hdev;
-       hdev->driver_data = priv;
+       hci_set_drvdata(hdev, priv);
 
        hdev->bus = HCI_SDIO;
        hdev->open = btmrvl_open;
        hdev->close = btmrvl_close;
        hdev->flush = btmrvl_flush;
        hdev->send = btmrvl_send_frame;
-       hdev->destruct = btmrvl_destruct;
        hdev->ioctl = btmrvl_ioctl;
-       hdev->owner = THIS_MODULE;
 
        btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ);
 
index 792e32d29a1de981c3bf84ad15a4e7899a94ec5a..e10ea03470510f876bd3b09ef572630c4ef83e29 100644 (file)
@@ -189,7 +189,7 @@ static void btsdio_interrupt(struct sdio_func *func)
 
 static int btsdio_open(struct hci_dev *hdev)
 {
-       struct btsdio_data *data = hdev->driver_data;
+       struct btsdio_data *data = hci_get_drvdata(hdev);
        int err;
 
        BT_DBG("%s", hdev->name);
@@ -225,7 +225,7 @@ release:
 
 static int btsdio_close(struct hci_dev *hdev)
 {
-       struct btsdio_data *data = hdev->driver_data;
+       struct btsdio_data *data = hci_get_drvdata(hdev);
 
        BT_DBG("%s", hdev->name);
 
@@ -246,7 +246,7 @@ static int btsdio_close(struct hci_dev *hdev)
 
 static int btsdio_flush(struct hci_dev *hdev)
 {
-       struct btsdio_data *data = hdev->driver_data;
+       struct btsdio_data *data = hci_get_drvdata(hdev);
 
        BT_DBG("%s", hdev->name);
 
@@ -258,7 +258,7 @@ static int btsdio_flush(struct hci_dev *hdev)
 static int btsdio_send_frame(struct sk_buff *skb)
 {
        struct hci_dev *hdev = (struct hci_dev *) skb->dev;
-       struct btsdio_data *data = hdev->driver_data;
+       struct btsdio_data *data = hci_get_drvdata(hdev);
 
        BT_DBG("%s", hdev->name);
 
@@ -289,15 +289,6 @@ static int btsdio_send_frame(struct sk_buff *skb)
        return 0;
 }
 
-static void btsdio_destruct(struct hci_dev *hdev)
-{
-       struct btsdio_data *data = hdev->driver_data;
-
-       BT_DBG("%s", hdev->name);
-
-       kfree(data);
-}
-
 static int btsdio_probe(struct sdio_func *func,
                                const struct sdio_device_id *id)
 {
@@ -330,7 +321,7 @@ static int btsdio_probe(struct sdio_func *func,
        }
 
        hdev->bus = HCI_SDIO;
-       hdev->driver_data = data;
+       hci_set_drvdata(hdev, data);
 
        if (id->class == SDIO_CLASS_BT_AMP)
                hdev->dev_type = HCI_AMP;
@@ -345,9 +336,6 @@ static int btsdio_probe(struct sdio_func *func,
        hdev->close    = btsdio_close;
        hdev->flush    = btsdio_flush;
        hdev->send     = btsdio_send_frame;
-       hdev->destruct = btsdio_destruct;
-
-       hdev->owner = THIS_MODULE;
 
        err = hci_register_dev(hdev);
        if (err < 0) {
@@ -378,6 +366,7 @@ static void btsdio_remove(struct sdio_func *func)
        hci_unregister_dev(hdev);
 
        hci_free_dev(hdev);
+       kfree(data);
 }
 
 static struct sdio_driver btsdio_driver = {
index 200b3a2877d69c43754d6210bc0ad2feb5be81c4..194224d07f7c391cbdb86cc025d27f6386a88f3e 100644 (file)
@@ -397,7 +397,7 @@ static void btuart_change_speed(btuart_info_t *info, unsigned int speed)
 
 static int btuart_hci_flush(struct hci_dev *hdev)
 {
-       btuart_info_t *info = (btuart_info_t *)(hdev->driver_data);
+       btuart_info_t *info = hci_get_drvdata(hdev);
 
        /* Drop TX queue */
        skb_queue_purge(&(info->txq));
@@ -435,7 +435,7 @@ static int btuart_hci_send_frame(struct sk_buff *skb)
                return -ENODEV;
        }
 
-       info = (btuart_info_t *)(hdev->driver_data);
+       info = hci_get_drvdata(hdev);
 
        switch (bt_cb(skb)->pkt_type) {
        case HCI_COMMAND_PKT:
@@ -459,11 +459,6 @@ static int btuart_hci_send_frame(struct sk_buff *skb)
 }
 
 
-static void btuart_hci_destruct(struct hci_dev *hdev)
-{
-}
-
-
 static int btuart_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
 {
        return -ENOIOCTLCMD;
@@ -498,18 +493,15 @@ static int btuart_open(btuart_info_t *info)
        info->hdev = hdev;
 
        hdev->bus = HCI_PCCARD;
-       hdev->driver_data = info;
+       hci_set_drvdata(hdev, info);
        SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
 
        hdev->open     = btuart_hci_open;
        hdev->close    = btuart_hci_close;
        hdev->flush    = btuart_hci_flush;
        hdev->send     = btuart_hci_send_frame;
-       hdev->destruct = btuart_hci_destruct;
        hdev->ioctl    = btuart_hci_ioctl;
 
-       hdev->owner = THIS_MODULE;
-
        spin_lock_irqsave(&(info->lock), flags);
 
        /* Reset UART */
index 789c9b579aea5bac7e0b2abfe3d14b377917a9c4..480cad9200481fb0ad2eb9a91c5b9b55d2dea5c5 100644 (file)
@@ -102,6 +102,7 @@ static struct usb_device_id btusb_table[] = {
 
        /* Broadcom BCM20702A0 */
        { USB_DEVICE(0x0a5c, 0x21e3) },
+       { USB_DEVICE(0x0a5c, 0x21e6) },
        { USB_DEVICE(0x0a5c, 0x21f3) },
        { USB_DEVICE(0x413c, 0x8197) },
 
@@ -121,12 +122,14 @@ static struct usb_device_id blacklist_table[] = {
        { USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE },
        { USB_DEVICE(0x13d3, 0x3304), .driver_info = BTUSB_IGNORE },
        { USB_DEVICE(0x0930, 0x0215), .driver_info = BTUSB_IGNORE },
+       { USB_DEVICE(0x0489, 0xe03d), .driver_info = BTUSB_IGNORE },
 
        /* Atheros AR9285 Malbec with sflash firmware */
        { USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE },
 
        /* Atheros 3012 with sflash firmware */
        { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
 
        /* Atheros AR5BBU12 with sflash firmware */
        { USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
@@ -243,7 +246,7 @@ static int inc_tx(struct btusb_data *data)
 static void btusb_intr_complete(struct urb *urb)
 {
        struct hci_dev *hdev = urb->context;
-       struct btusb_data *data = hdev->driver_data;
+       struct btusb_data *data = hci_get_drvdata(hdev);
        int err;
 
        BT_DBG("%s urb %p status %d count %d", hdev->name,
@@ -282,7 +285,7 @@ static void btusb_intr_complete(struct urb *urb)
 
 static int btusb_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags)
 {
-       struct btusb_data *data = hdev->driver_data;
+       struct btusb_data *data = hci_get_drvdata(hdev);
        struct urb *urb;
        unsigned char *buf;
        unsigned int pipe;
@@ -331,7 +334,7 @@ static int btusb_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags)
 static void btusb_bulk_complete(struct urb *urb)
 {
        struct hci_dev *hdev = urb->context;
-       struct btusb_data *data = hdev->driver_data;
+       struct btusb_data *data = hci_get_drvdata(hdev);
        int err;
 
        BT_DBG("%s urb %p status %d count %d", hdev->name,
@@ -370,7 +373,7 @@ static void btusb_bulk_complete(struct urb *urb)
 
 static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags)
 {
-       struct btusb_data *data = hdev->driver_data;
+       struct btusb_data *data = hci_get_drvdata(hdev);
        struct urb *urb;
        unsigned char *buf;
        unsigned int pipe;
@@ -417,7 +420,7 @@ static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags)
 static void btusb_isoc_complete(struct urb *urb)
 {
        struct hci_dev *hdev = urb->context;
-       struct btusb_data *data = hdev->driver_data;
+       struct btusb_data *data = hci_get_drvdata(hdev);
        int i, err;
 
        BT_DBG("%s urb %p status %d count %d", hdev->name,
@@ -484,7 +487,7 @@ static inline void __fill_isoc_descriptor(struct urb *urb, int len, int mtu)
 
 static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags)
 {
-       struct btusb_data *data = hdev->driver_data;
+       struct btusb_data *data = hci_get_drvdata(hdev);
        struct urb *urb;
        unsigned char *buf;
        unsigned int pipe;
@@ -537,7 +540,7 @@ static void btusb_tx_complete(struct urb *urb)
 {
        struct sk_buff *skb = urb->context;
        struct hci_dev *hdev = (struct hci_dev *) skb->dev;
-       struct btusb_data *data = hdev->driver_data;
+       struct btusb_data *data = hci_get_drvdata(hdev);
 
        BT_DBG("%s urb %p status %d count %d", hdev->name,
                                        urb, urb->status, urb->actual_length);
@@ -584,7 +587,7 @@ done:
 
 static int btusb_open(struct hci_dev *hdev)
 {
-       struct btusb_data *data = hdev->driver_data;
+       struct btusb_data *data = hci_get_drvdata(hdev);
        int err;
 
        BT_DBG("%s", hdev->name);
@@ -634,7 +637,7 @@ static void btusb_stop_traffic(struct btusb_data *data)
 
 static int btusb_close(struct hci_dev *hdev)
 {
-       struct btusb_data *data = hdev->driver_data;
+       struct btusb_data *data = hci_get_drvdata(hdev);
        int err;
 
        BT_DBG("%s", hdev->name);
@@ -664,7 +667,7 @@ failed:
 
 static int btusb_flush(struct hci_dev *hdev)
 {
-       struct btusb_data *data = hdev->driver_data;
+       struct btusb_data *data = hci_get_drvdata(hdev);
 
        BT_DBG("%s", hdev->name);
 
@@ -676,7 +679,7 @@ static int btusb_flush(struct hci_dev *hdev)
 static int btusb_send_frame(struct sk_buff *skb)
 {
        struct hci_dev *hdev = (struct hci_dev *) skb->dev;
-       struct btusb_data *data = hdev->driver_data;
+       struct btusb_data *data = hci_get_drvdata(hdev);
        struct usb_ctrlrequest *dr;
        struct urb *urb;
        unsigned int pipe;
@@ -784,18 +787,9 @@ done:
        return err;
 }
 
-static void btusb_destruct(struct hci_dev *hdev)
-{
-       struct btusb_data *data = hdev->driver_data;
-
-       BT_DBG("%s", hdev->name);
-
-       kfree(data);
-}
-
 static void btusb_notify(struct hci_dev *hdev, unsigned int evt)
 {
-       struct btusb_data *data = hdev->driver_data;
+       struct btusb_data *data = hci_get_drvdata(hdev);
 
        BT_DBG("%s evt %d", hdev->name, evt);
 
@@ -807,7 +801,7 @@ static void btusb_notify(struct hci_dev *hdev, unsigned int evt)
 
 static inline int __set_isoc_interface(struct hci_dev *hdev, int altsetting)
 {
-       struct btusb_data *data = hdev->driver_data;
+       struct btusb_data *data = hci_get_drvdata(hdev);
        struct usb_interface *intf = data->isoc;
        struct usb_endpoint_descriptor *ep_desc;
        int i, err;
@@ -995,7 +989,7 @@ static int btusb_probe(struct usb_interface *intf,
        }
 
        hdev->bus = HCI_USB;
-       hdev->driver_data = data;
+       hci_set_drvdata(hdev, data);
 
        data->hdev = hdev;
 
@@ -1005,11 +999,8 @@ static int btusb_probe(struct usb_interface *intf,
        hdev->close    = btusb_close;
        hdev->flush    = btusb_flush;
        hdev->send     = btusb_send_frame;
-       hdev->destruct = btusb_destruct;
        hdev->notify   = btusb_notify;
 
-       hdev->owner = THIS_MODULE;
-
        /* Interface numbers are hardcoded in the specification */
        data->isoc = usb_ifnum_to_if(data->udev, 1);
 
@@ -1091,9 +1082,6 @@ static void btusb_disconnect(struct usb_interface *intf)
                return;
 
        hdev = data->hdev;
-
-       __hci_dev_hold(hdev);
-
        usb_set_intfdata(data->intf, NULL);
 
        if (data->isoc)
@@ -1106,9 +1094,8 @@ static void btusb_disconnect(struct usb_interface *intf)
        else if (data->isoc)
                usb_driver_release_interface(&btusb_driver, data->isoc);
 
-       __hci_dev_put(hdev);
-
        hci_free_dev(hdev);
+       kfree(data);
 }
 
 #ifdef CONFIG_PM
index b5f83b44a0cd18a42f32aa8b4398ea69b5b9ba2b..88694697f34f68386cdb4273289ccea7baaeaa5b 100644 (file)
@@ -161,7 +161,7 @@ static int ti_st_open(struct hci_dev *hdev)
                return -EBUSY;
 
        /* provide contexts for callbacks from ST */
-       hst = hdev->driver_data;
+       hst = hci_get_drvdata(hdev);
 
        for (i = 0; i < MAX_BT_CHNL_IDS; i++) {
                ti_st_proto[i].priv_data = hst;
@@ -236,7 +236,7 @@ done:
 static int ti_st_close(struct hci_dev *hdev)
 {
        int err, i;
-       struct ti_st *hst = hdev->driver_data;
+       struct ti_st *hst = hci_get_drvdata(hdev);
 
        if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
                return 0;
@@ -264,7 +264,7 @@ static int ti_st_send_frame(struct sk_buff *skb)
        if (!test_bit(HCI_RUNNING, &hdev->flags))
                return -EBUSY;
 
-       hst = hdev->driver_data;
+       hst = hci_get_drvdata(hdev);
 
        /* Prepend skb with frame type */
        memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
@@ -291,14 +291,6 @@ static int ti_st_send_frame(struct sk_buff *skb)
        return 0;
 }
 
-static void ti_st_destruct(struct hci_dev *hdev)
-{
-       BT_DBG("%s", hdev->name);
-       /* do nothing here, since platform remove
-        * would free the hdev->driver_data
-        */
-}
-
 static int bt_ti_probe(struct platform_device *pdev)
 {
        static struct ti_st *hst;
@@ -320,13 +312,11 @@ static int bt_ti_probe(struct platform_device *pdev)
 
        hst->hdev = hdev;
        hdev->bus = HCI_UART;
-       hdev->driver_data = hst;
+       hci_set_drvdata(hdev, hst);
        hdev->open = ti_st_open;
        hdev->close = ti_st_close;
        hdev->flush = NULL;
        hdev->send = ti_st_send_frame;
-       hdev->destruct = ti_st_destruct;
-       hdev->owner = THIS_MODULE;
 
        err = hci_register_dev(hdev);
        if (err < 0) {
index 969bb22e493f530977ab1c5258f55067963a6cac..049c0594a76b94b82f021409f7a4cdea2bc5cd4c 100644 (file)
@@ -83,9 +83,6 @@ typedef struct dtl1_info_t {
 
 
 static int dtl1_config(struct pcmcia_device *link);
-static void dtl1_release(struct pcmcia_device *link);
-
-static void dtl1_detach(struct pcmcia_device *p_dev);
 
 
 /* Transmit states  */
@@ -367,7 +364,7 @@ static int dtl1_hci_open(struct hci_dev *hdev)
 
 static int dtl1_hci_flush(struct hci_dev *hdev)
 {
-       dtl1_info_t *info = (dtl1_info_t *)(hdev->driver_data);
+       dtl1_info_t *info = hci_get_drvdata(hdev);
 
        /* Drop TX queue */
        skb_queue_purge(&(info->txq));
@@ -399,7 +396,7 @@ static int dtl1_hci_send_frame(struct sk_buff *skb)
                return -ENODEV;
        }
 
-       info = (dtl1_info_t *)(hdev->driver_data);
+       info = hci_get_drvdata(hdev);
 
        switch (bt_cb(skb)->pkt_type) {
        case HCI_COMMAND_PKT:
@@ -442,11 +439,6 @@ static int dtl1_hci_send_frame(struct sk_buff *skb)
 }
 
 
-static void dtl1_hci_destruct(struct hci_dev *hdev)
-{
-}
-
-
 static int dtl1_hci_ioctl(struct hci_dev *hdev, unsigned int cmd,  unsigned long arg)
 {
        return -ENOIOCTLCMD;
@@ -483,18 +475,15 @@ static int dtl1_open(dtl1_info_t *info)
        info->hdev = hdev;
 
        hdev->bus = HCI_PCCARD;
-       hdev->driver_data = info;
+       hci_set_drvdata(hdev, info);
        SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
 
        hdev->open     = dtl1_hci_open;
        hdev->close    = dtl1_hci_close;
        hdev->flush    = dtl1_hci_flush;
        hdev->send     = dtl1_hci_send_frame;
-       hdev->destruct = dtl1_hci_destruct;
        hdev->ioctl    = dtl1_hci_ioctl;
 
-       hdev->owner = THIS_MODULE;
-
        spin_lock_irqsave(&(info->lock), flags);
 
        /* Reset UART */
@@ -579,8 +568,8 @@ static void dtl1_detach(struct pcmcia_device *link)
 {
        dtl1_info_t *info = link->priv;
 
-       dtl1_release(link);
-
+       dtl1_close(info);
+       pcmcia_disable_device(link);
        kfree(info);
 }
 
@@ -619,21 +608,10 @@ static int dtl1_config(struct pcmcia_device *link)
        return 0;
 
 failed:
-       dtl1_release(link);
+       dtl1_detach(link);
        return -ENODEV;
 }
 
-
-static void dtl1_release(struct pcmcia_device *link)
-{
-       dtl1_info_t *info = link->priv;
-
-       dtl1_close(info);
-
-       pcmcia_disable_device(link);
-}
-
-
 static const struct pcmcia_device_id dtl1_ids[] = {
        PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-1", 0xe1bfdd64, 0xe168480d),
        PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-4", 0xe1bfdd64, 0x9102bc82),
index 4093935ddf42619e44fef9b87428c34454104fe8..12172a6a95c440467666d1599f13bab4fe45253f 100644 (file)
@@ -112,7 +112,7 @@ static int ath_open(struct hci_uart *hu)
 
        BT_DBG("hu %p", hu);
 
-       ath = kzalloc(sizeof(*ath), GFP_ATOMIC);
+       ath = kzalloc(sizeof(*ath), GFP_KERNEL);
        if (!ath)
                return -ENOMEM;
 
index a767d4de45a4177d7fbc213f6f5edbcb42ae21c2..661a8dc4d2f8b346e390053ee45d63cb7249346e 100644 (file)
@@ -692,7 +692,7 @@ static int bcsp_open(struct hci_uart *hu)
 
        BT_DBG("hu %p", hu);
 
-       bcsp = kzalloc(sizeof(*bcsp), GFP_ATOMIC);
+       bcsp = kzalloc(sizeof(*bcsp), GFP_KERNEL);
        if (!bcsp)
                return -ENOMEM;
 
index 2fcd8b387d694b74130956fe836b5c211dbee20a..748329468d26ca6432f6e04dc2d2ab92afd62e4f 100644 (file)
@@ -69,7 +69,7 @@ static int h4_open(struct hci_uart *hu)
 
        BT_DBG("hu %p", hu);
 
-       h4 = kzalloc(sizeof(*h4), GFP_ATOMIC);
+       h4 = kzalloc(sizeof(*h4), GFP_KERNEL);
        if (!h4)
                return -ENOMEM;
 
index 07114489994f5f383f4aef45c38cca72b38b52f9..fd5adb408f447a4a08b9dbece913e111d3fe9906 100644 (file)
@@ -48,8 +48,6 @@
 
 #define VERSION "2.2"
 
-static bool reset = 0;
-
 static struct hci_uart_proto *hup[HCI_UART_MAX_PROTO];
 
 int hci_uart_register_proto(struct hci_uart_proto *p)
@@ -174,7 +172,7 @@ static int hci_uart_open(struct hci_dev *hdev)
 /* Reset device */
 static int hci_uart_flush(struct hci_dev *hdev)
 {
-       struct hci_uart *hu  = (struct hci_uart *) hdev->driver_data;
+       struct hci_uart *hu  = hci_get_drvdata(hdev);
        struct tty_struct *tty = hu->tty;
 
        BT_DBG("hdev %p tty %p", hdev, tty);
@@ -220,7 +218,7 @@ static int hci_uart_send_frame(struct sk_buff *skb)
        if (!test_bit(HCI_RUNNING, &hdev->flags))
                return -EBUSY;
 
-       hu = (struct hci_uart *) hdev->driver_data;
+       hu = hci_get_drvdata(hdev);
 
        BT_DBG("%s: type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len);
 
@@ -231,15 +229,6 @@ static int hci_uart_send_frame(struct sk_buff *skb)
        return 0;
 }
 
-static void hci_uart_destruct(struct hci_dev *hdev)
-{
-       if (!hdev)
-               return;
-
-       BT_DBG("%s", hdev->name);
-       kfree(hdev->driver_data);
-}
-
 /* ------ LDISC part ------ */
 /* hci_uart_tty_open
  * 
@@ -316,6 +305,8 @@ static void hci_uart_tty_close(struct tty_struct *tty)
                                hci_free_dev(hdev);
                        }
                }
+
+               kfree(hu);
        }
 }
 
@@ -391,22 +382,24 @@ static int hci_uart_register_dev(struct hci_uart *hu)
        hu->hdev = hdev;
 
        hdev->bus = HCI_UART;
-       hdev->driver_data = hu;
+       hci_set_drvdata(hdev, hu);
 
        hdev->open  = hci_uart_open;
        hdev->close = hci_uart_close;
        hdev->flush = hci_uart_flush;
        hdev->send  = hci_uart_send_frame;
-       hdev->destruct = hci_uart_destruct;
        hdev->parent = hu->tty->dev;
 
-       hdev->owner = THIS_MODULE;
+       if (test_bit(HCI_UART_RAW_DEVICE, &hu->hdev_flags))
+               set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
 
-       if (!reset)
+       if (!test_bit(HCI_UART_RESET_ON_INIT, &hu->hdev_flags))
                set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
 
-       if (test_bit(HCI_UART_RAW_DEVICE, &hu->hdev_flags))
-               set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
+       if (test_bit(HCI_UART_CREATE_AMP, &hu->hdev_flags))
+               hdev->dev_type = HCI_AMP;
+       else
+               hdev->dev_type = HCI_BREDR;
 
        if (hci_register_dev(hdev) < 0) {
                BT_ERR("Can't register HCI device");
@@ -594,9 +587,6 @@ static void __exit hci_uart_exit(void)
 module_init(hci_uart_init);
 module_exit(hci_uart_exit);
 
-module_param(reset, bool, 0644);
-MODULE_PARM_DESC(reset, "Send HCI reset command on initialization");
-
 MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
 MODULE_DESCRIPTION("Bluetooth HCI UART driver ver " VERSION);
 MODULE_VERSION(VERSION);
index 7e4b435f79f04244cdf5c65d2b7eba9852463bf1..b874c0efde247be90f38d0a2772813ea56fd6afa 100644 (file)
@@ -125,7 +125,7 @@ static int ll_open(struct hci_uart *hu)
 
        BT_DBG("hu %p", hu);
 
-       ll = kzalloc(sizeof(*ll), GFP_ATOMIC);
+       ll = kzalloc(sizeof(*ll), GFP_KERNEL);
        if (!ll)
                return -ENOMEM;
 
index 99fb35239d1fe35c6ec7979601da81ab771f7965..6cf6ab22ad21f7e081f1d806f44638adc8e6a627 100644 (file)
@@ -45,6 +45,8 @@
 #define HCI_UART_ATH3K 5
 
 #define HCI_UART_RAW_DEVICE    0
+#define HCI_UART_RESET_ON_INIT 1
+#define HCI_UART_CREATE_AMP    2
 
 struct hci_uart;
 
index 2ed6ab1c6e1b3a9e7a4b558d24b4f73ec6a8ad5f..158bfe507da7fb19f4149ce63806bd9e8c510409 100644 (file)
@@ -61,7 +61,7 @@ static int vhci_open_dev(struct hci_dev *hdev)
 
 static int vhci_close_dev(struct hci_dev *hdev)
 {
-       struct vhci_data *data = hdev->driver_data;
+       struct vhci_data *data = hci_get_drvdata(hdev);
 
        if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
                return 0;
@@ -73,7 +73,7 @@ static int vhci_close_dev(struct hci_dev *hdev)
 
 static int vhci_flush(struct hci_dev *hdev)
 {
-       struct vhci_data *data = hdev->driver_data;
+       struct vhci_data *data = hci_get_drvdata(hdev);
 
        skb_queue_purge(&data->readq);
 
@@ -93,7 +93,7 @@ static int vhci_send_frame(struct sk_buff *skb)
        if (!test_bit(HCI_RUNNING, &hdev->flags))
                return -EBUSY;
 
-       data = hdev->driver_data;
+       data = hci_get_drvdata(hdev);
 
        memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
        skb_queue_tail(&data->readq, skb);
@@ -103,11 +103,6 @@ static int vhci_send_frame(struct sk_buff *skb)
        return 0;
 }
 
-static void vhci_destruct(struct hci_dev *hdev)
-{
-       kfree(hdev->driver_data);
-}
-
 static inline ssize_t vhci_get_user(struct vhci_data *data,
                                        const char __user *buf, size_t count)
 {
@@ -239,7 +234,7 @@ static int vhci_open(struct inode *inode, struct file *file)
        data->hdev = hdev;
 
        hdev->bus = HCI_VIRTUAL;
-       hdev->driver_data = data;
+       hci_set_drvdata(hdev, data);
 
        if (amp)
                hdev->dev_type = HCI_AMP;
@@ -248,9 +243,6 @@ static int vhci_open(struct inode *inode, struct file *file)
        hdev->close    = vhci_close_dev;
        hdev->flush    = vhci_flush;
        hdev->send     = vhci_send_frame;
-       hdev->destruct = vhci_destruct;
-
-       hdev->owner = THIS_MODULE;
 
        if (hci_register_dev(hdev) < 0) {
                BT_ERR("Can't register HCI device");
@@ -273,6 +265,7 @@ static int vhci_release(struct inode *inode, struct file *file)
        hci_free_dev(hdev);
 
        file->private_data = NULL;
+       kfree(data);
 
        return 0;
 }
index 597235a2f8f908bbc69fffc596ffc20d71a16c5b..0d40cf66b3cc55111182515fd4d695101d200fa0 100644 (file)
@@ -714,6 +714,7 @@ static int mv_hash_final(struct ahash_request *req)
 {
        struct mv_req_hash_ctx *ctx = ahash_request_ctx(req);
 
+       ahash_request_set_crypt(req, NULL, req->result, 0);
        mv_update_hash_req_ctx(ctx, 1, 0);
        return mv_handle_req(&req->base);
 }
index d620b0784257f05cab7c52b121a460c99f6f7daf..618bd4d87d286171a87da2fdbdfc2d251eae63f2 100644 (file)
@@ -28,6 +28,7 @@
 #include "drmP.h"
 #include "drm_crtc_helper.h"
 
+#include <drm/exynos_drm.h>
 #include "exynos_drm_drv.h"
 #include "exynos_drm_encoder.h"
 
@@ -44,8 +45,9 @@ struct exynos_drm_connector {
 /* convert exynos_video_timings to drm_display_mode */
 static inline void
 convert_to_display_mode(struct drm_display_mode *mode,
-                       struct fb_videomode *timing)
+                       struct exynos_drm_panel_info *panel)
 {
+       struct fb_videomode *timing = &panel->timing;
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
        mode->clock = timing->pixclock / 1000;
@@ -60,6 +62,8 @@ convert_to_display_mode(struct drm_display_mode *mode,
        mode->vsync_start = mode->vdisplay + timing->upper_margin;
        mode->vsync_end = mode->vsync_start + timing->vsync_len;
        mode->vtotal = mode->vsync_end + timing->lower_margin;
+       mode->width_mm = panel->width_mm;
+       mode->height_mm = panel->height_mm;
 
        if (timing->vmode & FB_VMODE_INTERLACED)
                mode->flags |= DRM_MODE_FLAG_INTERLACE;
@@ -148,16 +152,18 @@ static int exynos_drm_connector_get_modes(struct drm_connector *connector)
                connector->display_info.raw_edid = edid;
        } else {
                struct drm_display_mode *mode = drm_mode_create(connector->dev);
-               struct fb_videomode *timing;
+               struct exynos_drm_panel_info *panel;
 
-               if (display_ops->get_timing)
-                       timing = display_ops->get_timing(manager->dev);
+               if (display_ops->get_panel)
+                       panel = display_ops->get_panel(manager->dev);
                else {
                        drm_mode_destroy(connector->dev, mode);
                        return 0;
                }
 
-               convert_to_display_mode(mode, timing);
+               convert_to_display_mode(mode, panel);
+               connector->display_info.width_mm = mode->width_mm;
+               connector->display_info.height_mm = mode->height_mm;
 
                mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
                drm_mode_set_name(mode);
index e685e1e33055fd21e08446da5215e368c46c02cc..13540de90bfc428101afe15c39258ee9623868a1 100644 (file)
@@ -136,7 +136,7 @@ struct exynos_drm_overlay {
  * @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI.
  * @is_connected: check for that display is connected or not.
  * @get_edid: get edid modes from display driver.
- * @get_timing: get timing object from display driver.
+ * @get_panel: get panel object from display driver.
  * @check_timing: check if timing is valid or not.
  * @power_on: display device on or off.
  */
@@ -145,7 +145,7 @@ struct exynos_drm_display_ops {
        bool (*is_connected)(struct device *dev);
        int (*get_edid)(struct device *dev, struct drm_connector *connector,
                                u8 *edid, int len);
-       void *(*get_timing)(struct device *dev);
+       void *(*get_panel)(struct device *dev);
        int (*check_timing)(struct device *dev, void *timing);
        int (*power_on)(struct device *dev, int mode);
 };
index 0dbb32bb18a359075f3421afea2f8ef856261dc9..360adf2bba047bb9c60177bc1a7dff8965ba3fd1 100644 (file)
@@ -89,7 +89,7 @@ struct fimd_context {
        bool                            suspended;
        struct mutex                    lock;
 
-       struct fb_videomode             *timing;
+       struct exynos_drm_panel_info *panel;
 };
 
 static bool fimd_display_is_connected(struct device *dev)
@@ -101,13 +101,13 @@ static bool fimd_display_is_connected(struct device *dev)
        return true;
 }
 
-static void *fimd_get_timing(struct device *dev)
+static void *fimd_get_panel(struct device *dev)
 {
        struct fimd_context *ctx = get_fimd_context(dev);
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
-       return ctx->timing;
+       return ctx->panel;
 }
 
 static int fimd_check_timing(struct device *dev, void *timing)
@@ -131,7 +131,7 @@ static int fimd_display_power_on(struct device *dev, int mode)
 static struct exynos_drm_display_ops fimd_display_ops = {
        .type = EXYNOS_DISPLAY_TYPE_LCD,
        .is_connected = fimd_display_is_connected,
-       .get_timing = fimd_get_timing,
+       .get_panel = fimd_get_panel,
        .check_timing = fimd_check_timing,
        .power_on = fimd_display_power_on,
 };
@@ -193,7 +193,8 @@ static void fimd_apply(struct device *subdrv_dev)
 static void fimd_commit(struct device *dev)
 {
        struct fimd_context *ctx = get_fimd_context(dev);
-       struct fb_videomode *timing = ctx->timing;
+       struct exynos_drm_panel_info *panel = ctx->panel;
+       struct fb_videomode *timing = &panel->timing;
        u32 val;
 
        if (ctx->suspended)
@@ -786,7 +787,7 @@ static int __devinit fimd_probe(struct platform_device *pdev)
        struct fimd_context *ctx;
        struct exynos_drm_subdrv *subdrv;
        struct exynos_drm_fimd_pdata *pdata;
-       struct fb_videomode *timing;
+       struct exynos_drm_panel_info *panel;
        struct resource *res;
        int win;
        int ret = -EINVAL;
@@ -799,9 +800,9 @@ static int __devinit fimd_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       timing = &pdata->timing;
-       if (!timing) {
-               dev_err(dev, "timing is null.\n");
+       panel = &pdata->panel;
+       if (!panel) {
+               dev_err(dev, "panel is null.\n");
                return -EINVAL;
        }
 
@@ -863,16 +864,16 @@ static int __devinit fimd_probe(struct platform_device *pdev)
                goto err_req_irq;
        }
 
-       ctx->clkdiv = fimd_calc_clkdiv(ctx, timing);
+       ctx->clkdiv = fimd_calc_clkdiv(ctx, &panel->timing);
        ctx->vidcon0 = pdata->vidcon0;
        ctx->vidcon1 = pdata->vidcon1;
        ctx->default_win = pdata->default_win;
-       ctx->timing = timing;
+       ctx->panel = panel;
 
-       timing->pixclock = clk_get_rate(ctx->lcd_clk) / ctx->clkdiv;
+       panel->timing.pixclock = clk_get_rate(ctx->lcd_clk) / ctx->clkdiv;
 
        DRM_DEBUG_KMS("pixel clock = %d, clkdiv = %d\n",
-                       timing->pixclock, ctx->clkdiv);
+                       panel->timing.pixclock, ctx->clkdiv);
 
        subdrv = &ctx->subdrv;
 
index 4a5b099c3bc5ac9430c9b24a651f326f0295c748..53404af2e748b74a6801f5d5f70079e4ce556a88 100644 (file)
@@ -321,6 +321,8 @@ static int cdv_chip_setup(struct drm_device *dev)
        cdv_get_core_freq(dev);
        gma_intel_opregion_init(dev);
        psb_intel_init_bios(dev);
+       REG_WRITE(PORT_HOTPLUG_EN, 0);
+       REG_WRITE(PORT_HOTPLUG_STAT, REG_READ(PORT_HOTPLUG_STAT));
        return 0;
 }
 
index 830dfdd6bf154a473e15357654cf4d19be8d6b81..be616735ec918502238df831ad59510513358996 100644 (file)
@@ -247,7 +247,6 @@ static struct fb_ops psbfb_roll_ops = {
        .fb_imageblit = cfb_imageblit,
        .fb_pan_display = psbfb_pan,
        .fb_mmap = psbfb_mmap,
-       .fb_sync = psbfb_sync,
        .fb_ioctl = psbfb_ioctl,
 };
 
index 5d5330f667f14031512c022e12ed3d8eb61bc530..aff194fbe9f3ee00c627e012f8d364af3caa2f8d 100644 (file)
@@ -446,10 +446,9 @@ int psb_gtt_init(struct drm_device *dev, int resume)
        pg->gtt_start = pci_resource_start(dev->pdev, PSB_GTT_RESOURCE);
        gtt_pages = pci_resource_len(dev->pdev, PSB_GTT_RESOURCE)
                                                                >> PAGE_SHIFT;
-       /* Some CDV firmware doesn't report this currently. In which case the
-          system has 64 gtt pages */
+       /* CDV doesn't report this. In which case the system has 64 gtt pages */
        if (pg->gtt_start == 0 || gtt_pages == 0) {
-               dev_err(dev->dev, "GTT PCI BAR not initialized.\n");
+               dev_dbg(dev->dev, "GTT PCI BAR not initialized.\n");
                gtt_pages = 64;
                pg->gtt_start = dev_priv->pge_ctl;
        }
@@ -461,10 +460,10 @@ int psb_gtt_init(struct drm_device *dev, int resume)
 
        if (pg->gatt_pages == 0 || pg->gatt_start == 0) {
                static struct resource fudge;   /* Preferably peppermint */
-               /* This can occur on CDV SDV systems. Fudge it in this case.
+               /* This can occur on CDV systems. Fudge it in this case.
                   We really don't care what imaginary space is being allocated
                   at this point */
-               dev_err(dev->dev, "GATT PCI BAR not initialized.\n");
+               dev_dbg(dev->dev, "GATT PCI BAR not initialized.\n");
                pg->gatt_start = 0x40000000;
                pg->gatt_pages = (128 * 1024 * 1024) >> PAGE_SHIFT;
                /* This is a little confusing but in fact the GTT is providing
index f425b23e3803317f8088a7e2ffbb377e80cbd3f8..f851db7be2cc20ccc279b794bf78e65d566d1573 100644 (file)
@@ -4680,8 +4680,17 @@ sandybridge_compute_sprite_srwm(struct drm_device *dev, int plane,
 
        crtc = intel_get_crtc_for_plane(dev, plane);
        clock = crtc->mode.clock;
+       if (!clock) {
+               *sprite_wm = 0;
+               return false;
+       }
 
        line_time_us = (sprite_width * 1000) / clock;
+       if (!line_time_us) {
+               *sprite_wm = 0;
+               return false;
+       }
+
        line_count = (latency_ns / line_time_us + 1000) / 1000;
        line_size = sprite_width * pixel_size;
 
@@ -6175,7 +6184,7 @@ void intel_crtc_load_lut(struct drm_crtc *crtc)
        int i;
 
        /* The clocks have to be on to load the palette. */
-       if (!crtc->enabled)
+       if (!crtc->enabled || !intel_crtc->active)
                return;
 
        /* use legacy palette for Ironlake */
@@ -6561,7 +6570,7 @@ intel_framebuffer_create_for_mode(struct drm_device *dev,
        mode_cmd.height = mode->vdisplay;
        mode_cmd.pitches[0] = intel_framebuffer_pitch_for_width(mode_cmd.width,
                                                                bpp);
-       mode_cmd.pixel_format = 0;
+       mode_cmd.pixel_format = drm_mode_legacy_fb_format(bpp, depth);
 
        return intel_framebuffer_create(dev, &mode_cmd, obj);
 }
@@ -8185,7 +8194,7 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv)
 
        if (intel_enable_rc6(dev_priv->dev))
                rc6_mask = GEN6_RC_CTL_RC6_ENABLE |
-                       (IS_GEN7(dev_priv->dev)) ? GEN6_RC_CTL_RC6p_ENABLE : 0;
+                       ((IS_GEN7(dev_priv->dev)) ? GEN6_RC_CTL_RC6p_ENABLE : 0);
 
        I915_WRITE(GEN6_RC_CONTROL,
                   rc6_mask |
index 1ab842c6032e949a37855a3995aa161d9f276977..536191540b0399bf8aa04f7c05f5129bb9a13d03 100644 (file)
@@ -301,7 +301,7 @@ static int init_ring_common(struct intel_ring_buffer *ring)
 
        I915_WRITE_CTL(ring,
                        ((ring->size - PAGE_SIZE) & RING_NR_PAGES)
-                       | RING_REPORT_64K | RING_VALID);
+                       | RING_VALID);
 
        /* If the head is still not zero, the ring is dead */
        if ((I915_READ_CTL(ring) & RING_VALID) == 0 ||
@@ -1132,18 +1132,6 @@ int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n)
        struct drm_device *dev = ring->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long end;
-       u32 head;
-
-       /* If the reported head position has wrapped or hasn't advanced,
-        * fallback to the slow and accurate path.
-        */
-       head = intel_read_status_page(ring, 4);
-       if (head > ring->head) {
-               ring->head = head;
-               ring->space = ring_space(ring);
-               if (ring->space >= n)
-                       return 0;
-       }
 
        trace_i915_ring_wait_begin(ring);
        if (drm_core_check_feature(dev, DRIVER_GEM))
index fbcd84803b60375b74c87b8e88df4caabf92b333..17ca72ce30277332965fa7772884a93764c0664a 100644 (file)
@@ -2362,6 +2362,9 @@ void r600_semaphore_ring_emit(struct radeon_device *rdev,
        uint64_t addr = semaphore->gpu_addr;
        unsigned sel = emit_wait ? PACKET3_SEM_SEL_WAIT : PACKET3_SEM_SEL_SIGNAL;
 
+       if (rdev->family < CHIP_CAYMAN)
+               sel |= PACKET3_SEM_WAIT_ON_SIGNAL;
+
        radeon_ring_write(ring, PACKET3(PACKET3_MEM_SEMAPHORE, 1));
        radeon_ring_write(ring, addr & 0xffffffff);
        radeon_ring_write(ring, (upper_32_bits(addr) & 0xff) | sel);
index 2d1f6c5ee2a77e0466f91ceb2e4b4f28cd0cf218..73e2c7c6edbc63c02e35a198a684e40708c65c8f 100644 (file)
@@ -313,6 +313,10 @@ const u32 r6xx_default_state[] =
        0x00000000, /* VGT_REUSE_OFF */
        0x00000000, /* VGT_VTX_CNT_EN */
 
+       0xc0016900,
+       0x000000d4,
+       0x00000000, /* SX_MISC */
+
        0xc0016900,
        0x000002c8,
        0x00000000, /* VGT_STRMOUT_BUFFER_EN */
@@ -625,6 +629,10 @@ const u32 r7xx_default_state[] =
        0x00000000, /* VGT_REUSE_OFF */
        0x00000000, /* VGT_VTX_CNT_EN */
 
+       0xc0016900,
+       0x000000d4,
+       0x00000000, /* SX_MISC */
+
        0xc0016900,
        0x000002c8,
        0x00000000, /* VGT_STRMOUT_BUFFER_EN */
index 38ce5d0427e34a4bf8388da339864c01ad1bf470..387fcc9f03ef242011fe7dba4dbb447902db3583 100644 (file)
@@ -1304,6 +1304,7 @@ static int r600_check_texture_resource(struct radeon_cs_parser *p,  u32 idx,
        h0 = G_038004_TEX_HEIGHT(word1) + 1;
        d0 = G_038004_TEX_DEPTH(word1);
        nfaces = 1;
+       array = 0;
        switch (G_038000_DIM(word0)) {
        case V_038000_SQ_TEX_DIM_1D:
        case V_038000_SQ_TEX_DIM_2D:
index 3ee1fd7ef3947d1f624ae8a059d9c511ea15eead..9b23670716f1fa4241ca6cd1cbd6d6186a832049 100644 (file)
 #define        PACKET3_STRMOUT_BUFFER_UPDATE                   0x34
 #define        PACKET3_INDIRECT_BUFFER_MP                      0x38
 #define        PACKET3_MEM_SEMAPHORE                           0x39
+#              define PACKET3_SEM_WAIT_ON_SIGNAL    (0x1 << 12)
 #              define PACKET3_SEM_SEL_SIGNAL       (0x6 << 29)
 #              define PACKET3_SEM_SEL_WAIT         (0x7 << 29)
 #define        PACKET3_MPEG_INDEX                              0x3A
index e7cb3ab09243165c57d261944cd30b489703e149..8c9a8115b632b255f3ad5deb2a88c1aee5dfffc6 100644 (file)
@@ -1057,7 +1057,7 @@ static int radeon_dvi_mode_valid(struct drm_connector *connector,
                    (radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_HDMI_TYPE_B))
                        return MODE_OK;
                else if (radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_HDMI_TYPE_A) {
-                       if (ASIC_IS_DCE3(rdev)) {
+                       if (0) {
                                /* HDMI 1.3+ supports max clock of 340 Mhz */
                                if (mode->clock > 340000)
                                        return MODE_CLOCK_HIGH;
@@ -1117,13 +1117,23 @@ static int radeon_dp_get_modes(struct drm_connector *connector)
            (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) {
                struct drm_display_mode *mode;
 
-               if (!radeon_dig_connector->edp_on)
-                       atombios_set_edp_panel_power(connector,
-                                                    ATOM_TRANSMITTER_ACTION_POWER_ON);
-               ret = radeon_ddc_get_modes(radeon_connector);
-               if (!radeon_dig_connector->edp_on)
-                       atombios_set_edp_panel_power(connector,
-                                                    ATOM_TRANSMITTER_ACTION_POWER_OFF);
+               if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+                       if (!radeon_dig_connector->edp_on)
+                               atombios_set_edp_panel_power(connector,
+                                                            ATOM_TRANSMITTER_ACTION_POWER_ON);
+                       ret = radeon_ddc_get_modes(radeon_connector);
+                       if (!radeon_dig_connector->edp_on)
+                               atombios_set_edp_panel_power(connector,
+                                                            ATOM_TRANSMITTER_ACTION_POWER_OFF);
+               } else {
+                       /* need to setup ddc on the bridge */
+                       if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) !=
+                           ENCODER_OBJECT_ID_NONE) {
+                               if (encoder)
+                                       radeon_atom_ext_encoder_setup_ddc(encoder);
+                       }
+                       ret = radeon_ddc_get_modes(radeon_connector);
+               }
 
                if (ret > 0) {
                        if (encoder) {
@@ -1134,7 +1144,6 @@ static int radeon_dp_get_modes(struct drm_connector *connector)
                        return ret;
                }
 
-               encoder = radeon_best_single_encoder(connector);
                if (!encoder)
                        return 0;
 
index 8c49fef1ce78d01765f0565b517f1f9bc23a5a1c..3d314338d8432398580a6789a78696f50c36871f 100644 (file)
@@ -1078,15 +1078,21 @@ static const struct drm_framebuffer_funcs radeon_fb_funcs = {
        .create_handle = radeon_user_framebuffer_create_handle,
 };
 
-void
+int
 radeon_framebuffer_init(struct drm_device *dev,
                        struct radeon_framebuffer *rfb,
                        struct drm_mode_fb_cmd2 *mode_cmd,
                        struct drm_gem_object *obj)
 {
+       int ret;
        rfb->obj = obj;
-       drm_framebuffer_init(dev, &rfb->base, &radeon_fb_funcs);
+       ret = drm_framebuffer_init(dev, &rfb->base, &radeon_fb_funcs);
+       if (ret) {
+               rfb->obj = NULL;
+               return ret;
+       }
        drm_helper_mode_fill_fb_struct(&rfb->base, mode_cmd);
+       return 0;
 }
 
 static struct drm_framebuffer *
@@ -1096,6 +1102,7 @@ radeon_user_framebuffer_create(struct drm_device *dev,
 {
        struct drm_gem_object *obj;
        struct radeon_framebuffer *radeon_fb;
+       int ret;
 
        obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]);
        if (obj ==  NULL) {
@@ -1108,7 +1115,12 @@ radeon_user_framebuffer_create(struct drm_device *dev,
        if (radeon_fb == NULL)
                return ERR_PTR(-ENOMEM);
 
-       radeon_framebuffer_init(dev, radeon_fb, mode_cmd, obj);
+       ret = radeon_framebuffer_init(dev, radeon_fb, mode_cmd, obj);
+       if (ret) {
+               kfree(radeon_fb);
+               drm_gem_object_unreference_unlocked(obj);
+               return NULL;
+       }
 
        return &radeon_fb->base;
 }
index 9419c51bcf50f0f98f86cfd8122730ceea70a4d6..26e92708d114a8eb64c4a27996911b3c2a61e73f 100644 (file)
@@ -307,8 +307,6 @@ void radeon_panel_mode_fixup(struct drm_encoder *encoder,
 bool radeon_dig_monitor_is_duallink(struct drm_encoder *encoder,
                                    u32 pixel_clock)
 {
-       struct drm_device *dev = encoder->dev;
-       struct radeon_device *rdev = dev->dev_private;
        struct drm_connector *connector;
        struct radeon_connector *radeon_connector;
        struct radeon_connector_atom_dig *dig_connector;
@@ -326,7 +324,7 @@ bool radeon_dig_monitor_is_duallink(struct drm_encoder *encoder,
        case DRM_MODE_CONNECTOR_HDMIB:
                if (radeon_connector->use_digital) {
                        /* HDMI 1.3 supports up to 340 Mhz over single link */
-                       if (ASIC_IS_DCE3(rdev) && drm_detect_hdmi_monitor(radeon_connector->edid)) {
+                       if (0 && drm_detect_hdmi_monitor(radeon_connector->edid)) {
                                if (pixel_clock > 340000)
                                        return true;
                                else
@@ -348,7 +346,7 @@ bool radeon_dig_monitor_is_duallink(struct drm_encoder *encoder,
                        return false;
                else {
                        /* HDMI 1.3 supports up to 340 Mhz over single link */
-                       if (ASIC_IS_DCE3(rdev) && drm_detect_hdmi_monitor(radeon_connector->edid)) {
+                       if (0 && drm_detect_hdmi_monitor(radeon_connector->edid)) {
                                if (pixel_clock > 340000)
                                        return true;
                                else
index cf2bf35b56b8efea936066b469d3211dbe607de1..195471cf65d3240dfb83e413f85a47bd0b0e9720 100644 (file)
@@ -209,6 +209,11 @@ static int radeonfb_create(struct radeon_fbdev *rfbdev,
                                                          sizes->surface_depth);
 
        ret = radeonfb_create_pinned_object(rfbdev, &mode_cmd, &gobj);
+       if (ret) {
+               DRM_ERROR("failed to create fbcon object %d\n", ret);
+               return ret;
+       }
+
        rbo = gem_to_radeon_bo(gobj);
 
        /* okay we have an object now allocate the framebuffer */
@@ -220,7 +225,11 @@ static int radeonfb_create(struct radeon_fbdev *rfbdev,
 
        info->par = rfbdev;
 
-       radeon_framebuffer_init(rdev->ddev, &rfbdev->rfb, &mode_cmd, gobj);
+       ret = radeon_framebuffer_init(rdev->ddev, &rfbdev->rfb, &mode_cmd, gobj);
+       if (ret) {
+               DRM_ERROR("failed to initalise framebuffer %d\n", ret);
+               goto out_unref;
+       }
 
        fb = &rfbdev->rfb.base;
 
index 010dad8b66ae98902f3b7c4ffb61d426103ef07f..c58a036233fb4409b3b4b656a1aba1c103b1b40a 100644 (file)
@@ -597,13 +597,13 @@ int radeon_vm_bo_rmv(struct radeon_device *rdev,
        if (bo_va == NULL)
                return 0;
 
-       list_del(&bo_va->bo_list);
        mutex_lock(&vm->mutex);
        radeon_mutex_lock(&rdev->cs_mutex);
        radeon_vm_bo_update_pte(rdev, vm, bo, NULL);
        radeon_mutex_unlock(&rdev->cs_mutex);
        list_del(&bo_va->vm_list);
        mutex_unlock(&vm->mutex);
+       list_del(&bo_va->bo_list);
 
        kfree(bo_va);
        return 0;
index 4330e3253573ffeb92a5dab9f39223e074fc65ca..8a85598fb242a4f5c9ed666104020e2e90a651c5 100644 (file)
@@ -649,7 +649,7 @@ extern void radeon_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
                                     u16 blue, int regno);
 extern void radeon_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
                                     u16 *blue, int regno);
-void radeon_framebuffer_init(struct drm_device *dev,
+int radeon_framebuffer_init(struct drm_device *dev,
                             struct radeon_framebuffer *rfb,
                             struct drm_mode_fb_cmd2 *mode_cmd,
                             struct drm_gem_object *obj);
index b8574cddd95352a360ef7ff67200527185b3c1fb..63552e30d0c38986308ad2a385bccd8ab6bb9218 100644 (file)
@@ -59,6 +59,9 @@
 #define USB_VENDOR_ID_AIRCABLE         0x16CA
 #define USB_DEVICE_ID_AIRCABLE1                0x1502
 
+#define USB_VENDOR_ID_AIREN            0x1a2c
+#define USB_DEVICE_ID_AIREN_SLIMPLUS   0x0002
+
 #define USB_VENDOR_ID_ALCOR            0x058f
 #define USB_DEVICE_ID_ALCOR_USBRS232   0x9720
 
index 9333d692a786b03df115ebe87d920e748b607dc6..627850a54d34ecd6da97f281324b1eff98a368fc 100644 (file)
@@ -986,8 +986,13 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
                return;
        }
 
-       /* Ignore out-of-range values as per HID specification, section 5.10 */
-       if (value < field->logical_minimum || value > field->logical_maximum) {
+       /*
+        * Ignore out-of-range values as per HID specification,
+        * section 5.10 and 6.2.25
+        */
+       if ((field->flags & HID_MAIN_ITEM_VARIABLE) &&
+           (value < field->logical_minimum ||
+            value > field->logical_maximum)) {
                dbg_hid("Ignoring out-of-range value %x\n", value);
                return;
        }
index c831af937481c66123965743f62aaf5f8a634b3c..57d4e1e1df48df061461681449f5e98f49c20a1e 100644 (file)
@@ -54,6 +54,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII, HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_TOUCHPACK, USB_DEVICE_ID_TOUCHPACK_RTS, HID_QUIRK_MULTI_INPUT },
 
+       { USB_VENDOR_ID_AIREN, USB_DEVICE_ID_AIREN_SLIMPLUS, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
index 02260406b9e440ac406ac3ae7fc3cded1f05bb4e..dad895fec62a3279d447b8049e5e63e430198ad2 100644 (file)
@@ -497,8 +497,9 @@ config SENSORS_JC42
          If you say yes here, you get support for JEDEC JC42.4 compliant
          temperature sensors, which are used on many DDR3 memory modules for
          mobile devices and servers.  Support will include, but not be limited
-         to, ADT7408, CAT34TS02, CAT6095, MAX6604, MCP9805, MCP98242, MCP98243,
-         MCP9843, SE97, SE98, STTS424(E), TSE2002B3, and TS3000B3.
+         to, ADT7408, AT30TS00, CAT34TS02, CAT6095, MAX6604, MCP9804, MCP9805,
+         MCP98242, MCP98243, MCP9843, SE97, SE98, STTS424(E), STTS2002,
+         STTS3000, TSE2002B3, TSE2002GB2, TS3000B3, and TS3000GB2.
 
          This driver can also be built as a module.  If so, the module
          will be called jc42.
index 6bab2001ef3b3d36c5549afe806d2dfab11809f6..6aa5a9fad87930800649fd4e0d17087325539530 100644 (file)
@@ -178,6 +178,16 @@ static inline void f75375_write16(struct i2c_client *client, u8 reg,
        i2c_smbus_write_byte_data(client, reg + 1, (value & 0xFF));
 }
 
+static void f75375_write_pwm(struct i2c_client *client, int nr)
+{
+       struct f75375_data *data = i2c_get_clientdata(client);
+       if (data->kind == f75387)
+               f75375_write16(client, F75375_REG_FAN_EXP(nr), data->pwm[nr]);
+       else
+               f75375_write8(client, F75375_REG_FAN_PWM_DUTY(nr),
+                             data->pwm[nr]);
+}
+
 static struct f75375_data *f75375_update_device(struct device *dev)
 {
        struct i2c_client *client = to_i2c_client(dev);
@@ -254,6 +264,36 @@ static inline u16 rpm_to_reg(int rpm)
        return 1500000 / rpm;
 }
 
+static bool duty_mode_enabled(u8 pwm_enable)
+{
+       switch (pwm_enable) {
+       case 0: /* Manual, duty mode (full speed) */
+       case 1: /* Manual, duty mode */
+       case 4: /* Auto, duty mode */
+               return true;
+       case 2: /* Auto, speed mode */
+       case 3: /* Manual, speed mode */
+               return false;
+       default:
+               BUG();
+       }
+}
+
+static bool auto_mode_enabled(u8 pwm_enable)
+{
+       switch (pwm_enable) {
+       case 0: /* Manual, duty mode (full speed) */
+       case 1: /* Manual, duty mode */
+       case 3: /* Manual, speed mode */
+               return false;
+       case 2: /* Auto, speed mode */
+       case 4: /* Auto, duty mode */
+               return true;
+       default:
+               BUG();
+       }
+}
+
 static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
                const char *buf, size_t count)
 {
@@ -287,6 +327,11 @@ static ssize_t set_fan_target(struct device *dev, struct device_attribute *attr,
        if (err < 0)
                return err;
 
+       if (auto_mode_enabled(data->pwm_enable[nr]))
+               return -EINVAL;
+       if (data->kind == f75387 && duty_mode_enabled(data->pwm_enable[nr]))
+               return -EINVAL;
+
        mutex_lock(&data->update_lock);
        data->fan_target[nr] = rpm_to_reg(val);
        f75375_write16(client, F75375_REG_FAN_EXP(nr), data->fan_target[nr]);
@@ -307,9 +352,13 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
        if (err < 0)
                return err;
 
+       if (auto_mode_enabled(data->pwm_enable[nr]) ||
+           !duty_mode_enabled(data->pwm_enable[nr]))
+               return -EINVAL;
+
        mutex_lock(&data->update_lock);
        data->pwm[nr] = SENSORS_LIMIT(val, 0, 255);
-       f75375_write8(client, F75375_REG_FAN_PWM_DUTY(nr), data->pwm[nr]);
+       f75375_write_pwm(client, nr);
        mutex_unlock(&data->update_lock);
        return count;
 }
@@ -327,11 +376,15 @@ static int set_pwm_enable_direct(struct i2c_client *client, int nr, int val)
        struct f75375_data *data = i2c_get_clientdata(client);
        u8 fanmode;
 
-       if (val < 0 || val > 3)
+       if (val < 0 || val > 4)
                return -EINVAL;
 
        fanmode = f75375_read8(client, F75375_REG_FAN_TIMER);
        if (data->kind == f75387) {
+               /* For now, deny dangerous toggling of duty mode */
+               if (duty_mode_enabled(data->pwm_enable[nr]) !=
+                               duty_mode_enabled(val))
+                       return -EOPNOTSUPP;
                /* clear each fanX_mode bit before setting them properly */
                fanmode &= ~(1 << F75387_FAN_DUTY_MODE(nr));
                fanmode &= ~(1 << F75387_FAN_MANU_MODE(nr));
@@ -345,12 +398,14 @@ static int set_pwm_enable_direct(struct i2c_client *client, int nr, int val)
                        fanmode  |= (1 << F75387_FAN_MANU_MODE(nr));
                        fanmode  |= (1 << F75387_FAN_DUTY_MODE(nr));
                        break;
-               case 2: /* AUTOMATIC*/
-                       fanmode  |=  (1 << F75387_FAN_DUTY_MODE(nr));
+               case 2: /* Automatic, speed mode */
                        break;
                case 3: /* fan speed */
                        fanmode |= (1 << F75387_FAN_MANU_MODE(nr));
                        break;
+               case 4: /* Automatic, pwm */
+                       fanmode |= (1 << F75387_FAN_DUTY_MODE(nr));
+                       break;
                }
        } else {
                /* clear each fanX_mode bit before setting them properly */
@@ -368,14 +423,15 @@ static int set_pwm_enable_direct(struct i2c_client *client, int nr, int val)
                        break;
                case 3: /* fan speed */
                        break;
+               case 4: /* Automatic pwm */
+                       return -EINVAL;
                }
        }
 
        f75375_write8(client, F75375_REG_FAN_TIMER, fanmode);
        data->pwm_enable[nr] = val;
        if (val == 0)
-               f75375_write8(client, F75375_REG_FAN_PWM_DUTY(nr),
-                               data->pwm[nr]);
+               f75375_write_pwm(client, nr);
        return 0;
 }
 
@@ -726,14 +782,17 @@ static void f75375_init(struct i2c_client *client, struct f75375_data *data,
 
                                manu = ((mode >> F75387_FAN_MANU_MODE(nr)) & 1);
                                duty = ((mode >> F75387_FAN_DUTY_MODE(nr)) & 1);
-                               if (manu && duty)
-                                       /* speed */
+                               if (!manu && duty)
+                                       /* auto, pwm */
+                                       data->pwm_enable[nr] = 4;
+                               else if (manu && !duty)
+                                       /* manual, speed */
                                        data->pwm_enable[nr] = 3;
-                               else if (!manu && duty)
-                                       /* automatic */
+                               else if (!manu && !duty)
+                                       /* automatic, speed */
                                        data->pwm_enable[nr] = 2;
                                else
-                                       /* manual */
+                                       /* manual, pwm */
                                        data->pwm_enable[nr] = 1;
                        } else {
                                if (!(conf & (1 << F75375_FAN_CTRL_LINEAR(nr))))
@@ -758,9 +817,11 @@ static void f75375_init(struct i2c_client *client, struct f75375_data *data,
        set_pwm_enable_direct(client, 0, f75375s_pdata->pwm_enable[0]);
        set_pwm_enable_direct(client, 1, f75375s_pdata->pwm_enable[1]);
        for (nr = 0; nr < 2; nr++) {
+               if (auto_mode_enabled(f75375s_pdata->pwm_enable[nr]) ||
+                   !duty_mode_enabled(f75375s_pdata->pwm_enable[nr]))
+                       continue;
                data->pwm[nr] = SENSORS_LIMIT(f75375s_pdata->pwm[nr], 0, 255);
-               f75375_write8(client, F75375_REG_FAN_PWM_DUTY(nr),
-                       data->pwm[nr]);
+               f75375_write_pwm(client, nr);
        }
 
 }
@@ -787,7 +848,7 @@ static int f75375_probe(struct i2c_client *client,
        if (err)
                goto exit_free;
 
-       if (data->kind == f75375) {
+       if (data->kind != f75373) {
                err = sysfs_chmod_file(&client->dev.kobj,
                        &sensor_dev_attr_pwm1_mode.dev_attr.attr,
                        S_IRUGO | S_IWUSR);
index 28c09eead36baf1ae8360990613d8c694ffa4f29..b927ee5ccdd745dc57f065686a82bf190c5786e7 100644 (file)
@@ -64,6 +64,7 @@ static const unsigned short normal_i2c[] = {
 
 /* Manufacturer IDs */
 #define ADT_MANID              0x11d4  /* Analog Devices */
+#define ATMEL_MANID            0x001f  /* Atmel */
 #define MAX_MANID              0x004d  /* Maxim */
 #define IDT_MANID              0x00b3  /* IDT */
 #define MCP_MANID              0x0054  /* Microchip */
@@ -77,15 +78,25 @@ static const unsigned short normal_i2c[] = {
 #define ADT7408_DEVID          0x0801
 #define ADT7408_DEVID_MASK     0xffff
 
+/* Atmel */
+#define AT30TS00_DEVID         0x8201
+#define AT30TS00_DEVID_MASK    0xffff
+
 /* IDT */
 #define TS3000B3_DEVID         0x2903  /* Also matches TSE2002B3 */
 #define TS3000B3_DEVID_MASK    0xffff
 
+#define TS3000GB2_DEVID                0x2912  /* Also matches TSE2002GB2 */
+#define TS3000GB2_DEVID_MASK   0xffff
+
 /* Maxim */
 #define MAX6604_DEVID          0x3e00
 #define MAX6604_DEVID_MASK     0xffff
 
 /* Microchip */
+#define MCP9804_DEVID          0x0200
+#define MCP9804_DEVID_MASK     0xfffc
+
 #define MCP98242_DEVID         0x2000
 #define MCP98242_DEVID_MASK    0xfffc
 
@@ -113,6 +124,12 @@ static const unsigned short normal_i2c[] = {
 #define STTS424E_DEVID         0x0000
 #define STTS424E_DEVID_MASK    0xfffe
 
+#define STTS2002_DEVID         0x0300
+#define STTS2002_DEVID_MASK    0xffff
+
+#define STTS3000_DEVID         0x0200
+#define STTS3000_DEVID_MASK    0xffff
+
 static u16 jc42_hysteresis[] = { 0, 1500, 3000, 6000 };
 
 struct jc42_chips {
@@ -123,8 +140,11 @@ struct jc42_chips {
 
 static struct jc42_chips jc42_chips[] = {
        { ADT_MANID, ADT7408_DEVID, ADT7408_DEVID_MASK },
+       { ATMEL_MANID, AT30TS00_DEVID, AT30TS00_DEVID_MASK },
        { IDT_MANID, TS3000B3_DEVID, TS3000B3_DEVID_MASK },
+       { IDT_MANID, TS3000GB2_DEVID, TS3000GB2_DEVID_MASK },
        { MAX_MANID, MAX6604_DEVID, MAX6604_DEVID_MASK },
+       { MCP_MANID, MCP9804_DEVID, MCP9804_DEVID_MASK },
        { MCP_MANID, MCP98242_DEVID, MCP98242_DEVID_MASK },
        { MCP_MANID, MCP98243_DEVID, MCP98243_DEVID_MASK },
        { MCP_MANID, MCP9843_DEVID, MCP9843_DEVID_MASK },
@@ -133,6 +153,8 @@ static struct jc42_chips jc42_chips[] = {
        { NXP_MANID, SE98_DEVID, SE98_DEVID_MASK },
        { STM_MANID, STTS424_DEVID, STTS424_DEVID_MASK },
        { STM_MANID, STTS424E_DEVID, STTS424E_DEVID_MASK },
+       { STM_MANID, STTS2002_DEVID, STTS2002_DEVID_MASK },
+       { STM_MANID, STTS3000_DEVID, STTS3000_DEVID_MASK },
 };
 
 /* Each client has this additional data */
@@ -159,10 +181,12 @@ static struct jc42_data *jc42_update_device(struct device *dev);
 
 static const struct i2c_device_id jc42_id[] = {
        { "adt7408", 0 },
+       { "at30ts00", 0 },
        { "cat94ts02", 0 },
        { "cat6095", 0 },
        { "jc42", 0 },
        { "max6604", 0 },
+       { "mcp9804", 0 },
        { "mcp9805", 0 },
        { "mcp98242", 0 },
        { "mcp98243", 0 },
@@ -171,8 +195,10 @@ static const struct i2c_device_id jc42_id[] = {
        { "se97b", 0 },
        { "se98", 0 },
        { "stts424", 0 },
-       { "tse2002b3", 0 },
-       { "ts3000b3", 0 },
+       { "stts2002", 0 },
+       { "stts3000", 0 },
+       { "tse2002", 0 },
+       { "ts3000", 0 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, jc42_id);
index 00460d8d84239e57c880238469df0f2965c9b976..d89b33967a852b8975f09cb5cea88371f1d52e85 100644 (file)
@@ -54,7 +54,8 @@
                                                   lcrit_alarm, crit_alarm */
 #define PMBUS_IOUT_BOOLEANS_PER_PAGE   3       /* alarm, lcrit_alarm,
                                                   crit_alarm */
-#define PMBUS_POUT_BOOLEANS_PER_PAGE   2       /* alarm, crit_alarm */
+#define PMBUS_POUT_BOOLEANS_PER_PAGE   3       /* cap_alarm, alarm, crit_alarm
+                                                */
 #define PMBUS_MAX_BOOLEANS_PER_FAN     2       /* alarm, fault */
 #define PMBUS_MAX_BOOLEANS_PER_TEMP    4       /* min_alarm, max_alarm,
                                                   lcrit_alarm, crit_alarm */
index 48c7b4a716ae49dfec79a51ff3ac0362849973cd..880b90cf4d3260ce4bb6c586fd34d0d895fea0bc 100644 (file)
@@ -33,6 +33,7 @@ enum chips { zl2004, zl2005, zl2006, zl2008, zl2105, zl2106, zl6100, zl6105 };
 struct zl6100_data {
        int id;
        ktime_t access;         /* chip access time */
+       int delay;              /* Delay between chip accesses in uS */
        struct pmbus_driver_info info;
 };
 
@@ -52,10 +53,10 @@ MODULE_PARM_DESC(delay, "Delay between chip accesses in uS");
 /* Some chips need a delay between accesses */
 static inline void zl6100_wait(const struct zl6100_data *data)
 {
-       if (delay) {
+       if (data->delay) {
                s64 delta = ktime_us_delta(ktime_get(), data->access);
-               if (delta < delay)
-                       udelay(delay - delta);
+               if (delta < data->delay)
+                       udelay(data->delay - delta);
        }
 }
 
@@ -207,8 +208,9 @@ static int zl6100_probe(struct i2c_client *client,
         * can be cleared later for additional chips if tests show that it
         * is not needed (in other words, better be safe than sorry).
         */
+       data->delay = delay;
        if (data->id == zl2004 || data->id == zl6105)
-               delay = 0;
+               data->delay = 0;
 
        /*
         * Since there was a direct I2C device access above, wait before
index 7e78f7c87857c7f0d7af5417064f19e822b4a5f4..3d471d56bf15d1faf295f606c31f19d90f384e79 100644 (file)
@@ -72,6 +72,7 @@
 
 #define MXS_I2C_QUEUESTAT      (0x70)
 #define MXS_I2C_QUEUESTAT_RD_QUEUE_EMPTY        0x00002000
+#define MXS_I2C_QUEUESTAT_WRITE_QUEUE_CNT_MASK 0x0000001F
 
 #define MXS_I2C_QUEUECMD       (0x80)
 
@@ -219,14 +220,14 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
        int ret;
        int flags;
 
-       init_completion(&i2c->cmd_complete);
-
        dev_dbg(i2c->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
                msg->addr, msg->len, msg->flags, stop);
 
        if (msg->len == 0)
                return -EINVAL;
 
+       init_completion(&i2c->cmd_complete);
+
        flags = stop ? MXS_I2C_CTRL0_POST_SEND_STOP : 0;
 
        if (msg->flags & I2C_M_RD)
@@ -286,6 +287,7 @@ static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id)
 {
        struct mxs_i2c_dev *i2c = dev_id;
        u32 stat = readl(i2c->regs + MXS_I2C_CTRL1) & MXS_I2C_IRQ_MASK;
+       bool is_last_cmd;
 
        if (!stat)
                return IRQ_NONE;
@@ -300,9 +302,14 @@ static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id)
        else
                i2c->cmd_err = 0;
 
-       complete(&i2c->cmd_complete);
+       is_last_cmd = (readl(i2c->regs + MXS_I2C_QUEUESTAT) &
+               MXS_I2C_QUEUESTAT_WRITE_QUEUE_CNT_MASK) == 0;
+
+       if (is_last_cmd || i2c->cmd_err)
+               complete(&i2c->cmd_complete);
 
        writel(stat, i2c->regs + MXS_I2C_CTRL1_CLR);
+
        return IRQ_HANDLED;
 }
 
index afc166fcc3d9c41ad6654bae17d5c893382c3705..7df5bfef2624d5c1e49bd39208135c29aaed8653 100644 (file)
@@ -332,7 +332,7 @@ static ssize_t evdev_write(struct file *file, const char __user *buffer,
        struct evdev_client *client = file->private_data;
        struct evdev *evdev = client->evdev;
        struct input_event event;
-       int retval;
+       int retval = 0;
 
        if (count < input_event_size())
                return -EINVAL;
index 37651373a95b0ebb19d25ca32cfcd62599ee4a9b..f3bc4189a7ba136154d418b49028cccb680fb970 100644 (file)
@@ -172,7 +172,7 @@ static void twl4030_vibra_close(struct input_dev *input)
 }
 
 /*** Module ***/
-#if CONFIG_PM
+#if CONFIG_PM_SLEEP
 static int twl4030_vibra_suspend(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
@@ -189,10 +189,10 @@ static int twl4030_vibra_resume(struct device *dev)
        vibra_disable_leds();
        return 0;
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(twl4030_vibra_pm_ops,
                         twl4030_vibra_suspend, twl4030_vibra_resume);
-#endif
 
 static int __devinit twl4030_vibra_probe(struct platform_device *pdev)
 {
@@ -273,9 +273,7 @@ static struct platform_driver twl4030_vibra_driver = {
        .driver         = {
                .name   = "twl4030-vibra",
                .owner  = THIS_MODULE,
-#ifdef CONFIG_PM
                .pm     = &twl4030_vibra_pm_ops,
-#endif
        },
 };
 module_platform_driver(twl4030_vibra_driver);
index bd87380bd879edcfd9a278d53c887c444a14b9d6..4c6a72d3d48c33c875efe6b969652d0f45961270 100644 (file)
@@ -952,7 +952,9 @@ static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int
 
        /*
         * First try "E6 report".
-        * ALPS should return 0,0,10 or 0,0,100
+        * ALPS should return 0,0,10 or 0,0,100 if no buttons are pressed.
+        * The bits 0-2 of the first byte will be 1s if some buttons are
+        * pressed.
         */
        param[0] = 0;
        if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES) ||
@@ -968,7 +970,8 @@ static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int
        psmouse_dbg(psmouse, "E6 report: %2.2x %2.2x %2.2x",
                    param[0], param[1], param[2]);
 
-       if (param[0] != 0 || param[1] != 0 || (param[2] != 10 && param[2] != 100))
+       if ((param[0] & 0xf8) != 0 || param[1] != 0 ||
+           (param[2] != 10 && param[2] != 100))
                return NULL;
 
        /*
index 58a87755b936eee386811396b9ba0ae418a3e0ea..e53f4081a586956974bea8731d366366515ff6f8 100644 (file)
@@ -77,6 +77,8 @@ config TABLET_USB_WACOM
        tristate "Wacom Intuos/Graphire tablet support (USB)"
        depends on USB_ARCH_HAS_HCD
        select USB
+       select NEW_LEDS
+       select LEDS_CLASS
        help
          Say Y here if you want to use the USB version of the Wacom Intuos
          or Graphire tablet.  Make sure to say Y to "Mouse support"
index 88672ec296c116e10d7340c7f07397e10e09afe1..cd3ed29e0801347f20fb9b5da9e2fbbddfbd14b5 100644 (file)
@@ -926,7 +926,7 @@ static int wacom_bpt3_touch(struct wacom_wac *wacom)
 {
        struct input_dev *input = wacom->input;
        unsigned char *data = wacom->data;
-       int count = data[1] & 0x03;
+       int count = data[1] & 0x07;
        int i;
 
        if (data[0] != 0x02)
index bdea288dc185c619e7e944a2959ed215e2a22c10..a35e98ad97258a47e39152361e2b435fa9ba7f07 100644 (file)
@@ -275,7 +275,7 @@ static void iommu_set_exclusion_range(struct amd_iommu *iommu)
 }
 
 /* Programs the physical address of the device table into the IOMMU hardware */
-static void __init iommu_set_device_table(struct amd_iommu *iommu)
+static void iommu_set_device_table(struct amd_iommu *iommu)
 {
        u64 entry;
 
index 288da5c1499d5432c14b2410136dfc05f82d18ff..103dbd92e2563ac55116b335fa35cb84f73fe7a8 100644 (file)
@@ -44,7 +44,8 @@ static ssize_t debug_read_ver(struct file *file, char __user *userbuf,
 static ssize_t debug_read_regs(struct file *file, char __user *userbuf,
                               size_t count, loff_t *ppos)
 {
-       struct omap_iommu *obj = file->private_data;
+       struct device *dev = file->private_data;
+       struct omap_iommu *obj = dev_to_omap_iommu(dev);
        char *p, *buf;
        ssize_t bytes;
 
@@ -67,7 +68,8 @@ static ssize_t debug_read_regs(struct file *file, char __user *userbuf,
 static ssize_t debug_read_tlb(struct file *file, char __user *userbuf,
                              size_t count, loff_t *ppos)
 {
-       struct omap_iommu *obj = file->private_data;
+       struct device *dev = file->private_data;
+       struct omap_iommu *obj = dev_to_omap_iommu(dev);
        char *p, *buf;
        ssize_t bytes, rest;
 
@@ -97,7 +99,8 @@ static ssize_t debug_write_pagetable(struct file *file,
        struct iotlb_entry e;
        struct cr_regs cr;
        int err;
-       struct omap_iommu *obj = file->private_data;
+       struct device *dev = file->private_data;
+       struct omap_iommu *obj = dev_to_omap_iommu(dev);
        char buf[MAXCOLUMN], *p = buf;
 
        count = min(count, sizeof(buf));
@@ -184,7 +187,8 @@ out:
 static ssize_t debug_read_pagetable(struct file *file, char __user *userbuf,
                                    size_t count, loff_t *ppos)
 {
-       struct omap_iommu *obj = file->private_data;
+       struct device *dev = file->private_data;
+       struct omap_iommu *obj = dev_to_omap_iommu(dev);
        char *p, *buf;
        size_t bytes;
 
@@ -212,7 +216,8 @@ static ssize_t debug_read_pagetable(struct file *file, char __user *userbuf,
 static ssize_t debug_read_mmap(struct file *file, char __user *userbuf,
                               size_t count, loff_t *ppos)
 {
-       struct omap_iommu *obj = file->private_data;
+       struct device *dev = file->private_data;
+       struct omap_iommu *obj = dev_to_omap_iommu(dev);
        char *p, *buf;
        struct iovm_struct *tmp;
        int uninitialized_var(i);
@@ -254,7 +259,7 @@ static ssize_t debug_read_mmap(struct file *file, char __user *userbuf,
 static ssize_t debug_read_mem(struct file *file, char __user *userbuf,
                              size_t count, loff_t *ppos)
 {
-       struct omap_iommu *obj = file->private_data;
+       struct device *dev = file->private_data;
        char *p, *buf;
        struct iovm_struct *area;
        ssize_t bytes;
@@ -268,8 +273,8 @@ static ssize_t debug_read_mem(struct file *file, char __user *userbuf,
 
        mutex_lock(&iommu_debug_lock);
 
-       area = omap_find_iovm_area(obj, (u32)ppos);
-       if (IS_ERR(area)) {
+       area = omap_find_iovm_area(dev, (u32)ppos);
+       if (!area) {
                bytes = -EINVAL;
                goto err_out;
        }
@@ -287,7 +292,7 @@ err_out:
 static ssize_t debug_write_mem(struct file *file, const char __user *userbuf,
                               size_t count, loff_t *ppos)
 {
-       struct omap_iommu *obj = file->private_data;
+       struct device *dev = file->private_data;
        struct iovm_struct *area;
        char *p, *buf;
 
@@ -305,8 +310,8 @@ static ssize_t debug_write_mem(struct file *file, const char __user *userbuf,
                goto err_out;
        }
 
-       area = omap_find_iovm_area(obj, (u32)ppos);
-       if (IS_ERR(area)) {
+       area = omap_find_iovm_area(dev, (u32)ppos);
+       if (!area) {
                count = -EINVAL;
                goto err_out;
        }
@@ -350,7 +355,7 @@ DEBUG_FOPS(mem);
        {                                                               \
                struct dentry *dent;                                    \
                dent = debugfs_create_file(#attr, mode, parent,         \
-                                          obj, &debug_##attr##_fops);  \
+                                          dev, &debug_##attr##_fops);  \
                if (!dent)                                              \
                        return -ENOMEM;                                 \
        }
@@ -362,20 +367,29 @@ static int iommu_debug_register(struct device *dev, void *data)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct omap_iommu *obj = platform_get_drvdata(pdev);
+       struct omap_iommu_arch_data *arch_data;
        struct dentry *d, *parent;
 
        if (!obj || !obj->dev)
                return -EINVAL;
 
+       arch_data = kzalloc(sizeof(*arch_data), GFP_KERNEL);
+       if (!arch_data)
+               return -ENOMEM;
+
+       arch_data->iommu_dev = obj;
+
+       dev->archdata.iommu = arch_data;
+
        d = debugfs_create_dir(obj->name, iommu_debug_root);
        if (!d)
-               return -ENOMEM;
+               goto nomem;
        parent = d;
 
        d = debugfs_create_u8("nr_tlb_entries", 400, parent,
                              (u8 *)&obj->nr_tlb_entries);
        if (!d)
-               return -ENOMEM;
+               goto nomem;
 
        DEBUG_ADD_FILE_RO(ver);
        DEBUG_ADD_FILE_RO(regs);
@@ -384,6 +398,22 @@ static int iommu_debug_register(struct device *dev, void *data)
        DEBUG_ADD_FILE_RO(mmap);
        DEBUG_ADD_FILE(mem);
 
+       return 0;
+
+nomem:
+       kfree(arch_data);
+       return -ENOMEM;
+}
+
+static int iommu_debug_unregister(struct device *dev, void *data)
+{
+       if (!dev->archdata.iommu)
+               return 0;
+
+       kfree(dev->archdata.iommu);
+
+       dev->archdata.iommu = NULL;
+
        return 0;
 }
 
@@ -411,6 +441,7 @@ module_init(iommu_debug_init)
 static void __exit iommu_debugfs_exit(void)
 {
        debugfs_remove_recursive(iommu_debug_root);
+       omap_foreach_iommu_device(NULL, iommu_debug_unregister);
 }
 module_exit(iommu_debugfs_exit)
 
index d8edd979d01b2c3d84ffb49a9d2c3c53829518d9..6899dcd02dfa0e35df014c42651ba4c5b4f6bb67 100644 (file)
@@ -1223,7 +1223,8 @@ static int __init omap_iommu_init(void)
 
        return platform_driver_register(&omap_iommu_driver);
 }
-module_init(omap_iommu_init);
+/* must be ready before omap3isp is probed */
+subsys_initcall(omap_iommu_init);
 
 static void __exit omap_iommu_exit(void)
 {
index 9fb18c147825aef18fb859ad9bc4faafa7d5e6c9..b280c433e4a08196c0fe3d5166d9fb9f0879704f 100644 (file)
@@ -323,7 +323,7 @@ static int flakey_end_io(struct dm_target *ti, struct bio *bio,
         * Corrupt successful READs while in down state.
         * If flags were specified, only corrupt those that match.
         */
-       if (!error && bio_submitted_while_down &&
+       if (fc->corrupt_bio_byte && !error && bio_submitted_while_down &&
            (bio_data_dir(bio) == READ) && (fc->corrupt_bio_rw == READ) &&
            all_corrupt_bio_flags_match(bio, fc))
                corrupt_bio_data(bio, fc);
index ad2eba40e3190e700eab3136b8af5dd150cbf208..ea5dd289fe2a591cf62246eb10b36ab445de201f 100644 (file)
@@ -296,6 +296,8 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
        unsigned offset;
        unsigned num_bvecs;
        sector_t remaining = where->count;
+       struct request_queue *q = bdev_get_queue(where->bdev);
+       sector_t discard_sectors;
 
        /*
         * where->count may be zero if rw holds a flush and we need to
@@ -305,9 +307,12 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
                /*
                 * Allocate a suitably sized-bio.
                 */
-               num_bvecs = dm_sector_div_up(remaining,
-                                            (PAGE_SIZE >> SECTOR_SHIFT));
-               num_bvecs = min_t(int, bio_get_nr_vecs(where->bdev), num_bvecs);
+               if (rw & REQ_DISCARD)
+                       num_bvecs = 1;
+               else
+                       num_bvecs = min_t(int, bio_get_nr_vecs(where->bdev),
+                                         dm_sector_div_up(remaining, (PAGE_SIZE >> SECTOR_SHIFT)));
+
                bio = bio_alloc_bioset(GFP_NOIO, num_bvecs, io->client->bios);
                bio->bi_sector = where->sector + (where->count - remaining);
                bio->bi_bdev = where->bdev;
@@ -315,10 +320,14 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
                bio->bi_destructor = dm_bio_destructor;
                store_io_and_region_in_bio(bio, io, region);
 
-               /*
-                * Try and add as many pages as possible.
-                */
-               while (remaining) {
+               if (rw & REQ_DISCARD) {
+                       discard_sectors = min_t(sector_t, q->limits.max_discard_sectors, remaining);
+                       bio->bi_size = discard_sectors << SECTOR_SHIFT;
+                       remaining -= discard_sectors;
+               } else while (remaining) {
+                       /*
+                        * Try and add as many pages as possible.
+                        */
                        dp->get_page(dp, &page, &len, &offset);
                        len = min(len, to_bytes(remaining));
                        if (!bio_add_page(bio, page, len, offset))
index 31c2dc25886d985467e7f4084c96d35a98858f67..1ce84ed0b765a889b74b94674da2aff4ffe0fd1c 100644 (file)
@@ -1437,7 +1437,7 @@ static int target_message(struct dm_ioctl *param, size_t param_size)
 
        if (!argc) {
                DMWARN("Empty message received.");
-               goto out;
+               goto out_argv;
        }
 
        table = dm_get_live_table(md);
index 86cb7e5d83d545f1cca9706e689665780148c5db..787022c18187ab24d3305738676b0ca19c148b4c 100644 (file)
@@ -668,7 +668,14 @@ static int super_load(struct md_rdev *rdev, struct md_rdev *refdev)
                return ret;
 
        sb = page_address(rdev->sb_page);
-       if (sb->magic != cpu_to_le32(DM_RAID_MAGIC)) {
+
+       /*
+        * Two cases that we want to write new superblocks and rebuild:
+        * 1) New device (no matching magic number)
+        * 2) Device specified for rebuild (!In_sync w/ offset == 0)
+        */
+       if ((sb->magic != cpu_to_le32(DM_RAID_MAGIC)) ||
+           (!test_bit(In_sync, &rdev->flags) && !rdev->recovery_offset)) {
                super_sync(rdev->mddev, rdev);
 
                set_bit(FirstUse, &rdev->flags);
@@ -745,11 +752,8 @@ static int super_init_validation(struct mddev *mddev, struct md_rdev *rdev)
         */
        rdev_for_each(r, t, mddev) {
                if (!test_bit(In_sync, &r->flags)) {
-                       if (!test_bit(FirstUse, &r->flags))
-                               DMERR("Superblock area of "
-                                     "rebuild device %d should have been "
-                                     "cleared.", r->raid_disk);
-                       set_bit(FirstUse, &r->flags);
+                       DMINFO("Device %d specified for rebuild: "
+                              "Clearing superblock", r->raid_disk);
                        rebuilds++;
                } else if (test_bit(FirstUse, &r->flags))
                        new_devs++;
@@ -971,6 +975,7 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv)
 
        INIT_WORK(&rs->md.event_work, do_table_event);
        ti->private = rs;
+       ti->num_flush_requests = 1;
 
        mutex_lock(&rs->md.reconfig_mutex);
        ret = md_run(&rs->md);
index 59c4f0446ffa9d5081e8dea0308cc68d51911612..237571af77fdfcf552b7061fa13ff291514c86b7 100644 (file)
@@ -385,6 +385,7 @@ static int init_pmd(struct dm_pool_metadata *pmd,
                data_sm = dm_sm_disk_create(tm, nr_blocks);
                if (IS_ERR(data_sm)) {
                        DMERR("sm_disk_create failed");
+                       dm_tm_unlock(tm, sblock);
                        r = PTR_ERR(data_sm);
                        goto bad;
                }
@@ -789,6 +790,11 @@ int dm_pool_metadata_close(struct dm_pool_metadata *pmd)
        return 0;
 }
 
+/*
+ * __open_device: Returns @td corresponding to device with id @dev,
+ * creating it if @create is set and incrementing @td->open_count.
+ * On failure, @td is undefined.
+ */
 static int __open_device(struct dm_pool_metadata *pmd,
                         dm_thin_id dev, int create,
                         struct dm_thin_device **td)
@@ -799,10 +805,16 @@ static int __open_device(struct dm_pool_metadata *pmd,
        struct disk_device_details details_le;
 
        /*
-        * Check the device isn't already open.
+        * If the device is already open, return it.
         */
        list_for_each_entry(td2, &pmd->thin_devices, list)
                if (td2->id == dev) {
+                       /*
+                        * May not create an already-open device.
+                        */
+                       if (create)
+                               return -EEXIST;
+
                        td2->open_count++;
                        *td = td2;
                        return 0;
@@ -817,6 +829,9 @@ static int __open_device(struct dm_pool_metadata *pmd,
                if (r != -ENODATA || !create)
                        return r;
 
+               /*
+                * Create new device.
+                */
                changed = 1;
                details_le.mapped_blocks = 0;
                details_le.transaction_id = cpu_to_le64(pmd->trans_id);
@@ -882,12 +897,10 @@ static int __create_thin(struct dm_pool_metadata *pmd,
 
        r = __open_device(pmd, dev, 1, &td);
        if (r) {
-               __close_device(td);
                dm_btree_remove(&pmd->tl_info, pmd->root, &key, &pmd->root);
                dm_btree_del(&pmd->bl_info, dev_root);
                return r;
        }
-       td->changed = 1;
        __close_device(td);
 
        return r;
@@ -967,14 +980,14 @@ static int __create_snap(struct dm_pool_metadata *pmd,
                goto bad;
 
        r = __set_snapshot_details(pmd, td, origin, pmd->time);
+       __close_device(td);
+
        if (r)
                goto bad;
 
-       __close_device(td);
        return 0;
 
 bad:
-       __close_device(td);
        dm_btree_remove(&pmd->tl_info, pmd->root, &key, &pmd->root);
        dm_btree_remove(&pmd->details_info, pmd->details_root,
                        &key, &pmd->details_root);
@@ -1211,6 +1224,8 @@ static int __remove(struct dm_thin_device *td, dm_block_t block)
        if (r)
                return r;
 
+       td->mapped_blocks--;
+       td->changed = 1;
        pmd->need_commit = 1;
 
        return 0;
index a368db2431a596020a98a3e64f67685ccef9c6cc..a0b225eb4ac449b0ae4b74349be9dbb1e0874fa7 100644 (file)
@@ -624,7 +624,7 @@ int md_raid1_congested(struct mddev *mddev, int bits)
                return 1;
 
        rcu_read_lock();
-       for (i = 0; i < conf->raid_disks; i++) {
+       for (i = 0; i < conf->raid_disks * 2; i++) {
                struct md_rdev *rdev = rcu_dereference(conf->mirrors[i].rdev);
                if (rdev && !test_bit(Faulty, &rdev->flags)) {
                        struct request_queue *q = bdev_get_queue(rdev->bdev);
index 6e8aa213f0d5208d917b8222a56980ab3582b4d6..58c44d6453a0bfa0fb40f155c0357e4392731999 100644 (file)
@@ -67,6 +67,7 @@ static int max_queued_requests = 1024;
 
 static void allow_barrier(struct r10conf *conf);
 static void lower_barrier(struct r10conf *conf);
+static int enough(struct r10conf *conf, int ignore);
 
 static void * r10bio_pool_alloc(gfp_t gfp_flags, void *data)
 {
@@ -347,6 +348,19 @@ static void raid10_end_read_request(struct bio *bio, int error)
                 * wait for the 'master' bio.
                 */
                set_bit(R10BIO_Uptodate, &r10_bio->state);
+       } else {
+               /* If all other devices that store this block have
+                * failed, we want to return the error upwards rather
+                * than fail the last device.  Here we redefine
+                * "uptodate" to mean "Don't want to retry"
+                */
+               unsigned long flags;
+               spin_lock_irqsave(&conf->device_lock, flags);
+               if (!enough(conf, rdev->raid_disk))
+                       uptodate = 1;
+               spin_unlock_irqrestore(&conf->device_lock, flags);
+       }
+       if (uptodate) {
                raid_end_bio_io(r10_bio);
                rdev_dec_pending(rdev, conf->mddev);
        } else {
@@ -2052,6 +2066,7 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10
                       "md/raid10:%s: %s: Failing raid device\n",
                       mdname(mddev), b);
                md_error(mddev, conf->mirrors[d].rdev);
+               r10_bio->devs[r10_bio->read_slot].bio = IO_BLOCKED;
                return;
        }
 
@@ -2105,8 +2120,11 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10
                                    rdev,
                                    r10_bio->devs[r10_bio->read_slot].addr
                                    + sect,
-                                   s, 0))
+                                   s, 0)) {
                                md_error(mddev, rdev);
+                               r10_bio->devs[r10_bio->read_slot].bio
+                                       = IO_BLOCKED;
+                       }
                        break;
                }
 
@@ -2299,17 +2317,20 @@ static void handle_read_error(struct mddev *mddev, struct r10bio *r10_bio)
         * This is all done synchronously while the array is
         * frozen.
         */
+       bio = r10_bio->devs[slot].bio;
+       bdevname(bio->bi_bdev, b);
+       bio_put(bio);
+       r10_bio->devs[slot].bio = NULL;
+
        if (mddev->ro == 0) {
                freeze_array(conf);
                fix_read_error(conf, mddev, r10_bio);
                unfreeze_array(conf);
-       }
+       } else
+               r10_bio->devs[slot].bio = IO_BLOCKED;
+
        rdev_dec_pending(rdev, mddev);
 
-       bio = r10_bio->devs[slot].bio;
-       bdevname(bio->bi_bdev, b);
-       r10_bio->devs[slot].bio =
-               mddev->ro ? IO_BLOCKED : NULL;
 read_more:
        rdev = read_balance(conf, r10_bio, &max_sectors);
        if (rdev == NULL) {
@@ -2318,13 +2339,10 @@ read_more:
                       mdname(mddev), b,
                       (unsigned long long)r10_bio->sector);
                raid_end_bio_io(r10_bio);
-               bio_put(bio);
                return;
        }
 
        do_sync = (r10_bio->master_bio->bi_rw & REQ_SYNC);
-       if (bio)
-               bio_put(bio);
        slot = r10_bio->read_slot;
        printk_ratelimited(
                KERN_ERR
@@ -2360,7 +2378,6 @@ read_more:
                        mbio->bi_phys_segments++;
                spin_unlock_irq(&conf->device_lock);
                generic_make_request(bio);
-               bio = NULL;
 
                r10_bio = mempool_alloc(conf->r10bio_pool,
                                        GFP_NOIO);
@@ -3243,7 +3260,6 @@ static int run(struct mddev *mddev)
                        disk->rdev = rdev;
                }
 
-               disk->rdev = rdev;
                disk_stack_limits(mddev->gendisk, rdev->bdev,
                                  rdev->data_offset << 9);
                /* as we don't honour merge_bvec_fn, we must never risk
index 53e2a80f42facb931f56c4adcde9221f5b5c69e1..d295941c9a3db63ab75408470ac8edfefbdb2cb2 100644 (file)
@@ -956,11 +956,12 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
        return ret;
 
 out_freeirq:
-       if (ab8500->irq_base) {
+       if (ab8500->irq_base)
                free_irq(ab8500->irq, ab8500);
 out_removeirq:
+       if (ab8500->irq_base)
                ab8500_irq_remove(ab8500);
-       }
+
        return ret;
 }
 
index 0f5922812bffdee8e3e892cab978052548d92114..411f523d4878bd1cec6f8783ca6c99d6b57b669e 100644 (file)
@@ -123,7 +123,7 @@ static int mfd_add_device(struct device *parent, int id,
                }
 
                if (!cell->ignore_resource_conflicts) {
-                       ret = acpi_check_resource_conflict(res);
+                       ret = acpi_check_resource_conflict(&res[r]);
                        if (ret)
                                goto fail_res;
                }
index e075c113eec6f7d77a67b5ca1eb145abe8eebbdf..caadabeed8e94d59ae55fd8dbde84b37014769bb 100644 (file)
@@ -105,7 +105,7 @@ static int s5m87xx_i2c_probe(struct i2c_client *i2c,
        s5m87xx->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR);
        i2c_set_clientdata(s5m87xx->rtc, s5m87xx);
 
-       if (pdata->cfg_pmic_irq)
+       if (pdata && pdata->cfg_pmic_irq)
                pdata->cfg_pmic_irq();
 
        s5m_irq_init(s5m87xx);
index 01cf5012a08fb26c3b561fde99341d6ab84749e2..4392f6bca156e20a71d7acb8cce0b9316db42753 100644 (file)
@@ -168,7 +168,7 @@ static int tps65910_i2c_probe(struct i2c_client *i2c,
                goto err;
 
        init_data->irq = pmic_plat_data->irq;
-       init_data->irq_base = pmic_plat_data->irq;
+       init_data->irq_base = pmic_plat_data->irq_base;
 
        tps65910_gpio_init(tps65910, pmic_plat_data->gpio_base);
 
index 5fec23a9ac039f34eaf6cf902acbfb6521aa7ab4..74fd8cb5f37224e576f58398c20fda9f4884d9e7 100644 (file)
@@ -151,7 +151,7 @@ int tps65912_device_init(struct tps65912 *tps65912)
                goto err;
 
        init_data->irq = pmic_plat_data->irq;
-       init_data->irq_base = pmic_plat_data->irq;
+       init_data->irq_base = pmic_plat_data->irq_base;
        ret = tps65912_irq_init(tps65912, init_data->irq, init_data);
        if (ret < 0)
                goto err;
index 8a1fafd0bf7d129184e8910b73a0848954dcf42c..9fd01bf63c510eafab2c1efc987728576aa54f5e 100644 (file)
@@ -496,7 +496,6 @@ int wm8350_irq_init(struct wm8350 *wm8350, int irq,
 
        mutex_init(&wm8350->irq_lock);
        wm8350->chip_irq = irq;
-       wm8350->irq_base = pdata->irq_base;
 
        if (pdata && pdata->irq_base > 0)
                irq_base = pdata->irq_base;
index f117e7fb932194fc174ed52439dadcd57e81684c..a04b3c108c8ca38a06f54ac946f77ce4ec920f0c 100644 (file)
@@ -256,6 +256,20 @@ static int wm8994_suspend(struct device *dev)
                break;
        }
 
+       switch (wm8994->type) {
+       case WM1811:
+               ret = wm8994_reg_read(wm8994, WM8994_ANTIPOP_2);
+               if (ret < 0) {
+                       dev_err(dev, "Failed to read jackdet: %d\n", ret);
+               } else if (ret & WM1811_JACKDET_MODE_MASK) {
+                       dev_dbg(dev, "CODEC still active, ignoring suspend\n");
+                       return 0;
+               }
+               break;
+       default:
+               break;
+       }
+
        /* Disable LDO pulldowns while the device is suspended if we
         * don't know that something will be driving them. */
        if (!wm8994->ldo_ena_always_driven)
index c598ae69b8ff052584c94e75b44db9f07ea8d694..bc0c5096539a5bdbd874ef99babdd60dbf17a0c0 100644 (file)
@@ -806,6 +806,7 @@ static bool wm1811_readable_register(struct device *dev, unsigned int reg)
        case WM8994_DC_SERVO_2:
        case WM8994_DC_SERVO_READBACK:
        case WM8994_DC_SERVO_4:
+       case WM8994_DC_SERVO_4E:
        case WM8994_ANALOGUE_HP_1:
        case WM8958_MIC_DETECT_1:
        case WM8958_MIC_DETECT_2:
index 19fc7c1cb428c47f822254c2d748b7fe572b2da3..f428d86bfc103256ccd48f50436d23d6bd4d48a7 100644 (file)
@@ -984,9 +984,9 @@ static int __init c2port_init(void)
                " - (C) 2007 Rodolfo Giometti\n");
 
        c2port_class = class_create(THIS_MODULE, "c2port");
-       if (!c2port_class) {
+       if (IS_ERR(c2port_class)) {
                printk(KERN_ERR "c2port: failed to allocate class\n");
-               return -ENOMEM;
+               return PTR_ERR(c2port_class);
        }
        c2port_class->dev_attrs = c2port_attrs;
 
index 690255c7d4dcc8c407e7b0852216edab75f4ef31..132378b89d76a0072fe31b7f436975525d04e353 100644 (file)
@@ -2068,6 +2068,9 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
         */
        mmc_hw_reset_for_init(host);
 
+       /* Initialization should be done at 3.3 V I/O voltage. */
+       mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0);
+
        /*
         * sdio_reset sends CMD52 to reset card.  Since we do not know
         * if the card is being re-initialized, just send it.  CMD52
index 30055f2b0d445b3e0c08ed131f939146fef68626..c3704e293a7b30d52c9cc1893da88a0e4844131b 100644 (file)
@@ -238,10 +238,10 @@ static inline void mmc_host_clk_init(struct mmc_host *host)
        /* Hold MCI clock for 8 cycles by default */
        host->clk_delay = 8;
        /*
-        * Default clock gating delay is 200ms.
+        * Default clock gating delay is 0ms to avoid wasting power.
         * This value can be tuned by writing into sysfs entry.
         */
-       host->clkgate_delay = 200;
+       host->clkgate_delay = 0;
        host->clk_gated = false;
        INIT_DELAYED_WORK(&host->clk_gate_work, mmc_host_clk_gate_work);
        spin_lock_init(&host->clk_lock);
index a48066344fa87316997b0bcca501d0842ea7e8a1..2b9ed1401dc439bf1dd29e4aa751f74e0175bc93 100644 (file)
@@ -816,6 +816,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
        if (!mmc_host_is_spi(host))
                mmc_set_bus_mode(host, MMC_BUSMODE_OPENDRAIN);
 
+       /* Initialization should be done at 3.3 V I/O voltage. */
+       mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0);
+
        /*
         * Since we're changing the OCR value, we seem to
         * need to tell some cards to go back to the idle
index 5017f9354ce28af6a67418d1ce0a2c438ed07edd..c272c6868ecf6d11a39c3cf2be99f1257fccd026 100644 (file)
@@ -911,6 +911,9 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
        BUG_ON(!host);
        WARN_ON(!host->claimed);
 
+       /* The initialization should be done at 3.3 V I/O voltage. */
+       mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0);
+
        err = mmc_sd_get_cid(host, ocr, cid, &rocr);
        if (err)
                return err;
@@ -1156,11 +1159,6 @@ int mmc_attach_sd(struct mmc_host *host)
        BUG_ON(!host);
        WARN_ON(!host->claimed);
 
-       /* Make sure we are at 3.3V signalling voltage */
-       err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, false);
-       if (err)
-               return err;
-
        /* Disable preset value enable if already set since last time */
        if (host->ops->enable_preset_value) {
                mmc_host_clk_hold(host);
index 12cde6ee17f50732ac5cd05f6843928abf87d0c9..2c7c83f832d289c25eaf83cf4d7ef32d420fb002 100644 (file)
@@ -585,6 +585,9 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
         * Inform the card of the voltage
         */
        if (!powered_resume) {
+               /* The initialization should be done at 3.3 V I/O voltage. */
+               mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0);
+
                err = mmc_send_io_op_cond(host, host->ocr, &ocr);
                if (err)
                        goto err;
@@ -996,6 +999,11 @@ static int mmc_sdio_power_restore(struct mmc_host *host)
         * With these steps taken, mmc_select_voltage() is also required to
         * restore the correct voltage setting of the card.
         */
+
+       /* The initialization should be done at 3.3 V I/O voltage. */
+       if (!mmc_card_keep_power(host))
+               mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0);
+
        sdio_reset(host);
        mmc_go_idle(host);
        mmc_send_if_cond(host, host->ocr_avail);
index 6985cdb0bb26e641fb340c0218d331e48844614a..e4449a54ae8f9fc68c3d9f719fe3a09e3e028adf 100644 (file)
@@ -1948,12 +1948,12 @@ static bool atmci_filter(struct dma_chan *chan, void *slave)
        }
 }
 
-static void atmci_configure_dma(struct atmel_mci *host)
+static bool atmci_configure_dma(struct atmel_mci *host)
 {
        struct mci_platform_data        *pdata;
 
        if (host == NULL)
-               return;
+               return false;
 
        pdata = host->pdev->dev.platform_data;
 
@@ -1970,12 +1970,15 @@ static void atmci_configure_dma(struct atmel_mci *host)
                host->dma.chan =
                        dma_request_channel(mask, atmci_filter, pdata->dma_slave);
        }
-       if (!host->dma.chan)
-               dev_notice(&host->pdev->dev, "DMA not available, using PIO\n");
-       else
+       if (!host->dma.chan) {
+               dev_warn(&host->pdev->dev, "no DMA channel available\n");
+               return false;
+       } else {
                dev_info(&host->pdev->dev,
                                        "Using %s for DMA transfers\n",
                                        dma_chan_name(host->dma.chan));
+               return true;
+       }
 }
 
 static inline unsigned int atmci_get_version(struct atmel_mci *host)
@@ -2085,8 +2088,7 @@ static int __init atmci_probe(struct platform_device *pdev)
 
        /* Get MCI capabilities and set operations according to it */
        atmci_get_cap(host);
-       if (host->caps.has_dma) {
-               dev_info(&pdev->dev, "using DMA\n");
+       if (host->caps.has_dma && atmci_configure_dma(host)) {
                host->prepare_data = &atmci_prepare_data_dma;
                host->submit_data = &atmci_submit_data_dma;
                host->stop_transfer = &atmci_stop_transfer_dma;
@@ -2096,15 +2098,12 @@ static int __init atmci_probe(struct platform_device *pdev)
                host->submit_data = &atmci_submit_data_pdc;
                host->stop_transfer = &atmci_stop_transfer_pdc;
        } else {
-               dev_info(&pdev->dev, "no DMA, no PDC\n");
+               dev_info(&pdev->dev, "using PIO\n");
                host->prepare_data = &atmci_prepare_data;
                host->submit_data = &atmci_submit_data;
                host->stop_transfer = &atmci_stop_transfer;
        }
 
-       if (host->caps.has_dma)
-               atmci_configure_dma(host);
-
        platform_set_drvdata(pdev, host);
 
        /* We need at least one slot to succeed */
index 0d955ffaf44e2c3ec5961f966687da3e675819d9..11e589cd8233e5f7438f7240d14c8f7897fbf8d7 100644 (file)
@@ -1271,12 +1271,13 @@ static int __devinit mmci_probe(struct amba_device *dev,
        /*
         * Block size can be up to 2048 bytes, but must be a power of two.
         */
-       mmc->max_blk_size = 2048;
+       mmc->max_blk_size = 1 << 11;
 
        /*
-        * No limit on the number of blocks transferred.
+        * Limit the number of blocks transferred so that we don't overflow
+        * the maximum request size.
         */
-       mmc->max_blk_count = mmc->max_req_size;
+       mmc->max_blk_count = mmc->max_req_size >> 11;
 
        spin_lock_init(&host->lock);
 
index d601e41af282105ad5c3a86d30d569dfef3def8c..0be4e2013632f97ce4dddc489212c2ed6f7c4985 100644 (file)
@@ -269,8 +269,9 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
                imx_data->scratchpad = val;
                return;
        case SDHCI_COMMAND:
-               if ((host->cmd->opcode == MMC_STOP_TRANSMISSION)
-                       && (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT))
+               if ((host->cmd->opcode == MMC_STOP_TRANSMISSION ||
+                    host->cmd->opcode == MMC_SET_BLOCK_COUNT) &&
+                   (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT))
                        val |= SDHCI_CMD_ABORTCMD;
 
                if (is_imx6q_usdhc(imx_data)) {
index c8afd62239e98fa7c7cf5eb86f92cdbaa80935fe..9a66e2a910ae21f586ff59439b8116fe891d4c95 100644 (file)
@@ -1031,7 +1031,7 @@ static void cfhsi_setup(struct net_device *dev)
        dev->netdev_ops = &cfhsi_ops;
        dev->type = ARPHRD_CAIF;
        dev->flags = IFF_POINTOPOINT | IFF_NOARP;
-       dev->mtu = CFHSI_MAX_PAYLOAD_SZ;
+       dev->mtu = CFHSI_MAX_CAIF_FRAME_SZ;
        dev->tx_queue_len = 0;
        dev->destructor = free_netdev;
        skb_queue_head_init(&cfhsi->qhead);
index 0f21a9b4cdd41f3c44c336b743cdacbb112389d9..1ef0c9275deefee39bdca1df04d7240b6adeba52 100644 (file)
@@ -1711,7 +1711,7 @@ static irqreturn_t atl1c_intr(int irq, void *data)
                                        "atl1c hardware error (status = 0x%x)\n",
                                        status & ISR_ERROR);
                        /* reset MAC */
-                       adapter->work_event |= ATL1C_WORK_EVENT_RESET;
+                       set_bit(ATL1C_WORK_EVENT_RESET, &adapter->work_event);
                        schedule_work(&adapter->common_task);
                        return IRQ_HANDLED;
                }
index bc236b6a7a91bacda6731e67014edf7ef5f89484..b0657466041d733900199124ffab0f6dbaf088af 100644 (file)
@@ -5595,7 +5595,7 @@ static void tg3_tx(struct tg3_napi *tnapi)
                }
        }
 
-       netdev_completed_queue(tp->dev, pkts_compl, bytes_compl);
+       netdev_tx_completed_queue(txq, pkts_compl, bytes_compl);
 
        tnapi->tx_cons = sw_idx;
 
@@ -6971,7 +6971,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
        }
 
        skb_tx_timestamp(skb);
-       netdev_sent_queue(tp->dev, skb->len);
+       netdev_tx_sent_queue(txq, skb->len);
 
        /* Sync BD data before updating mailbox */
        wmb();
@@ -7396,8 +7396,8 @@ static void tg3_free_rings(struct tg3 *tp)
 
                        dev_kfree_skb_any(skb);
                }
+               netdev_tx_reset_queue(netdev_get_tx_queue(tp->dev, j));
        }
-       netdev_reset_queue(tp->dev);
 }
 
 /* Initialize tx/rx rings for packet processing.
index 1d889427073f142f804461e75252869bf6c788f8..05ff076af06d92fe024199cba9f68f6e1847b299 100644 (file)
@@ -196,6 +196,8 @@ static DEFINE_PCI_DEVICE_TABLE(cxgb4_pci_tbl) = {
        CH_DEVICE(0x4408, 4),
        CH_DEVICE(0x4409, 4),
        CH_DEVICE(0x440a, 4),
+       CH_DEVICE(0x440d, 4),
+       CH_DEVICE(0x440e, 4),
        { 0, }
 };
 
index 3f580c0c28a6abf21006f6c56a5c67c5fbdaebe5..25e3308fc9d8af2307cec26f3e7ea3ba69b6f33a 100644 (file)
@@ -2890,6 +2890,8 @@ static struct pci_device_id cxgb4vf_pci_tbl[] = {
        CH_DEVICE(0x4808, 0),   /* T420-cx */
        CH_DEVICE(0x4809, 0),   /* T420-bt */
        CH_DEVICE(0x480a, 0),   /* T404-bt */
+       CH_DEVICE(0x480d, 0),   /* T480-cr */
+       CH_DEVICE(0x480e, 0),   /* T440-lp-cr */
        { 0, }
 };
 
index cf1fb4b9a4adff6fbd5904fd31d4dfdef3c97bf9..afe9b1662b8cef8c2ba09c73febdca3583f2642a 100644 (file)
@@ -32,7 +32,7 @@
 
 #define DRV_NAME               "enic"
 #define DRV_DESCRIPTION                "Cisco VIC Ethernet NIC Driver"
-#define DRV_VERSION            "2.1.1.38"
+#define DRV_VERSION            "2.1.1.39"
 #define DRV_COPYRIGHT          "Copyright 2008-2011 Cisco Systems, Inc"
 
 #define ENIC_BARS_MAX          6
index 9080ed6516662c82b6db3f3fb6df007b36375bca..77b4e873f91c04fa8f6d3d3853c63513c1ea2af0 100644 (file)
@@ -1069,7 +1069,7 @@ static int enic_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
        if (err)
                return err;
 
-       if (is_valid_ether_addr(mac)) {
+       if (is_valid_ether_addr(mac) || is_zero_ether_addr(mac)) {
                if (vf == PORT_SELF_VF) {
                        memcpy(pp->vf_mac, mac, ETH_ALEN);
                        return 0;
index 8b73dd4724758758725f8ec4d773cbda953c54bf..3516e17a399d3137ccf0e2eea06318c0171aeba4 100644 (file)
@@ -336,7 +336,9 @@ static struct rtnl_link_stats64 *ehea_get_stats64(struct net_device *dev,
        stats->tx_bytes = tx_bytes;
        stats->rx_packets = rx_packets;
 
-       return &port->stats;
+       stats->multicast = port->stats.multicast;
+       stats->rx_errors = port->stats.rx_errors;
+       return stats;
 }
 
 static void ehea_update_stats(struct work_struct *work)
index dac7ffb4eaf17cc3a5b6afb48969a7e0fa441b64..a0fe6e3fce61a5ad7b4b17b7de723e0798ab9086 100644 (file)
@@ -434,6 +434,11 @@ static inline u32 emac_iff2rmr(struct net_device *ndev)
        else if (!netdev_mc_empty(ndev))
                r |= EMAC_RMR_MAE;
 
+       if (emac_has_feature(dev, EMAC_APM821XX_REQ_JUMBO_FRAME_SIZE)) {
+               r &= ~EMAC4_RMR_MJS_MASK;
+               r |= EMAC4_RMR_MJS(ndev->mtu);
+       }
+
        return r;
 }
 
@@ -965,6 +970,7 @@ static int emac_resize_rx_ring(struct emac_instance *dev, int new_mtu)
        int rx_sync_size = emac_rx_sync_size(new_mtu);
        int rx_skb_size = emac_rx_skb_size(new_mtu);
        int i, ret = 0;
+       int mr1_jumbo_bit_change = 0;
 
        mutex_lock(&dev->link_lock);
        emac_netif_stop(dev);
@@ -1013,7 +1019,15 @@ static int emac_resize_rx_ring(struct emac_instance *dev, int new_mtu)
        }
  skip:
        /* Check if we need to change "Jumbo" bit in MR1 */
-       if ((new_mtu > ETH_DATA_LEN) ^ (dev->ndev->mtu > ETH_DATA_LEN)) {
+       if (emac_has_feature(dev, EMAC_APM821XX_REQ_JUMBO_FRAME_SIZE)) {
+               mr1_jumbo_bit_change = (new_mtu > ETH_DATA_LEN) ||
+                               (dev->ndev->mtu > ETH_DATA_LEN);
+       } else {
+               mr1_jumbo_bit_change = (new_mtu > ETH_DATA_LEN) ^
+                               (dev->ndev->mtu > ETH_DATA_LEN);
+       }
+
+       if (mr1_jumbo_bit_change) {
                /* This is to prevent starting RX channel in emac_rx_enable() */
                set_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags);
 
@@ -2471,6 +2485,7 @@ static int __devinit emac_init_phy(struct emac_instance *dev)
 
        /* Disable any PHY features not supported by the platform */
        dev->phy.def->features &= ~dev->phy_feat_exc;
+       dev->phy.features &= ~dev->phy_feat_exc;
 
        /* Setup initial link parameters */
        if (dev->phy.features & SUPPORTED_Autoneg) {
@@ -2568,6 +2583,11 @@ static int __devinit emac_init_config(struct emac_instance *dev)
                if (of_device_is_compatible(np, "ibm,emac-405ex") ||
                    of_device_is_compatible(np, "ibm,emac-405exr"))
                        dev->features |= EMAC_FTR_440EP_PHY_CLK_FIX;
+               if (of_device_is_compatible(np, "ibm,emac-apm821xx")) {
+                       dev->features |= (EMAC_APM821XX_REQ_JUMBO_FRAME_SIZE |
+                                         EMAC_FTR_APM821XX_NO_HALF_DUPLEX |
+                                         EMAC_FTR_460EX_PHY_CLK_FIX);
+               }
        } else if (of_device_is_compatible(np, "ibm,emac4")) {
                dev->features |= EMAC_FTR_EMAC4;
                if (of_device_is_compatible(np, "ibm,emac-440gx"))
@@ -2816,6 +2836,13 @@ static int __devinit emac_probe(struct platform_device *ofdev)
        dev->stop_timeout = STOP_TIMEOUT_100;
        INIT_DELAYED_WORK(&dev->link_work, emac_link_timer);
 
+       /* Some SoCs like APM821xx does not support Half Duplex mode. */
+       if (emac_has_feature(dev, EMAC_FTR_APM821XX_NO_HALF_DUPLEX)) {
+               dev->phy_feat_exc = (SUPPORTED_1000baseT_Half |
+                                    SUPPORTED_100baseT_Half |
+                                    SUPPORTED_10baseT_Half);
+       }
+
        /* Find PHY if any */
        err = emac_init_phy(dev);
        if (err != 0)
index bade29690c716a8e34afe5af10b0bb664e81fdf0..70074792bdefdc24c30aca7b4181073dc9bb7ffc 100644 (file)
@@ -325,7 +325,14 @@ struct emac_instance {
  * Set if we need phy clock workaround for 460ex or 460gt
  */
 #define EMAC_FTR_460EX_PHY_CLK_FIX     0x00000400
-
+/*
+ * APM821xx requires Jumbo frame size set explicitly
+ */
+#define EMAC_APM821XX_REQ_JUMBO_FRAME_SIZE     0x00000800
+/*
+ * APM821xx does not support Half Duplex mode
+ */
+#define EMAC_FTR_APM821XX_NO_HALF_DUPLEX       0x00001000
 
 /* Right now, we don't quite handle the always/possible masks on the
  * most optimal way as we don't have a way to say something like
@@ -353,7 +360,9 @@ enum {
            EMAC_FTR_NO_FLOW_CONTROL_40x |
 #endif
        EMAC_FTR_460EX_PHY_CLK_FIX |
-       EMAC_FTR_440EP_PHY_CLK_FIX,
+       EMAC_FTR_440EP_PHY_CLK_FIX |
+       EMAC_APM821XX_REQ_JUMBO_FRAME_SIZE |
+       EMAC_FTR_APM821XX_NO_HALF_DUPLEX,
 };
 
 static inline int emac_has_feature(struct emac_instance *dev,
index b44bd243fb58db704e2c967e290f2b74984710d6..5afcc27ceebb6872bfb9cd2cda8abda2fcdae934 100644 (file)
@@ -212,6 +212,8 @@ struct emac_regs {
 #define EMAC4_RMR_RFAF_64_1024         0x00000006
 #define EMAC4_RMR_RFAF_128_2048                0x00000007
 #define EMAC4_RMR_BASE                 EMAC4_RMR_RFAF_128_2048
+#define EMAC4_RMR_MJS_MASK              0x0001fff8
+#define EMAC4_RMR_MJS(s)                (((s) << 3) & EMAC4_RMR_MJS_MASK)
 
 /* EMACx_ISR & EMACx_ISER */
 #define EMAC4_ISR_TXPE                 0x20000000
index 9fe4f94c6da7266cb80821db661de4b7abf6997d..31b455a49273f1a3d877f5c7e8cea1515de1963a 100644 (file)
@@ -1062,6 +1062,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
        memset(priv, 0, sizeof(struct mlx4_en_priv));
        priv->dev = dev;
        priv->mdev = mdev;
+       priv->ddev = &mdev->pdev->dev;
        priv->prof = prof;
        priv->port = port;
        priv->port_up = false;
index d703ef2c9c91cfdb2f2d642fcdc0766b95873b5c..9adbd53da525ba59b5d9f1378e347b029533f0d7 100644 (file)
@@ -48,7 +48,6 @@ static int mlx4_en_alloc_frag(struct mlx4_en_priv *priv,
                              struct mlx4_en_rx_alloc *ring_alloc,
                              int i)
 {
-       struct mlx4_en_dev *mdev = priv->mdev;
        struct mlx4_en_frag_info *frag_info = &priv->frag_info[i];
        struct mlx4_en_rx_alloc *page_alloc = &ring_alloc[i];
        struct page *page;
@@ -72,7 +71,7 @@ static int mlx4_en_alloc_frag(struct mlx4_en_priv *priv,
                skb_frags[i].offset = page_alloc->offset;
                page_alloc->offset += frag_info->frag_stride;
        }
-       dma = pci_map_single(mdev->pdev, page_address(skb_frags[i].page) +
+       dma = dma_map_single(priv->ddev, page_address(skb_frags[i].page) +
                             skb_frags[i].offset, frag_info->frag_size,
                             PCI_DMA_FROMDEVICE);
        rx_desc->data[i].addr = cpu_to_be64(dma);
@@ -186,7 +185,6 @@ static void mlx4_en_free_rx_desc(struct mlx4_en_priv *priv,
                                 struct mlx4_en_rx_ring *ring,
                                 int index)
 {
-       struct mlx4_en_dev *mdev = priv->mdev;
        struct page_frag *skb_frags;
        struct mlx4_en_rx_desc *rx_desc = ring->buf + (index << ring->log_stride);
        dma_addr_t dma;
@@ -198,7 +196,7 @@ static void mlx4_en_free_rx_desc(struct mlx4_en_priv *priv,
                dma = be64_to_cpu(rx_desc->data[nr].addr);
 
                en_dbg(DRV, priv, "Unmapping buffer at dma:0x%llx\n", (u64) dma);
-               pci_unmap_single(mdev->pdev, dma, skb_frags[nr].size,
+               dma_unmap_single(priv->ddev, dma, skb_frags[nr].size,
                                 PCI_DMA_FROMDEVICE);
                put_page(skb_frags[nr].page);
        }
@@ -412,7 +410,6 @@ static int mlx4_en_complete_rx_desc(struct mlx4_en_priv *priv,
                                    int length)
 {
        struct skb_frag_struct *skb_frags_rx = skb_shinfo(skb)->frags;
-       struct mlx4_en_dev *mdev = priv->mdev;
        struct mlx4_en_frag_info *frag_info;
        int nr;
        dma_addr_t dma;
@@ -435,7 +432,7 @@ static int mlx4_en_complete_rx_desc(struct mlx4_en_priv *priv,
                        goto fail;
 
                /* Unmap buffer */
-               pci_unmap_single(mdev->pdev, dma, skb_frag_size(&skb_frags_rx[nr]),
+               dma_unmap_single(priv->ddev, dma, skb_frag_size(&skb_frags_rx[nr]),
                                 PCI_DMA_FROMDEVICE);
        }
        /* Adjust size of last fragment to match actual length */
@@ -461,7 +458,6 @@ static struct sk_buff *mlx4_en_rx_skb(struct mlx4_en_priv *priv,
                                      struct mlx4_en_rx_alloc *page_alloc,
                                      unsigned int length)
 {
-       struct mlx4_en_dev *mdev = priv->mdev;
        struct sk_buff *skb;
        void *va;
        int used_frags;
@@ -483,10 +479,10 @@ static struct sk_buff *mlx4_en_rx_skb(struct mlx4_en_priv *priv,
                /* We are copying all relevant data to the skb - temporarily
                 * synch buffers for the copy */
                dma = be64_to_cpu(rx_desc->data[0].addr);
-               dma_sync_single_for_cpu(&mdev->pdev->dev, dma, length,
+               dma_sync_single_for_cpu(priv->ddev, dma, length,
                                        DMA_FROM_DEVICE);
                skb_copy_to_linear_data(skb, va, length);
-               dma_sync_single_for_device(&mdev->pdev->dev, dma, length,
+               dma_sync_single_for_device(priv->ddev, dma, length,
                                           DMA_FROM_DEVICE);
                skb->tail += length;
        } else {
@@ -914,7 +910,7 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv)
        rss_context->flags = rss_mask;
        rss_context->hash_fn = MLX4_RSS_HASH_TOP;
        for (i = 0; i < 10; i++)
-               rss_context->rss_key[i] = rsskey[i];
+               rss_context->rss_key[i] = cpu_to_be32(rsskey[i]);
 
        err = mlx4_qp_to_ready(mdev->dev, &priv->res.mtt, &context,
                               &rss_map->indir_qp, &rss_map->indir_state);
index 2fd51405a509cfa5c296f91184e217755377c840..17968244c399509b169540388b8b1d971739eef1 100644 (file)
@@ -198,7 +198,6 @@ static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
                                struct mlx4_en_tx_ring *ring,
                                int index, u8 owner)
 {
-       struct mlx4_en_dev *mdev = priv->mdev;
        struct mlx4_en_tx_info *tx_info = &ring->tx_info[index];
        struct mlx4_en_tx_desc *tx_desc = ring->buf + index * TXBB_SIZE;
        struct mlx4_wqe_data_seg *data = (void *) tx_desc + tx_info->data_offset;
@@ -214,7 +213,7 @@ static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
        if (likely((void *) tx_desc + tx_info->nr_txbb * TXBB_SIZE <= end)) {
                if (!tx_info->inl) {
                        if (tx_info->linear) {
-                               pci_unmap_single(mdev->pdev,
+                               dma_unmap_single(priv->ddev,
                                        (dma_addr_t) be64_to_cpu(data->addr),
                                         be32_to_cpu(data->byte_count),
                                         PCI_DMA_TODEVICE);
@@ -223,7 +222,7 @@ static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
 
                        for (i = 0; i < frags; i++) {
                                frag = &skb_shinfo(skb)->frags[i];
-                               pci_unmap_page(mdev->pdev,
+                               dma_unmap_page(priv->ddev,
                                        (dma_addr_t) be64_to_cpu(data[i].addr),
                                        skb_frag_size(frag), PCI_DMA_TODEVICE);
                        }
@@ -241,7 +240,7 @@ static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
                        }
 
                        if (tx_info->linear) {
-                               pci_unmap_single(mdev->pdev,
+                               dma_unmap_single(priv->ddev,
                                        (dma_addr_t) be64_to_cpu(data->addr),
                                         be32_to_cpu(data->byte_count),
                                         PCI_DMA_TODEVICE);
@@ -253,7 +252,7 @@ static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
                                if ((void *) data >= end)
                                        data = ring->buf;
                                frag = &skb_shinfo(skb)->frags[i];
-                               pci_unmap_page(mdev->pdev,
+                               dma_unmap_page(priv->ddev,
                                        (dma_addr_t) be64_to_cpu(data->addr),
                                         skb_frag_size(frag), PCI_DMA_TODEVICE);
                                ++data;
@@ -585,7 +584,7 @@ u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb)
        return skb_tx_hash(dev, skb);
 }
 
-static void mlx4_bf_copy(unsigned long *dst, unsigned long *src, unsigned bytecnt)
+static void mlx4_bf_copy(void __iomem *dst, unsigned long *src, unsigned bytecnt)
 {
        __iowrite64_copy(dst, src, bytecnt / 8);
 }
@@ -686,8 +685,8 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
 
        /* Copy dst mac address to wqe */
        ethh = (struct ethhdr *)skb->data;
-       tx_desc->ctrl.srcrb_flags16[0] = get_unaligned((u16 *)ethh->h_dest);
-       tx_desc->ctrl.imm = get_unaligned((u32 *)(ethh->h_dest + 2));
+       tx_desc->ctrl.srcrb_flags16[0] = get_unaligned((__be16 *)ethh->h_dest);
+       tx_desc->ctrl.imm = get_unaligned((__be32 *)(ethh->h_dest + 2));
        /* Handle LSO (TSO) packets */
        if (lso_header_size) {
                /* Mark opcode as LSO */
@@ -733,7 +732,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
                /* Map fragments */
                for (i = skb_shinfo(skb)->nr_frags - 1; i >= 0; i--) {
                        frag = &skb_shinfo(skb)->frags[i];
-                       dma = skb_frag_dma_map(&mdev->dev->pdev->dev, frag,
+                       dma = skb_frag_dma_map(priv->ddev, frag,
                                               0, skb_frag_size(frag),
                                               DMA_TO_DEVICE);
                        data->addr = cpu_to_be64(dma);
@@ -745,7 +744,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
 
                /* Map linear part */
                if (tx_info->linear) {
-                       dma = pci_map_single(mdev->dev->pdev, skb->data + lso_header_size,
+                       dma = dma_map_single(priv->ddev, skb->data + lso_header_size,
                                             skb_headlen(skb) - lso_header_size, PCI_DMA_TODEVICE);
                        data->addr = cpu_to_be64(dma);
                        data->lkey = cpu_to_be32(mdev->mr.key);
index 9ea7cabcaf3c8839d86f96a9ee4ad68c102caf66..2a02ba522e60c16e0ed01ca7418e348e1671f802 100644 (file)
@@ -685,16 +685,6 @@ int mlx4_QUERY_PORT_wrapper(struct mlx4_dev *dev, int slave,
        return err;
 }
 
-int mlx4_QUERY_PORT(struct mlx4_dev *dev, void *ptr, u8 port)
-{
-       struct mlx4_cmd_mailbox *outbox = ptr;
-
-       return mlx4_cmd_box(dev, 0, outbox->dma, port, 0,
-                           MLX4_CMD_QUERY_PORT, MLX4_CMD_TIME_CLASS_B,
-                           MLX4_CMD_WRAPPED);
-}
-EXPORT_SYMBOL_GPL(mlx4_QUERY_PORT);
-
 int mlx4_map_cmd(struct mlx4_dev *dev, u16 op, struct mlx4_icm *icm, u64 virt)
 {
        struct mlx4_cmd_mailbox *mailbox;
index d60335f3c473382ea80f4a3f2c1c819a50391c33..9e2b911a12304ee88f5934c1c895d394d662e05a 100644 (file)
@@ -453,7 +453,7 @@ struct mlx4_en_priv {
        int base_qpn;
 
        struct mlx4_en_rss_map rss_map;
-       u32 ctrl_flags;
+       __be32 ctrl_flags;
        u32 flags;
 #define MLX4_EN_FLAG_PROMISC   0x1
 #define MLX4_EN_FLAG_MC_PROMISC        0x2
@@ -482,6 +482,7 @@ struct mlx4_en_priv {
        struct mlx4_en_stat_out_mbox hw_stats;
        int vids[128];
        bool wol;
+       struct device *ddev;
 };
 
 enum mlx4_en_wol {
@@ -552,10 +553,6 @@ void mlx4_en_rx_irq(struct mlx4_cq *mcq);
 
 int mlx4_SET_MCAST_FLTR(struct mlx4_dev *dev, u8 port, u64 mac, u64 clear, u8 mode);
 int mlx4_SET_VLAN_FLTR(struct mlx4_dev *dev, struct mlx4_en_priv *priv);
-int mlx4_SET_PORT_general(struct mlx4_dev *dev, u8 port, int mtu,
-                         u8 pptx, u8 pfctx, u8 pprx, u8 pfcrx);
-int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn,
-                          u8 promisc);
 
 int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset);
 int mlx4_en_QUERY_PORT(struct mlx4_en_dev *mdev, u8 port);
index 25a80d71fb2ab476df010be63a6f597f0b917319..32e2b6616f3db44340718f35cc8c32fd05537c95 100644 (file)
@@ -304,30 +304,7 @@ static int mlx4_HW2SW_MPT(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox
                            MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED);
 }
 
-int mlx4_mr_reserve_range(struct mlx4_dev *dev, int cnt, int align,
-                         u32 *base_mridx)
-{
-       struct mlx4_priv *priv = mlx4_priv(dev);
-       u32 mridx;
-
-       mridx = mlx4_bitmap_alloc_range(&priv->mr_table.mpt_bitmap, cnt, align);
-       if (mridx == -1)
-               return -ENOMEM;
-
-       *base_mridx = mridx;
-       return 0;
-
-}
-EXPORT_SYMBOL_GPL(mlx4_mr_reserve_range);
-
-void mlx4_mr_release_range(struct mlx4_dev *dev, u32 base_mridx, int cnt)
-{
-       struct mlx4_priv *priv = mlx4_priv(dev);
-       mlx4_bitmap_free_range(&priv->mr_table.mpt_bitmap, base_mridx, cnt);
-}
-EXPORT_SYMBOL_GPL(mlx4_mr_release_range);
-
-int mlx4_mr_alloc_reserved(struct mlx4_dev *dev, u32 mridx, u32 pd,
+static int mlx4_mr_alloc_reserved(struct mlx4_dev *dev, u32 mridx, u32 pd,
                           u64 iova, u64 size, u32 access, int npages,
                           int page_shift, struct mlx4_mr *mr)
 {
@@ -340,7 +317,6 @@ int mlx4_mr_alloc_reserved(struct mlx4_dev *dev, u32 mridx, u32 pd,
 
        return mlx4_mtt_init(dev, npages, page_shift, &mr->mtt);
 }
-EXPORT_SYMBOL_GPL(mlx4_mr_alloc_reserved);
 
 static int mlx4_WRITE_MTT(struct mlx4_dev *dev,
                          struct mlx4_cmd_mailbox *mailbox,
@@ -457,7 +433,7 @@ int mlx4_mr_alloc(struct mlx4_dev *dev, u32 pd, u64 iova, u64 size, u32 access,
 }
 EXPORT_SYMBOL_GPL(mlx4_mr_alloc);
 
-void mlx4_mr_free_reserved(struct mlx4_dev *dev, struct mlx4_mr *mr)
+static void mlx4_mr_free_reserved(struct mlx4_dev *dev, struct mlx4_mr *mr)
 {
        int err;
 
@@ -472,7 +448,6 @@ void mlx4_mr_free_reserved(struct mlx4_dev *dev, struct mlx4_mr *mr)
        }
        mlx4_mtt_cleanup(dev, &mr->mtt);
 }
-EXPORT_SYMBOL_GPL(mlx4_mr_free_reserved);
 
 void mlx4_mr_free(struct mlx4_dev *dev, struct mlx4_mr *mr)
 {
@@ -852,46 +827,6 @@ err_free:
 }
 EXPORT_SYMBOL_GPL(mlx4_fmr_alloc);
 
-int mlx4_fmr_alloc_reserved(struct mlx4_dev *dev, u32 mridx,
-                           u32 pd, u32 access, int max_pages,
-                           int max_maps, u8 page_shift, struct mlx4_fmr *fmr)
-{
-       struct mlx4_priv *priv = mlx4_priv(dev);
-       int err = -ENOMEM;
-
-       if (page_shift < (ffs(dev->caps.page_size_cap) - 1) || page_shift >= 32)
-               return -EINVAL;
-
-       /* All MTTs must fit in the same page */
-       if (max_pages * sizeof *fmr->mtts > PAGE_SIZE)
-               return -EINVAL;
-
-       fmr->page_shift = page_shift;
-       fmr->max_pages  = max_pages;
-       fmr->max_maps   = max_maps;
-       fmr->maps = 0;
-
-       err = mlx4_mr_alloc_reserved(dev, mridx, pd, 0, 0, access, max_pages,
-                                    page_shift, &fmr->mr);
-       if (err)
-               return err;
-
-       fmr->mtts = mlx4_table_find(&priv->mr_table.mtt_table,
-                                   fmr->mr.mtt.offset,
-                                   &fmr->dma_handle);
-       if (!fmr->mtts) {
-               err = -ENOMEM;
-               goto err_free;
-       }
-
-       return 0;
-
-err_free:
-       mlx4_mr_free_reserved(dev, &fmr->mr);
-       return err;
-}
-EXPORT_SYMBOL_GPL(mlx4_fmr_alloc_reserved);
-
 int mlx4_fmr_enable(struct mlx4_dev *dev, struct mlx4_fmr *fmr)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
@@ -954,18 +889,6 @@ int mlx4_fmr_free(struct mlx4_dev *dev, struct mlx4_fmr *fmr)
 }
 EXPORT_SYMBOL_GPL(mlx4_fmr_free);
 
-int mlx4_fmr_free_reserved(struct mlx4_dev *dev, struct mlx4_fmr *fmr)
-{
-       if (fmr->maps)
-               return -EBUSY;
-
-       mlx4_mr_free_reserved(dev, &fmr->mr);
-       fmr->mr.enabled = MLX4_MR_DISABLED;
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(mlx4_fmr_free_reserved);
-
 int mlx4_SYNC_TPT(struct mlx4_dev *dev)
 {
        return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_SYNC_TPT, 1000,
index 575839dba8a2ab27e1e49e7ef79a4a71df38461d..98e776261eada0ba25f339751f6c8a8c8f93c0b4 100644 (file)
@@ -79,13 +79,14 @@ static int mlx4_uc_steer_add(struct mlx4_dev *dev, u8 port, u64 mac, int *qpn)
 {
        struct mlx4_qp qp;
        u8 gid[16] = {0};
+       __be64 be_mac;
        int err;
 
        qp.qpn = *qpn;
 
        mac &= 0xffffffffffffULL;
-       mac = cpu_to_be64(mac << 16);
-       memcpy(&gid[10], &mac, ETH_ALEN);
+       be_mac = cpu_to_be64(mac << 16);
+       memcpy(&gid[10], &be_mac, ETH_ALEN);
        gid[5] = port;
 
        err = mlx4_unicast_attach(dev, &qp, gid, 0, MLX4_PROT_ETH);
@@ -100,11 +101,12 @@ static void mlx4_uc_steer_release(struct mlx4_dev *dev, u8 port,
 {
        struct mlx4_qp qp;
        u8 gid[16] = {0};
+       __be64 be_mac;
 
        qp.qpn = qpn;
        mac &= 0xffffffffffffULL;
-       mac = cpu_to_be64(mac << 16);
-       memcpy(&gid[10], &mac, ETH_ALEN);
+       be_mac = cpu_to_be64(mac << 16);
+       memcpy(&gid[10], &be_mac, ETH_ALEN);
        gid[5] = port;
 
        mlx4_unicast_detach(dev, &qp, gid, MLX4_PROT_ETH);
index 738f950a1ce59e69c6297517882913d90f22f784..fb2b36759cbf657d66dfa7c245d49306d5a06c58 100644 (file)
@@ -151,11 +151,6 @@ static int __mlx4_qp_modify(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
                context->log_page_size   = mtt->page_shift - MLX4_ICM_PAGE_SHIFT;
        }
 
-       port = ((context->pri_path.sched_queue >> 6) & 1) + 1;
-       if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH)
-               context->pri_path.sched_queue = (context->pri_path.sched_queue &
-                                               0xc3);
-
        *(__be32 *) mailbox->buf = cpu_to_be32(optpar);
        memcpy(mailbox->buf + 8, context, sizeof *context);
 
index bfdb7af19e496285bdeff3ada8a302b71e746865..8752e6e0816922f5ecd4b441fc478b02a27fd5d2 100644 (file)
@@ -2255,8 +2255,7 @@ int mlx4_MODIFY_CQ_wrapper(struct mlx4_dev *dev, int slave,
 
        if (vhcr->op_modifier == 0) {
                err = handle_resize(dev, slave, vhcr, inbox, outbox, cmd, cq);
-               if (err)
-                       goto ex_put;
+               goto ex_put;
        }
 
        err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
index 00bc4fc968c7fa76ba3fbd18c733bc7bfb38a435..bce01641ee6b325f91ee1e29ae4414adfe981b18 100644 (file)
@@ -20,3 +20,16 @@ config PCH_GBE
          purpose use.
          ML7223/ML7831 is companion chip for Intel Atom E6xx series.
          ML7223/ML7831 is completely compatible for Intel EG20T PCH.
+
+if PCH_GBE
+
+config PCH_PTP
+       bool "PCH PTP clock support"
+       default n
+       depends on PTP_1588_CLOCK_PCH
+       ---help---
+         Say Y here if you want to use Precision Time Protocol (PTP) in the
+         driver. PTP is a method to precisely synchronize distributed clocks
+         over Ethernet networks.
+
+endif # PCH_GBE
index a09a07197eb58f65122296800959accab87b0f21..dd14915f54bb8581516329c36b3fed3d0204cfae 100644 (file)
@@ -630,6 +630,9 @@ struct pch_gbe_adapter {
        unsigned long tx_queue_len;
        bool have_msi;
        bool rx_stop_flag;
+       int hwts_tx_en;
+       int hwts_rx_en;
+       struct pci_dev *ptp_pdev;
 };
 
 extern const char pch_driver_version[];
@@ -648,6 +651,16 @@ extern void pch_gbe_free_tx_resources(struct pch_gbe_adapter *adapter,
 extern void pch_gbe_free_rx_resources(struct pch_gbe_adapter *adapter,
                                       struct pch_gbe_rx_ring *rx_ring);
 extern void pch_gbe_update_stats(struct pch_gbe_adapter *adapter);
+#ifdef CONFIG_PCH_PTP
+extern u32 pch_ch_control_read(struct pci_dev *pdev);
+extern void pch_ch_control_write(struct pci_dev *pdev, u32 val);
+extern u32 pch_ch_event_read(struct pci_dev *pdev);
+extern void pch_ch_event_write(struct pci_dev *pdev, u32 val);
+extern u32 pch_src_uuid_lo_read(struct pci_dev *pdev);
+extern u32 pch_src_uuid_hi_read(struct pci_dev *pdev);
+extern u64 pch_rx_snap_read(struct pci_dev *pdev);
+extern u64 pch_tx_snap_read(struct pci_dev *pdev);
+#endif
 
 /* pch_gbe_param.c */
 extern void pch_gbe_check_options(struct pch_gbe_adapter *adapter);
index 69a66545c8aeeff84bbc2a2826ef78f8f1a12693..8035e5ff6e060d4c208208857159c7e32c0484f0 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 1999 - 2010 Intel Corporation.
- * Copyright (C) 2010 OKI SEMICONDUCTOR CO., LTD.
+ * Copyright (C) 2010 - 2012 LAPIS SEMICONDUCTOR CO., LTD.
  *
  * This code was derived from the Intel e1000e Linux driver.
  *
 #include "pch_gbe.h"
 #include "pch_gbe_api.h"
 #include <linux/module.h>
+#ifdef CONFIG_PCH_PTP
+#include <linux/net_tstamp.h>
+#include <linux/ptp_classify.h>
+#endif
 
 #define DRV_VERSION     "1.00"
 const char pch_driver_version[] = DRV_VERSION;
@@ -95,12 +99,195 @@ const char pch_driver_version[] = DRV_VERSION;
 
 #define PCH_GBE_INT_DISABLE_ALL                0
 
+#ifdef CONFIG_PCH_PTP
+/* Macros for ieee1588 */
+#define TICKS_NS_SHIFT  5
+
+/* 0x40 Time Synchronization Channel Control Register Bits */
+#define MASTER_MODE   (1<<0)
+#define SLAVE_MODE    (0<<0)
+#define V2_MODE       (1<<31)
+#define CAP_MODE0     (0<<16)
+#define CAP_MODE2     (1<<17)
+
+/* 0x44 Time Synchronization Channel Event Register Bits */
+#define TX_SNAPSHOT_LOCKED (1<<0)
+#define RX_SNAPSHOT_LOCKED (1<<1)
+#endif
+
 static unsigned int copybreak __read_mostly = PCH_GBE_COPYBREAK_DEFAULT;
 
 static int pch_gbe_mdio_read(struct net_device *netdev, int addr, int reg);
 static void pch_gbe_mdio_write(struct net_device *netdev, int addr, int reg,
                               int data);
 
+#ifdef CONFIG_PCH_PTP
+static struct sock_filter ptp_filter[] = {
+       PTP_FILTER
+};
+
+static int pch_ptp_match(struct sk_buff *skb, u16 uid_hi, u32 uid_lo, u16 seqid)
+{
+       u8 *data = skb->data;
+       unsigned int offset;
+       u16 *hi, *id;
+       u32 lo;
+
+       if ((sk_run_filter(skb, ptp_filter) != PTP_CLASS_V2_IPV4) &&
+               (sk_run_filter(skb, ptp_filter) != PTP_CLASS_V1_IPV4)) {
+               return 0;
+       }
+
+       offset = ETH_HLEN + IPV4_HLEN(data) + UDP_HLEN;
+
+       if (skb->len < offset + OFF_PTP_SEQUENCE_ID + sizeof(seqid))
+               return 0;
+
+       hi = (u16 *)(data + offset + OFF_PTP_SOURCE_UUID);
+       id = (u16 *)(data + offset + OFF_PTP_SEQUENCE_ID);
+
+       memcpy(&lo, &hi[1], sizeof(lo));
+
+       return (uid_hi == *hi &&
+               uid_lo == lo &&
+               seqid  == *id);
+}
+
+static void pch_rx_timestamp(
+                       struct pch_gbe_adapter *adapter, struct sk_buff *skb)
+{
+       struct skb_shared_hwtstamps *shhwtstamps;
+       struct pci_dev *pdev;
+       u64 ns;
+       u32 hi, lo, val;
+       u16 uid, seq;
+
+       if (!adapter->hwts_rx_en)
+               return;
+
+       /* Get ieee1588's dev information */
+       pdev = adapter->ptp_pdev;
+
+       val = pch_ch_event_read(pdev);
+
+       if (!(val & RX_SNAPSHOT_LOCKED))
+               return;
+
+       lo = pch_src_uuid_lo_read(pdev);
+       hi = pch_src_uuid_hi_read(pdev);
+
+       uid = hi & 0xffff;
+       seq = (hi >> 16) & 0xffff;
+
+       if (!pch_ptp_match(skb, htons(uid), htonl(lo), htons(seq)))
+               goto out;
+
+       ns = pch_rx_snap_read(pdev);
+       ns <<= TICKS_NS_SHIFT;
+
+       shhwtstamps = skb_hwtstamps(skb);
+       memset(shhwtstamps, 0, sizeof(*shhwtstamps));
+       shhwtstamps->hwtstamp = ns_to_ktime(ns);
+out:
+       pch_ch_event_write(pdev, RX_SNAPSHOT_LOCKED);
+}
+
+static void pch_tx_timestamp(
+                       struct pch_gbe_adapter *adapter, struct sk_buff *skb)
+{
+       struct skb_shared_hwtstamps shhwtstamps;
+       struct pci_dev *pdev;
+       struct skb_shared_info *shtx;
+       u64 ns;
+       u32 cnt, val;
+
+       shtx = skb_shinfo(skb);
+       if (unlikely(shtx->tx_flags & SKBTX_HW_TSTAMP && adapter->hwts_tx_en))
+               shtx->tx_flags |= SKBTX_IN_PROGRESS;
+       else
+               return;
+
+       /* Get ieee1588's dev information */
+       pdev = adapter->ptp_pdev;
+
+       /*
+        * This really stinks, but we have to poll for the Tx time stamp.
+        * Usually, the time stamp is ready after 4 to 6 microseconds.
+        */
+       for (cnt = 0; cnt < 100; cnt++) {
+               val = pch_ch_event_read(pdev);
+               if (val & TX_SNAPSHOT_LOCKED)
+                       break;
+               udelay(1);
+       }
+       if (!(val & TX_SNAPSHOT_LOCKED)) {
+               shtx->tx_flags &= ~SKBTX_IN_PROGRESS;
+               return;
+       }
+
+       ns = pch_tx_snap_read(pdev);
+       ns <<= TICKS_NS_SHIFT;
+
+       memset(&shhwtstamps, 0, sizeof(shhwtstamps));
+       shhwtstamps.hwtstamp = ns_to_ktime(ns);
+       skb_tstamp_tx(skb, &shhwtstamps);
+
+       pch_ch_event_write(pdev, TX_SNAPSHOT_LOCKED);
+}
+
+static int hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+       struct hwtstamp_config cfg;
+       struct pch_gbe_adapter *adapter = netdev_priv(netdev);
+       struct pci_dev *pdev;
+
+       if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
+               return -EFAULT;
+
+       if (cfg.flags) /* reserved for future extensions */
+               return -EINVAL;
+
+       /* Get ieee1588's dev information */
+       pdev = adapter->ptp_pdev;
+
+       switch (cfg.tx_type) {
+       case HWTSTAMP_TX_OFF:
+               adapter->hwts_tx_en = 0;
+               break;
+       case HWTSTAMP_TX_ON:
+               adapter->hwts_tx_en = 1;
+               break;
+       default:
+               return -ERANGE;
+       }
+
+       switch (cfg.rx_filter) {
+       case HWTSTAMP_FILTER_NONE:
+               adapter->hwts_rx_en = 0;
+               break;
+       case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+               adapter->hwts_rx_en = 0;
+               pch_ch_control_write(pdev, (SLAVE_MODE | CAP_MODE0));
+               break;
+       case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+               adapter->hwts_rx_en = 1;
+               pch_ch_control_write(pdev, (MASTER_MODE | CAP_MODE0));
+               break;
+       case HWTSTAMP_FILTER_PTP_V2_EVENT:
+               adapter->hwts_rx_en = 1;
+               pch_ch_control_write(pdev, (V2_MODE | CAP_MODE2));
+               break;
+       default:
+               return -ERANGE;
+       }
+
+       /* Clear out any old time stamps. */
+       pch_ch_event_write(pdev, TX_SNAPSHOT_LOCKED | RX_SNAPSHOT_LOCKED);
+
+       return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
+}
+#endif
+
 inline void pch_gbe_mac_load_mac_addr(struct pch_gbe_hw *hw)
 {
        iowrite32(0x01, &hw->reg->MAC_ADDR_LOAD);
@@ -1072,6 +1259,11 @@ static void pch_gbe_tx_queue(struct pch_gbe_adapter *adapter,
        iowrite32(tx_ring->dma +
                  (int)sizeof(struct pch_gbe_tx_desc) * ring_num,
                  &hw->reg->TX_DSC_SW_P);
+
+#ifdef CONFIG_PCH_PTP
+       pch_tx_timestamp(adapter, skb);
+#endif
+
        dev_kfree_skb_any(skb);
 }
 
@@ -1543,6 +1735,11 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter,
                                adapter->stats.multicast++;
                        /* Write meta date of skb */
                        skb_put(skb, length);
+
+#ifdef CONFIG_PCH_PTP
+                       pch_rx_timestamp(adapter, skb);
+#endif
+
                        skb->protocol = eth_type_trans(skb, netdev);
                        if (tcp_ip_status & PCH_GBE_RXD_ACC_STAT_TCPIPOK)
                                skb->ip_summed = CHECKSUM_NONE;
@@ -2144,6 +2341,11 @@ static int pch_gbe_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
 
        pr_debug("cmd : 0x%04x\n", cmd);
 
+#ifdef CONFIG_PCH_PTP
+       if (cmd == SIOCSHWTSTAMP)
+               return hwtstamp_ioctl(netdev, ifr, cmd);
+#endif
+
        return generic_mii_ioctl(&adapter->mii, if_mii(ifr), cmd, NULL);
 }
 
@@ -2435,6 +2637,15 @@ static int pch_gbe_probe(struct pci_dev *pdev,
                goto err_free_netdev;
        }
 
+#ifdef CONFIG_PCH_PTP
+       adapter->ptp_pdev = pci_get_bus_and_slot(adapter->pdev->bus->number,
+                                              PCI_DEVFN(12, 4));
+       if (ptp_filter_init(ptp_filter, ARRAY_SIZE(ptp_filter))) {
+               pr_err("Bad ptp filter\n");
+               return -EINVAL;
+       }
+#endif
+
        netdev->netdev_ops = &pch_gbe_netdev_ops;
        netdev->watchdog_timeo = PCH_GBE_WATCHDOG_PERIOD;
        netif_napi_add(netdev, &adapter->napi,
@@ -2499,7 +2710,7 @@ static int pch_gbe_probe(struct pci_dev *pdev,
        netif_carrier_off(netdev);
        netif_stop_queue(netdev);
 
-       dev_dbg(&pdev->dev, "OKIsemi(R) PCH Network Connection\n");
+       dev_dbg(&pdev->dev, "PCH Network Connection\n");
 
        device_set_wakeup_enable(&pdev->dev, 1);
        return 0;
@@ -2600,7 +2811,7 @@ module_init(pch_gbe_init_module);
 module_exit(pch_gbe_exit_module);
 
 MODULE_DESCRIPTION("EG20T PCH Gigabit ethernet Driver");
-MODULE_AUTHOR("OKI SEMICONDUCTOR, <toshiharu-linux@dsn.okisemi.com>");
+MODULE_AUTHOR("LAPIS SEMICONDUCTOR, <tshimizu818@gmail.com>");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 MODULE_DEVICE_TABLE(pci, pch_gbe_pcidev_id);
index b97132d9dff0c09fdd804ad63335e10a8225343d..8f29feb35548273c56d6ea2247031214eb820a22 100644 (file)
@@ -4,6 +4,7 @@
 
 config NET_PACKET_ENGINE
        bool "Packet Engine devices"
+       default y
        depends on PCI
        ---help---
          If you have a network (Ethernet) card belonging to this class, say Y
index d49f6dac51fd928ca3507f5bb1e83617725f799c..df09b1cb742fb211f639e0e6a16d658a768cf7d6 100644 (file)
@@ -2836,7 +2836,7 @@ static int ql_create_send_free_list(struct ql3_adapter *qdev)
                req_q_curr++;
                tx_cb->oal = kmalloc(512, GFP_KERNEL);
                if (tx_cb->oal == NULL)
-                       return -1;
+                       return -ENOMEM;
        }
        return 0;
 }
@@ -3017,7 +3017,6 @@ static int ql_adapter_initialize(struct ql3_adapter *qdev)
                (void __iomem *)port_regs;
        u32 delay = 10;
        int status = 0;
-       unsigned long hw_flags = 0;
 
        if (ql_mii_setup(qdev))
                return -1;
@@ -3228,9 +3227,9 @@ static int ql_adapter_initialize(struct ql3_adapter *qdev)
                value = ql_read_page0_reg(qdev, &port_regs->portStatus);
                if (value & PORT_STATUS_IC)
                        break;
-               spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+               spin_unlock_irq(&qdev->hw_lock);
                msleep(500);
-               spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+               spin_lock_irq(&qdev->hw_lock);
        } while (--delay);
 
        if (delay == 0) {
index abd6aca70e9bdb62219f673826a35ed66ea2b612..df7fd8d083dc1a133805f1b54ca47b4e0bb4c44f 100644 (file)
@@ -565,6 +565,12 @@ struct rtl_extra_stats {
        unsigned long rx_lost_in_ring;
 };
 
+struct rtl8139_stats {
+       u64     packets;
+       u64     bytes;
+       struct u64_stats_sync   syncp;
+};
+
 struct rtl8139_private {
        void __iomem            *mmio_addr;
        int                     drv_flags;
@@ -575,11 +581,13 @@ struct rtl8139_private {
 
        unsigned char           *rx_ring;
        unsigned int            cur_rx; /* RX buf index of next pkt */
+       struct rtl8139_stats    rx_stats;
        dma_addr_t              rx_ring_dma;
 
        unsigned int            tx_flag;
        unsigned long           cur_tx;
        unsigned long           dirty_tx;
+       struct rtl8139_stats    tx_stats;
        unsigned char           *tx_buf[NUM_TX_DESC];   /* Tx bounce buffers */
        unsigned char           *tx_bufs;       /* Tx bounce buffer region. */
        dma_addr_t              tx_bufs_dma;
@@ -641,7 +649,9 @@ static int rtl8139_poll(struct napi_struct *napi, int budget);
 static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance);
 static int rtl8139_close (struct net_device *dev);
 static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
-static struct net_device_stats *rtl8139_get_stats (struct net_device *dev);
+static struct rtnl_link_stats64 *rtl8139_get_stats64(struct net_device *dev,
+                                                   struct rtnl_link_stats64
+                                                   *stats);
 static void rtl8139_set_rx_mode (struct net_device *dev);
 static void __set_rx_mode (struct net_device *dev);
 static void rtl8139_hw_start (struct net_device *dev);
@@ -937,7 +947,7 @@ static int rtl8139_set_features(struct net_device *dev, netdev_features_t featur
 static const struct net_device_ops rtl8139_netdev_ops = {
        .ndo_open               = rtl8139_open,
        .ndo_stop               = rtl8139_close,
-       .ndo_get_stats          = rtl8139_get_stats,
+       .ndo_get_stats64        = rtl8139_get_stats64,
        .ndo_change_mtu         = eth_change_mtu,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_set_mac_address    = rtl8139_set_mac_address,
@@ -1807,8 +1817,10 @@ static void rtl8139_tx_interrupt (struct net_device *dev,
                                dev->stats.tx_fifo_errors++;
                        }
                        dev->stats.collisions += (txstatus >> 24) & 15;
-                       dev->stats.tx_bytes += txstatus & 0x7ff;
-                       dev->stats.tx_packets++;
+                       u64_stats_update_begin(&tp->tx_stats.syncp);
+                       tp->tx_stats.packets++;
+                       tp->tx_stats.bytes += txstatus & 0x7ff;
+                       u64_stats_update_end(&tp->tx_stats.syncp);
                }
 
                dirty_tx++;
@@ -2050,8 +2062,10 @@ keep_pkt:
 
                        skb->protocol = eth_type_trans (skb, dev);
 
-                       dev->stats.rx_bytes += pkt_size;
-                       dev->stats.rx_packets++;
+                       u64_stats_update_begin(&tp->rx_stats.syncp);
+                       tp->rx_stats.packets++;
+                       tp->rx_stats.bytes += pkt_size;
+                       u64_stats_update_end(&tp->rx_stats.syncp);
 
                        netif_receive_skb (skb);
                } else {
@@ -2515,11 +2529,13 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 }
 
 
-static struct net_device_stats *rtl8139_get_stats (struct net_device *dev)
+static struct rtnl_link_stats64 *
+rtl8139_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
 {
        struct rtl8139_private *tp = netdev_priv(dev);
        void __iomem *ioaddr = tp->mmio_addr;
        unsigned long flags;
+       unsigned int start;
 
        if (netif_running(dev)) {
                spin_lock_irqsave (&tp->lock, flags);
@@ -2528,7 +2544,21 @@ static struct net_device_stats *rtl8139_get_stats (struct net_device *dev)
                spin_unlock_irqrestore (&tp->lock, flags);
        }
 
-       return &dev->stats;
+       netdev_stats_to_stats64(stats, &dev->stats);
+
+       do {
+               start = u64_stats_fetch_begin_bh(&tp->rx_stats.syncp);
+               stats->rx_packets = tp->rx_stats.packets;
+               stats->rx_bytes = tp->rx_stats.bytes;
+       } while (u64_stats_fetch_retry_bh(&tp->rx_stats.syncp, start));
+
+       do {
+               start = u64_stats_fetch_begin_bh(&tp->tx_stats.syncp);
+               stats->tx_packets = tp->tx_stats.packets;
+               stats->tx_bytes = tp->tx_stats.bytes;
+       } while (u64_stats_fetch_retry_bh(&tp->tx_stats.syncp, start));
+
+       return stats;
 }
 
 /* Set or clear the multicast filter for this adaptor.
index fbd855bcd9f023a18d7995afb0851a6b59cabeff..c04df3d2b2a984e054df3da419c62f26eaac697e 100644 (file)
@@ -675,6 +675,12 @@ enum rtl_flag {
        RTL_FLAG_MAX
 };
 
+struct rtl8169_stats {
+       u64                     packets;
+       u64                     bytes;
+       struct u64_stats_sync   syncp;
+};
+
 struct rtl8169_private {
        void __iomem *mmio_addr;        /* memory map physical address */
        struct pci_dev *pci_dev;
@@ -687,6 +693,8 @@ struct rtl8169_private {
        u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
        u32 dirty_rx;
        u32 dirty_tx;
+       struct rtl8169_stats rx_stats;
+       struct rtl8169_stats tx_stats;
        struct TxDesc *TxDescArray;     /* 256-aligned Tx descriptor ring */
        struct RxDesc *RxDescArray;     /* 256-aligned Rx descriptor ring */
        dma_addr_t TxPhyAddr;
@@ -775,7 +783,9 @@ static void rtl_hw_start(struct net_device *dev);
 static int rtl8169_close(struct net_device *dev);
 static void rtl_set_rx_mode(struct net_device *dev);
 static void rtl8169_tx_timeout(struct net_device *dev);
-static struct net_device_stats *rtl8169_get_stats(struct net_device *dev);
+static struct rtnl_link_stats64 *rtl8169_get_stats64(struct net_device *dev,
+                                                   struct rtnl_link_stats64
+                                                   *stats);
 static int rtl8169_change_mtu(struct net_device *dev, int new_mtu);
 static void rtl8169_rx_clear(struct rtl8169_private *tp);
 static int rtl8169_poll(struct napi_struct *napi, int budget);
@@ -3521,7 +3531,7 @@ static void rtl_disable_msi(struct pci_dev *pdev, struct rtl8169_private *tp)
 static const struct net_device_ops rtl8169_netdev_ops = {
        .ndo_open               = rtl8169_open,
        .ndo_stop               = rtl8169_close,
-       .ndo_get_stats          = rtl8169_get_stats,
+       .ndo_get_stats64        = rtl8169_get_stats64,
        .ndo_start_xmit         = rtl8169_start_xmit,
        .ndo_tx_timeout         = rtl8169_tx_timeout,
        .ndo_validate_addr      = eth_validate_addr,
@@ -3844,12 +3854,20 @@ static void rtl8169_init_ring_indexes(struct rtl8169_private *tp)
 
 static void rtl_hw_jumbo_enable(struct rtl8169_private *tp)
 {
+       void __iomem *ioaddr = tp->mmio_addr;
+
+       RTL_W8(Cfg9346, Cfg9346_Unlock);
        rtl_generic_op(tp, tp->jumbo_ops.enable);
+       RTL_W8(Cfg9346, Cfg9346_Lock);
 }
 
 static void rtl_hw_jumbo_disable(struct rtl8169_private *tp)
 {
+       void __iomem *ioaddr = tp->mmio_addr;
+
+       RTL_W8(Cfg9346, Cfg9346_Unlock);
        rtl_generic_op(tp, tp->jumbo_ops.disable);
+       RTL_W8(Cfg9346, Cfg9346_Lock);
 }
 
 static void r8168c_hw_jumbo_enable(struct rtl8169_private *tp)
@@ -5389,6 +5407,7 @@ static void rtl8169_tx_clear(struct rtl8169_private *tp)
 {
        rtl8169_tx_clear_range(tp, tp->dirty_tx, NUM_TX_DESC);
        tp->cur_tx = tp->dirty_tx = 0;
+       netdev_reset_queue(tp->dev);
 }
 
 static void rtl_reset_work(struct rtl8169_private *tp)
@@ -5543,6 +5562,8 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
 
        txd->opts2 = cpu_to_le32(opts[1]);
 
+       netdev_sent_queue(dev, skb->len);
+
        wmb();
 
        /* Anti gcc 2.95.3 bugware (sic) */
@@ -5637,9 +5658,16 @@ static void rtl8169_pcierr_interrupt(struct net_device *dev)
        rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
 }
 
+struct rtl_txc {
+       int packets;
+       int bytes;
+};
+
 static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp)
 {
+       struct rtl8169_stats *tx_stats = &tp->tx_stats;
        unsigned int dirty_tx, tx_left;
+       struct rtl_txc txc = { 0, 0 };
 
        dirty_tx = tp->dirty_tx;
        smp_rmb();
@@ -5658,15 +5686,24 @@ static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp)
                rtl8169_unmap_tx_skb(&tp->pci_dev->dev, tx_skb,
                                     tp->TxDescArray + entry);
                if (status & LastFrag) {
-                       dev->stats.tx_packets++;
-                       dev->stats.tx_bytes += tx_skb->skb->len;
-                       dev_kfree_skb(tx_skb->skb);
+                       struct sk_buff *skb = tx_skb->skb;
+
+                       txc.packets++;
+                       txc.bytes += skb->len;
+                       dev_kfree_skb(skb);
                        tx_skb->skb = NULL;
                }
                dirty_tx++;
                tx_left--;
        }
 
+       u64_stats_update_begin(&tx_stats->syncp);
+       tx_stats->packets += txc.packets;
+       tx_stats->bytes += txc.bytes;
+       u64_stats_update_end(&tx_stats->syncp);
+
+       netdev_completed_queue(dev, txc.packets, txc.bytes);
+
        if (tp->dirty_tx != dirty_tx) {
                tp->dirty_tx = dirty_tx;
                /* Sync with rtl8169_start_xmit:
@@ -5807,8 +5844,10 @@ process_pkt:
 
                        napi_gro_receive(&tp->napi, skb);
 
-                       dev->stats.rx_bytes += pkt_size;
-                       dev->stats.rx_packets++;
+                       u64_stats_update_begin(&tp->rx_stats.syncp);
+                       tp->rx_stats.packets++;
+                       tp->rx_stats.bytes += pkt_size;
+                       u64_stats_update_end(&tp->rx_stats.syncp);
                }
 
                /* Work around for AMD plateform. */
@@ -6069,21 +6108,38 @@ static void rtl_set_rx_mode(struct net_device *dev)
        RTL_W32(RxConfig, tmp);
 }
 
-/**
- *  rtl8169_get_stats - Get rtl8169 read/write statistics
- *  @dev: The Ethernet Device to get statistics for
- *
- *  Get TX/RX statistics for rtl8169
- */
-static struct net_device_stats *rtl8169_get_stats(struct net_device *dev)
+static struct rtnl_link_stats64 *
+rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
        void __iomem *ioaddr = tp->mmio_addr;
+       unsigned int start;
 
        if (netif_running(dev))
                rtl8169_rx_missed(dev, ioaddr);
 
-       return &dev->stats;
+       do {
+               start = u64_stats_fetch_begin_bh(&tp->rx_stats.syncp);
+               stats->rx_packets = tp->rx_stats.packets;
+               stats->rx_bytes = tp->rx_stats.bytes;
+       } while (u64_stats_fetch_retry_bh(&tp->rx_stats.syncp, start));
+
+
+       do {
+               start = u64_stats_fetch_begin_bh(&tp->tx_stats.syncp);
+               stats->tx_packets = tp->tx_stats.packets;
+               stats->tx_bytes = tp->tx_stats.bytes;
+       } while (u64_stats_fetch_retry_bh(&tp->tx_stats.syncp, start));
+
+       stats->rx_dropped       = dev->stats.rx_dropped;
+       stats->tx_dropped       = dev->stats.tx_dropped;
+       stats->rx_length_errors = dev->stats.rx_length_errors;
+       stats->rx_errors        = dev->stats.rx_errors;
+       stats->rx_crc_errors    = dev->stats.rx_crc_errors;
+       stats->rx_fifo_errors   = dev->stats.rx_fifo_errors;
+       stats->rx_missed_errors = dev->stats.rx_missed_errors;
+
+       return stats;
 }
 
 static void rtl8169_net_suspend(struct net_device *dev)
@@ -6236,6 +6292,9 @@ static void rtl_shutdown(struct pci_dev *pdev)
 {
        struct net_device *dev = pci_get_drvdata(pdev);
        struct rtl8169_private *tp = netdev_priv(dev);
+       struct device *d = &pdev->dev;
+
+       pm_runtime_get_sync(d);
 
        rtl8169_net_suspend(dev);
 
@@ -6253,6 +6312,8 @@ static void rtl_shutdown(struct pci_dev *pdev)
                pci_wake_from_d3(pdev, true);
                pci_set_power_state(pdev, PCI_D3hot);
        }
+
+       pm_runtime_put_noidle(d);
 }
 
 static struct pci_driver rtl8169_pci_driver = {
index 0ae7a1a6aeb0a95b456ffad376fe0af78db46f90..217dfedbba2002d5c6e5a286d80dabcd06704221 100644 (file)
@@ -310,7 +310,7 @@ int netvsc_recv_callback(struct hv_device *device_obj,
 static void netvsc_get_drvinfo(struct net_device *net,
                               struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, "hv_netvsc");
+       strcpy(info->driver, KBUILD_MODNAME);
        strcpy(info->version, HV_DRV_VERSION);
        strcpy(info->fw_version, "N/A");
 }
@@ -482,7 +482,7 @@ MODULE_DEVICE_TABLE(vmbus, id_table);
 
 /* The one and only one */
 static struct  hv_driver netvsc_drv = {
-       .name = "netvsc",
+       .name = KBUILD_MODNAME,
        .id_table = id_table,
        .probe = netvsc_probe,
        .remove = netvsc_remove,
index b924f46c963cc136be1e2e26b21cbd81ed0019a5..83dcc530618e4205322bcd6b7bba24239daa2ed1 100644 (file)
@@ -589,6 +589,7 @@ static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q)
                entry = (struct skb_data *) skb->cb;
                urb = entry->urb;
 
+               spin_unlock_irqrestore(&q->lock, flags);
                // during some PM-driven resume scenarios,
                // these (async) unlinks complete immediately
                retval = usb_unlink_urb (urb);
@@ -596,6 +597,7 @@ static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q)
                        netdev_dbg(dev->net, "unlink urb err, %d\n", retval);
                else
                        count++;
+               spin_lock_irqsave(&q->lock, flags);
        }
        spin_unlock_irqrestore (&q->lock, flags);
        return count;
index a9684a53af194414a50eb4a5b62d47abf3cb7b56..3f04ba0a5454cabb470db7bd2db1ffd437401bf3 100644 (file)
@@ -825,12 +825,7 @@ vmxnet3_parse_and_copy_hdr(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
                                if (iph->protocol == IPPROTO_TCP)
                                        ctx->l4_hdr_size = tcp_hdrlen(skb);
                                else if (iph->protocol == IPPROTO_UDP)
-                                       /*
-                                        * Use tcp header size so that bytes to
-                                        * be copied are more than required by
-                                        * the device.
-                                        */
-                                       ctx->l4_hdr_size = sizeof(struct tcphdr);
+                                       ctx->l4_hdr_size = sizeof(struct udphdr);
                                else
                                        ctx->l4_hdr_size = 0;
                        } else {
index ed54797db1916d717fe3141559bf95bca2013547..fc46a81ad5384969b1670114765e3df12799a256 100644 (file)
 /*
  * Version numbers
  */
-#define VMXNET3_DRIVER_VERSION_STRING   "1.1.18.0-k"
+#define VMXNET3_DRIVER_VERSION_STRING   "1.1.29.0-k"
 
 /* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */
-#define VMXNET3_DRIVER_VERSION_NUM      0x01011200
+#define VMXNET3_DRIVER_VERSION_NUM      0x01011D00
 
 #if defined(CONFIG_PCI_MSI)
        /* RSS only makes sense if MSI-X is supported. */
index 1c008c61b95ce8113d8ad230ee4e48aad27992b7..ddc061dd150ce47438020f28424a7449e9ab66a5 100644 (file)
@@ -1869,7 +1869,7 @@ static int readStatsRid(struct airo_info*ai, StatsRid *sr, int rid, int lock)
 
 static void try_auto_wep(struct airo_info *ai)
 {
-       if (auto_wep && !(ai->flags & FLAG_RADIO_DOWN)) {
+       if (auto_wep && !test_bit(FLAG_RADIO_DOWN, &ai->flags)) {
                ai->expires = RUN_AT(3*HZ);
                wake_up_interruptible(&ai->thr_wait);
        }
index ee7ea572b065753c3271c184bb84c65bcf2908e2..8faa129da5a00b60c74dd255ae1692effb3d329d 100644 (file)
@@ -140,23 +140,23 @@ static int ath_ahb_probe(struct platform_device *pdev)
 
        if (bcfg->devid >= AR5K_SREV_AR2315_R6) {
                /* Enable WMAC AHB arbitration */
-               reg = __raw_readl((void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
+               reg = ioread32((void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
                reg |= AR5K_AR2315_AHB_ARB_CTL_WLAN;
-               __raw_writel(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
+               iowrite32(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
 
                /* Enable global WMAC swapping */
-               reg = __raw_readl((void __iomem *) AR5K_AR2315_BYTESWAP);
+               reg = ioread32((void __iomem *) AR5K_AR2315_BYTESWAP);
                reg |= AR5K_AR2315_BYTESWAP_WMAC;
-               __raw_writel(reg, (void __iomem *) AR5K_AR2315_BYTESWAP);
+               iowrite32(reg, (void __iomem *) AR5K_AR2315_BYTESWAP);
        } else {
                /* Enable WMAC DMA access (assuming 5312 or 231x*/
                /* TODO: check other platforms */
-               reg = __raw_readl((void __iomem *) AR5K_AR5312_ENABLE);
+               reg = ioread32((void __iomem *) AR5K_AR5312_ENABLE);
                if (to_platform_device(ah->dev)->id == 0)
                        reg |= AR5K_AR5312_ENABLE_WLAN0;
                else
                        reg |= AR5K_AR5312_ENABLE_WLAN1;
-               __raw_writel(reg, (void __iomem *) AR5K_AR5312_ENABLE);
+               iowrite32(reg, (void __iomem *) AR5K_AR5312_ENABLE);
 
                /*
                 * On a dual-band AR5312, the multiband radio is only
@@ -203,17 +203,17 @@ static int ath_ahb_remove(struct platform_device *pdev)
 
        if (bcfg->devid >= AR5K_SREV_AR2315_R6) {
                /* Disable WMAC AHB arbitration */
-               reg = __raw_readl((void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
+               reg = ioread32((void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
                reg &= ~AR5K_AR2315_AHB_ARB_CTL_WLAN;
-               __raw_writel(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
+               iowrite32(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
        } else {
                /*Stop DMA access */
-               reg = __raw_readl((void __iomem *) AR5K_AR5312_ENABLE);
+               reg = ioread32((void __iomem *) AR5K_AR5312_ENABLE);
                if (to_platform_device(ah->dev)->id == 0)
                        reg &= ~AR5K_AR5312_ENABLE_WLAN0;
                else
                        reg &= ~AR5K_AR5312_ENABLE_WLAN1;
-               __raw_writel(reg, (void __iomem *) AR5K_AR5312_ENABLE);
+               iowrite32(reg, (void __iomem *) AR5K_AR5312_ENABLE);
        }
 
        ath5k_deinit_ah(ah);
index c2b2518c2ecd30732c900ab3490d01765b0c35b9..8d434b8f58557ff8b105371fe012661b829367e4 100644 (file)
@@ -1320,6 +1320,7 @@ struct ath5k_hw {
        struct ieee80211_vif    *bslot[ATH_BCBUF];
        u16                     num_ap_vifs;
        u16                     num_adhoc_vifs;
+       u16                     num_mesh_vifs;
        unsigned int            bhalq,          /* SW q for outgoing beacons */
                                bmisscount,     /* missed beacon transmits */
                                bintval,        /* beacon interval in TU */
@@ -1656,12 +1657,12 @@ static inline void __iomem *ath5k_ahb_reg(struct ath5k_hw *ah, u16 reg)
 
 static inline u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg)
 {
-       return __raw_readl(ath5k_ahb_reg(ah, reg));
+       return ioread32(ath5k_ahb_reg(ah, reg));
 }
 
 static inline void ath5k_hw_reg_write(struct ath5k_hw *ah, u32 val, u16 reg)
 {
-       __raw_writel(val, ath5k_ahb_reg(ah, reg));
+       iowrite32(val, ath5k_ahb_reg(ah, reg));
 }
 
 #else
index a339693fbe265cfc475f097d70fb0c11dc29e0b0..0e643b016b3286a12d80e040a7d399914468f8fb 100644 (file)
@@ -1867,7 +1867,8 @@ ath5k_beacon_send(struct ath5k_hw *ah)
                ah->bmisscount = 0;
        }
 
-       if ((ah->opmode == NL80211_IFTYPE_AP && ah->num_ap_vifs > 1) ||
+       if ((ah->opmode == NL80211_IFTYPE_AP && ah->num_ap_vifs +
+                       ah->num_mesh_vifs > 1) ||
                        ah->opmode == NL80211_IFTYPE_MESH_POINT) {
                u64 tsf = ath5k_hw_get_tsf64(ah);
                u32 tsftu = TSF_TO_TU(tsf);
@@ -1952,7 +1953,8 @@ ath5k_beacon_update_timers(struct ath5k_hw *ah, u64 bc_tsf)
        u64 hw_tsf;
 
        intval = ah->bintval & AR5K_BEACON_PERIOD;
-       if (ah->opmode == NL80211_IFTYPE_AP && ah->num_ap_vifs > 1) {
+       if (ah->opmode == NL80211_IFTYPE_AP && ah->num_ap_vifs
+               + ah->num_mesh_vifs > 1) {
                intval /= ATH_BCBUF;    /* staggered multi-bss beacons */
                if (intval < 15)
                        ATH5K_WARN(ah, "intval %u is too low, min 15\n",
@@ -2330,15 +2332,6 @@ ath5k_calibrate_work(struct work_struct *work)
                                        "got new rfgain, resetting\n");
                        ieee80211_queue_work(ah->hw, &ah->reset_work);
                }
-
-               /* TODO: On full calibration we should stop TX here,
-                * so that it doesn't interfere (mostly due to gain_f
-                * calibration that messes with tx packets -see phy.c).
-                *
-                * NOTE: Stopping the queues from above is not enough
-                * to stop TX but saves us from disconecting (at least
-                * we don't lose packets). */
-               ieee80211_stop_queues(ah->hw);
        } else
                ah->ah_cal_mask |= AR5K_CALIBRATION_SHORT;
 
@@ -2353,10 +2346,9 @@ ath5k_calibrate_work(struct work_struct *work)
                                ah->curchan->center_freq));
 
        /* Clear calibration flags */
-       if (ah->ah_cal_mask & AR5K_CALIBRATION_FULL) {
-               ieee80211_wake_queues(ah->hw);
+       if (ah->ah_cal_mask & AR5K_CALIBRATION_FULL)
                ah->ah_cal_mask &= ~AR5K_CALIBRATION_FULL;
-       else if (ah->ah_cal_mask & AR5K_CALIBRATION_SHORT)
+       else if (ah->ah_cal_mask & AR5K_CALIBRATION_SHORT)
                ah->ah_cal_mask &= ~AR5K_CALIBRATION_SHORT;
 }
 
index af4c7ecb4b303a6595413339de28473677ac135a..5c5329955414966247d5f44dcb8d7760e2d474f1 100644 (file)
@@ -134,6 +134,8 @@ ath5k_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
                        ah->num_ap_vifs++;
                else if (avf->opmode == NL80211_IFTYPE_ADHOC)
                        ah->num_adhoc_vifs++;
+               else if (avf->opmode == NL80211_IFTYPE_MESH_POINT)
+                       ah->num_mesh_vifs++;
        }
 
        /* Any MAC address is fine, all others are included through the
@@ -175,6 +177,8 @@ ath5k_remove_interface(struct ieee80211_hw *hw,
                ah->num_ap_vifs--;
        else if (avf->opmode == NL80211_IFTYPE_ADHOC)
                ah->num_adhoc_vifs--;
+       else if (avf->opmode == NL80211_IFTYPE_MESH_POINT)
+               ah->num_mesh_vifs--;
 
        ath5k_update_bssid_mask_and_opmode(ah, NULL);
        mutex_unlock(&ah->lock);
index e1f8613426a921f05fe294ba1409baaec7e2b954..3a2845489a1b67cb7df9c4750785a690639d9bdd 100644 (file)
@@ -1871,31 +1871,15 @@ ath5k_hw_phy_calibrate(struct ath5k_hw *ah,
                ret = 0;
        }
 
-       /* On full calibration do an AGC calibration and
-        * request a PAPD probe for gainf calibration if
-        * needed */
-       if (ah->ah_cal_mask & AR5K_CALIBRATION_FULL) {
-
-               AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
-                                       AR5K_PHY_AGCCTL_CAL);
-
-               ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
-                       AR5K_PHY_AGCCTL_CAL | AR5K_PHY_AGCCTL_NF,
-                       0, false);
-               if (ret) {
-                       ATH5K_ERR(ah,
-                               "gain calibration timeout (%uMHz)\n",
-                               channel->center_freq);
-               }
-
-               if ((ah->ah_radio == AR5K_RF5111 ||
-                       ah->ah_radio == AR5K_RF5112)
-                       && (channel->hw_value != AR5K_MODE_11B))
-                       ath5k_hw_request_rfgain_probe(ah);
-       }
-
-       /* Update noise floor
-        * XXX: Only do this after AGC calibration */
+       /* On full calibration request a PAPD probe for
+        * gainf calibration if needed */
+       if ((ah->ah_cal_mask & AR5K_CALIBRATION_FULL) &&
+           (ah->ah_radio == AR5K_RF5111 ||
+            ah->ah_radio == AR5K_RF5112) &&
+           channel->hw_value != AR5K_MODE_11B)
+               ath5k_hw_request_rfgain_probe(ah);
+
+       /* Update noise floor */
        if (!(ah->ah_cal_mask & AR5K_CALIBRATION_NF))
                ath5k_hw_update_noise_floor(ah);
 
index 250db40b751d1780b0c7937cb53c6de016973bdd..200f165c0c6d9c4a508ece1da7a2fd996b9df094 100644 (file)
@@ -473,14 +473,14 @@ ath5k_hw_wisoc_reset(struct ath5k_hw *ah, u32 flags)
        }
 
        /* Put BB/MAC into reset */
-       regval = __raw_readl(reg);
-       __raw_writel(regval | val, reg);
-       regval = __raw_readl(reg);
+       regval = ioread32(reg);
+       iowrite32(regval | val, reg);
+       regval = ioread32(reg);
        usleep_range(100, 150);
 
        /* Bring BB/MAC out of reset */
-       __raw_writel(regval & ~val, reg);
-       regval = __raw_readl(reg);
+       iowrite32(regval & ~val, reg);
+       regval = ioread32(reg);
 
        /*
         * Reset configuration register (for hw byte-swap). Note that this
index d1922d8eb3bb2a3ffca29a250701d0b7cf3ff7d7..5370333883e4632c03e9ca9958c43631d0072119 100644 (file)
@@ -2269,25 +2269,11 @@ static int ath6kl_set_ap_probe_resp_ies(struct ath6kl_vif *vif,
        return ret;
 }
 
-static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
-                           struct beacon_parameters *info, bool add)
+static int ath6kl_set_ies(struct ath6kl_vif *vif,
+                         struct cfg80211_beacon_data *info)
 {
-       struct ath6kl *ar = ath6kl_priv(dev);
-       struct ath6kl_vif *vif = netdev_priv(dev);
-       struct ieee80211_mgmt *mgmt;
-       u8 *ies;
-       int ies_len;
-       struct wmi_connect_cmd p;
+       struct ath6kl *ar = vif->ar;
        int res;
-       int i, ret;
-
-       ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
-
-       if (!ath6kl_cfg80211_ready(vif))
-               return -EIO;
-
-       if (vif->next_mode != AP_NETWORK)
-               return -EOPNOTSUPP;
 
        if (info->beacon_ies) {
                res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
@@ -2297,12 +2283,14 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
                if (res)
                        return res;
        }
+
        if (info->proberesp_ies) {
                res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies,
                                                   info->proberesp_ies_len);
                if (res)
                        return res;
        }
+
        if (info->assocresp_ies) {
                res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
                                               WMI_FRAME_ASSOC_RESP,
@@ -2312,8 +2300,30 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
                        return res;
        }
 
-       if (!add)
-               return 0;
+       return 0;
+}
+
+static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
+                          struct cfg80211_ap_settings *info)
+{
+       struct ath6kl *ar = ath6kl_priv(dev);
+       struct ath6kl_vif *vif = netdev_priv(dev);
+       struct ieee80211_mgmt *mgmt;
+       u8 *ies;
+       int ies_len;
+       struct wmi_connect_cmd p;
+       int res;
+       int i, ret;
+
+       ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s:\n", __func__);
+
+       if (!ath6kl_cfg80211_ready(vif))
+               return -EIO;
+
+       if (vif->next_mode != AP_NETWORK)
+               return -EOPNOTSUPP;
+
+       res = ath6kl_set_ies(vif, &info->beacon);
 
        ar->ap_mode_bkey.valid = false;
 
@@ -2322,13 +2332,13 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
         * info->dtim_period
         */
 
-       if (info->head == NULL)
+       if (info->beacon.head == NULL)
                return -EINVAL;
-       mgmt = (struct ieee80211_mgmt *) info->head;
+       mgmt = (struct ieee80211_mgmt *) info->beacon.head;
        ies = mgmt->u.beacon.variable;
-       if (ies > info->head + info->head_len)
+       if (ies > info->beacon.head + info->beacon.head_len)
                return -EINVAL;
-       ies_len = info->head + info->head_len - ies;
+       ies_len = info->beacon.head + info->beacon.head_len - ies;
 
        if (info->ssid == NULL)
                return -EINVAL;
@@ -2436,19 +2446,21 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
        return 0;
 }
 
-static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev,
-                            struct beacon_parameters *info)
+static int ath6kl_change_beacon(struct wiphy *wiphy, struct net_device *dev,
+                               struct cfg80211_beacon_data *beacon)
 {
-       return ath6kl_ap_beacon(wiphy, dev, info, true);
-}
+       struct ath6kl_vif *vif = netdev_priv(dev);
 
-static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev,
-                            struct beacon_parameters *info)
-{
-       return ath6kl_ap_beacon(wiphy, dev, info, false);
+       if (!ath6kl_cfg80211_ready(vif))
+               return -EIO;
+
+       if (vif->next_mode != AP_NETWORK)
+               return -EOPNOTSUPP;
+
+       return ath6kl_set_ies(vif, beacon);
 }
 
-static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev)
+static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev)
 {
        struct ath6kl *ar = ath6kl_priv(dev);
        struct ath6kl_vif *vif = netdev_priv(dev);
@@ -2783,9 +2795,9 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = {
        .resume = __ath6kl_cfg80211_resume,
 #endif
        .set_channel = ath6kl_set_channel,
-       .add_beacon = ath6kl_add_beacon,
-       .set_beacon = ath6kl_set_beacon,
-       .del_beacon = ath6kl_del_beacon,
+       .start_ap = ath6kl_start_ap,
+       .change_beacon = ath6kl_change_beacon,
+       .stop_ap = ath6kl_stop_ap,
        .del_station = ath6kl_del_station,
        .change_station = ath6kl_change_station,
        .remain_on_channel = ath6kl_remain_on_channel,
index 18fa9aa8af92464a4888f37b68d9904293ed2573..97abf4699b41270883b80357185652253237c59c 100644 (file)
@@ -556,7 +556,8 @@ static int ath6kl_wmi_rx_probe_req_event_rx(struct wmi *wmi, u8 *datap, int len,
                   dlen, freq, vif->probe_req_report);
 
        if (vif->probe_req_report || vif->nw_type == AP_NETWORK)
-               cfg80211_rx_mgmt(vif->ndev, freq, ev->data, dlen, GFP_ATOMIC);
+               cfg80211_rx_mgmt(vif->ndev, freq, 0,
+                                ev->data, dlen, GFP_ATOMIC);
 
        return 0;
 }
@@ -595,7 +596,8 @@ static int ath6kl_wmi_rx_action_event_rx(struct wmi *wmi, u8 *datap, int len,
                return -EINVAL;
        }
        ath6kl_dbg(ATH6KL_DBG_WMI, "rx_action: len=%u freq=%u\n", dlen, freq);
-       cfg80211_rx_mgmt(vif->ndev, freq, ev->data, dlen, GFP_ATOMIC);
+       cfg80211_rx_mgmt(vif->ndev, freq, 0,
+                        ev->data, dlen, GFP_ATOMIC);
 
        return 0;
 }
index dc6be4afe8eb96ad1ecce4147db6ff761d1556bc..e507e78398f3dc76b3678fb8d16a8b7282735c14 100644 (file)
@@ -6,6 +6,14 @@ config ATH9K_DFS_DEBUGFS
        def_bool y
        depends on ATH9K_DEBUGFS && ATH9K_DFS_CERTIFIED
 
+config ATH9K_BTCOEX_SUPPORT
+       bool "Atheros bluetooth coexistence support"
+       depends on (ATH9K || ATH9K_HTC)
+       default y
+       ---help---
+         Say Y, if you want to use the ath9k/ath9k_htc radios together with
+         Bluetooth modules in the same system.
+
 config ATH9K
        tristate "Atheros 802.11n wireless cards support"
        depends on MAC80211
@@ -73,6 +81,14 @@ config ATH9K_DFS_CERTIFIED
          developed. At this point enabling this option won't do anything
          except increase code size.
 
+config ATH9K_MAC_DEBUG
+       bool "Atheros MAC statistics"
+       depends on ATH9K_DEBUGFS
+       default y
+       ---help---
+         This option enables collection of statistics for Rx/Tx status
+         data and some other MAC related statistics
+
 config ATH9K_RATE_CONTROL
        bool "Atheros ath9k rate control"
        depends on ATH9K
@@ -81,14 +97,6 @@ config ATH9K_RATE_CONTROL
          Say Y, if you want to use the ath9k specific rate control
          module instead of minstrel_ht.
 
-config ATH9K_BTCOEX_SUPPORT
-       bool "Atheros ath9k bluetooth coexistence support"
-       depends on ATH9K
-       default y
-       ---help---
-         Say Y, if you want to use the ath9k radios together with
-         Bluetooth modules in the same system.
-
 config ATH9K_HTC
        tristate "Atheros HTC based wireless cards support"
        depends on USB && MAC80211
index da02242499af15d9049b3a2ce7913cb87ade80bc..27d95fe5ade058b234d88a78ebcbe43e0508834d 100644 (file)
@@ -3,9 +3,9 @@ ath9k-y +=      beacon.o \
                init.o \
                main.o \
                recv.o \
-               xmit.o \
-               mci.o \
+               xmit.o
 
+ath9k-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += mci.o
 ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o
 ath9k-$(CONFIG_ATH9K_PCI) += pci.o
 ath9k-$(CONFIG_ATH9K_AHB) += ahb.o
@@ -31,14 +31,14 @@ ath9k_hw-y:=        \
                eeprom_4k.o \
                eeprom_9287.o \
                ani.o \
-               btcoex.o \
                mac.o \
                ar9002_mac.o \
                ar9003_mac.o \
                ar9003_eeprom.o \
-               ar9003_paprd.o \
-               ar9003_mci.o
+               ar9003_paprd.o
 
+ath9k_hw-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += btcoex.o \
+                                          ar9003_mci.o
 obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o
 
 obj-$(CONFIG_ATH9K_COMMON) += ath9k_common.o
index e8bdc75405f15df52bb84297916bd3b447a916d0..ea4a230997acc7c34c3e944a9ddf4d8c9e65f914 100644 (file)
@@ -459,97 +459,6 @@ static const u32 ar5416Common_9100[][2] = {
        {0x0000a3e0, 0x000001ce},
 };
 
-static const u32 ar5416Bank0_9100[][2] = {
-       /* Addr      allmodes  */
-       {0x000098b0, 0x1e5795e5},
-       {0x000098e0, 0x02008020},
-};
-
-static const u32 ar5416BB_RfGain_9100[][3] = {
-       /* Addr      5G_HT20     5G_HT40   */
-       {0x00009a00, 0x00000000, 0x00000000},
-       {0x00009a04, 0x00000040, 0x00000040},
-       {0x00009a08, 0x00000080, 0x00000080},
-       {0x00009a0c, 0x000001a1, 0x00000141},
-       {0x00009a10, 0x000001e1, 0x00000181},
-       {0x00009a14, 0x00000021, 0x000001c1},
-       {0x00009a18, 0x00000061, 0x00000001},
-       {0x00009a1c, 0x00000168, 0x00000041},
-       {0x00009a20, 0x000001a8, 0x000001a8},
-       {0x00009a24, 0x000001e8, 0x000001e8},
-       {0x00009a28, 0x00000028, 0x00000028},
-       {0x00009a2c, 0x00000068, 0x00000068},
-       {0x00009a30, 0x00000189, 0x000000a8},
-       {0x00009a34, 0x000001c9, 0x00000169},
-       {0x00009a38, 0x00000009, 0x000001a9},
-       {0x00009a3c, 0x00000049, 0x000001e9},
-       {0x00009a40, 0x00000089, 0x00000029},
-       {0x00009a44, 0x00000170, 0x00000069},
-       {0x00009a48, 0x000001b0, 0x00000190},
-       {0x00009a4c, 0x000001f0, 0x000001d0},
-       {0x00009a50, 0x00000030, 0x00000010},
-       {0x00009a54, 0x00000070, 0x00000050},
-       {0x00009a58, 0x00000191, 0x00000090},
-       {0x00009a5c, 0x000001d1, 0x00000151},
-       {0x00009a60, 0x00000011, 0x00000191},
-       {0x00009a64, 0x00000051, 0x000001d1},
-       {0x00009a68, 0x00000091, 0x00000011},
-       {0x00009a6c, 0x000001b8, 0x00000051},
-       {0x00009a70, 0x000001f8, 0x00000198},
-       {0x00009a74, 0x00000038, 0x000001d8},
-       {0x00009a78, 0x00000078, 0x00000018},
-       {0x00009a7c, 0x00000199, 0x00000058},
-       {0x00009a80, 0x000001d9, 0x00000098},
-       {0x00009a84, 0x00000019, 0x00000159},
-       {0x00009a88, 0x00000059, 0x00000199},
-       {0x00009a8c, 0x00000099, 0x000001d9},
-       {0x00009a90, 0x000000d9, 0x00000019},
-       {0x00009a94, 0x000000f9, 0x00000059},
-       {0x00009a98, 0x000000f9, 0x00000099},
-       {0x00009a9c, 0x000000f9, 0x000000d9},
-       {0x00009aa0, 0x000000f9, 0x000000f9},
-       {0x00009aa4, 0x000000f9, 0x000000f9},
-       {0x00009aa8, 0x000000f9, 0x000000f9},
-       {0x00009aac, 0x000000f9, 0x000000f9},
-       {0x00009ab0, 0x000000f9, 0x000000f9},
-       {0x00009ab4, 0x000000f9, 0x000000f9},
-       {0x00009ab8, 0x000000f9, 0x000000f9},
-       {0x00009abc, 0x000000f9, 0x000000f9},
-       {0x00009ac0, 0x000000f9, 0x000000f9},
-       {0x00009ac4, 0x000000f9, 0x000000f9},
-       {0x00009ac8, 0x000000f9, 0x000000f9},
-       {0x00009acc, 0x000000f9, 0x000000f9},
-       {0x00009ad0, 0x000000f9, 0x000000f9},
-       {0x00009ad4, 0x000000f9, 0x000000f9},
-       {0x00009ad8, 0x000000f9, 0x000000f9},
-       {0x00009adc, 0x000000f9, 0x000000f9},
-       {0x00009ae0, 0x000000f9, 0x000000f9},
-       {0x00009ae4, 0x000000f9, 0x000000f9},
-       {0x00009ae8, 0x000000f9, 0x000000f9},
-       {0x00009aec, 0x000000f9, 0x000000f9},
-       {0x00009af0, 0x000000f9, 0x000000f9},
-       {0x00009af4, 0x000000f9, 0x000000f9},
-       {0x00009af8, 0x000000f9, 0x000000f9},
-       {0x00009afc, 0x000000f9, 0x000000f9},
-};
-
-static const u32 ar5416Bank1_9100[][2] = {
-       /* Addr      allmodes  */
-       {0x000098b0, 0x02108421},
-       {0x000098ec, 0x00000008},
-};
-
-static const u32 ar5416Bank2_9100[][2] = {
-       /* Addr      allmodes  */
-       {0x000098b0, 0x0e73ff17},
-       {0x000098e0, 0x00000420},
-};
-
-static const u32 ar5416Bank3_9100[][3] = {
-       /* Addr      5G_HT20     5G_HT40   */
-       {0x000098f0, 0x01400018, 0x01c00018},
-};
-
 static const u32 ar5416Bank6_9100[][3] = {
        /* Addr      5G_HT20     5G_HT40   */
        {0x0000989c, 0x00000000, 0x00000000},
@@ -624,13 +533,6 @@ static const u32 ar5416Bank6TPC_9100[][3] = {
        {0x000098d0, 0x0000000f, 0x0010000f},
 };
 
-static const u32 ar5416Bank7_9100[][2] = {
-       /* Addr      allmodes  */
-       {0x0000989c, 0x00000500},
-       {0x0000989c, 0x00000800},
-       {0x000098cc, 0x0000000e},
-};
-
 static const u32 ar5416Addac_9100[][2] = {
        /* Addr      allmodes  */
        {0x0000989c, 0x00000000},
@@ -1113,178 +1015,6 @@ static const u32 ar5416Common_9160[][2] = {
        {0x0000a3e0, 0x000001ce},
 };
 
-static const u32 ar5416Bank0_9160[][2] = {
-       /* Addr      allmodes  */
-       {0x000098b0, 0x1e5795e5},
-       {0x000098e0, 0x02008020},
-};
-
-static const u32 ar5416BB_RfGain_9160[][3] = {
-       /* Addr      5G_HT20     5G_HT40   */
-       {0x00009a00, 0x00000000, 0x00000000},
-       {0x00009a04, 0x00000040, 0x00000040},
-       {0x00009a08, 0x00000080, 0x00000080},
-       {0x00009a0c, 0x000001a1, 0x00000141},
-       {0x00009a10, 0x000001e1, 0x00000181},
-       {0x00009a14, 0x00000021, 0x000001c1},
-       {0x00009a18, 0x00000061, 0x00000001},
-       {0x00009a1c, 0x00000168, 0x00000041},
-       {0x00009a20, 0x000001a8, 0x000001a8},
-       {0x00009a24, 0x000001e8, 0x000001e8},
-       {0x00009a28, 0x00000028, 0x00000028},
-       {0x00009a2c, 0x00000068, 0x00000068},
-       {0x00009a30, 0x00000189, 0x000000a8},
-       {0x00009a34, 0x000001c9, 0x00000169},
-       {0x00009a38, 0x00000009, 0x000001a9},
-       {0x00009a3c, 0x00000049, 0x000001e9},
-       {0x00009a40, 0x00000089, 0x00000029},
-       {0x00009a44, 0x00000170, 0x00000069},
-       {0x00009a48, 0x000001b0, 0x00000190},
-       {0x00009a4c, 0x000001f0, 0x000001d0},
-       {0x00009a50, 0x00000030, 0x00000010},
-       {0x00009a54, 0x00000070, 0x00000050},
-       {0x00009a58, 0x00000191, 0x00000090},
-       {0x00009a5c, 0x000001d1, 0x00000151},
-       {0x00009a60, 0x00000011, 0x00000191},
-       {0x00009a64, 0x00000051, 0x000001d1},
-       {0x00009a68, 0x00000091, 0x00000011},
-       {0x00009a6c, 0x000001b8, 0x00000051},
-       {0x00009a70, 0x000001f8, 0x00000198},
-       {0x00009a74, 0x00000038, 0x000001d8},
-       {0x00009a78, 0x00000078, 0x00000018},
-       {0x00009a7c, 0x00000199, 0x00000058},
-       {0x00009a80, 0x000001d9, 0x00000098},
-       {0x00009a84, 0x00000019, 0x00000159},
-       {0x00009a88, 0x00000059, 0x00000199},
-       {0x00009a8c, 0x00000099, 0x000001d9},
-       {0x00009a90, 0x000000d9, 0x00000019},
-       {0x00009a94, 0x000000f9, 0x00000059},
-       {0x00009a98, 0x000000f9, 0x00000099},
-       {0x00009a9c, 0x000000f9, 0x000000d9},
-       {0x00009aa0, 0x000000f9, 0x000000f9},
-       {0x00009aa4, 0x000000f9, 0x000000f9},
-       {0x00009aa8, 0x000000f9, 0x000000f9},
-       {0x00009aac, 0x000000f9, 0x000000f9},
-       {0x00009ab0, 0x000000f9, 0x000000f9},
-       {0x00009ab4, 0x000000f9, 0x000000f9},
-       {0x00009ab8, 0x000000f9, 0x000000f9},
-       {0x00009abc, 0x000000f9, 0x000000f9},
-       {0x00009ac0, 0x000000f9, 0x000000f9},
-       {0x00009ac4, 0x000000f9, 0x000000f9},
-       {0x00009ac8, 0x000000f9, 0x000000f9},
-       {0x00009acc, 0x000000f9, 0x000000f9},
-       {0x00009ad0, 0x000000f9, 0x000000f9},
-       {0x00009ad4, 0x000000f9, 0x000000f9},
-       {0x00009ad8, 0x000000f9, 0x000000f9},
-       {0x00009adc, 0x000000f9, 0x000000f9},
-       {0x00009ae0, 0x000000f9, 0x000000f9},
-       {0x00009ae4, 0x000000f9, 0x000000f9},
-       {0x00009ae8, 0x000000f9, 0x000000f9},
-       {0x00009aec, 0x000000f9, 0x000000f9},
-       {0x00009af0, 0x000000f9, 0x000000f9},
-       {0x00009af4, 0x000000f9, 0x000000f9},
-       {0x00009af8, 0x000000f9, 0x000000f9},
-       {0x00009afc, 0x000000f9, 0x000000f9},
-};
-
-static const u32 ar5416Bank1_9160[][2] = {
-       /* Addr      allmodes  */
-       {0x000098b0, 0x02108421},
-       {0x000098ec, 0x00000008},
-};
-
-static const u32 ar5416Bank2_9160[][2] = {
-       /* Addr      allmodes  */
-       {0x000098b0, 0x0e73ff17},
-       {0x000098e0, 0x00000420},
-};
-
-static const u32 ar5416Bank3_9160[][3] = {
-       /* Addr      5G_HT20     5G_HT40   */
-       {0x000098f0, 0x01400018, 0x01c00018},
-};
-
-static const u32 ar5416Bank6_9160[][3] = {
-       /* Addr      5G_HT20     5G_HT40   */
-       {0x0000989c, 0x00000000, 0x00000000},
-       {0x0000989c, 0x00000000, 0x00000000},
-       {0x0000989c, 0x00000000, 0x00000000},
-       {0x0000989c, 0x00e00000, 0x00e00000},
-       {0x0000989c, 0x005e0000, 0x005e0000},
-       {0x0000989c, 0x00120000, 0x00120000},
-       {0x0000989c, 0x00620000, 0x00620000},
-       {0x0000989c, 0x00020000, 0x00020000},
-       {0x0000989c, 0x00ff0000, 0x00ff0000},
-       {0x0000989c, 0x00ff0000, 0x00ff0000},
-       {0x0000989c, 0x00ff0000, 0x00ff0000},
-       {0x0000989c, 0x40ff0000, 0x40ff0000},
-       {0x0000989c, 0x005f0000, 0x005f0000},
-       {0x0000989c, 0x00870000, 0x00870000},
-       {0x0000989c, 0x00f90000, 0x00f90000},
-       {0x0000989c, 0x007b0000, 0x007b0000},
-       {0x0000989c, 0x00ff0000, 0x00ff0000},
-       {0x0000989c, 0x00f50000, 0x00f50000},
-       {0x0000989c, 0x00dc0000, 0x00dc0000},
-       {0x0000989c, 0x00110000, 0x00110000},
-       {0x0000989c, 0x006100a8, 0x006100a8},
-       {0x0000989c, 0x004210a2, 0x004210a2},
-       {0x0000989c, 0x0014008f, 0x0014008f},
-       {0x0000989c, 0x00c40003, 0x00c40003},
-       {0x0000989c, 0x003000f2, 0x003000f2},
-       {0x0000989c, 0x00440016, 0x00440016},
-       {0x0000989c, 0x00410040, 0x00410040},
-       {0x0000989c, 0x0001805e, 0x0001805e},
-       {0x0000989c, 0x0000c0ab, 0x0000c0ab},
-       {0x0000989c, 0x000000f1, 0x000000f1},
-       {0x0000989c, 0x00002081, 0x00002081},
-       {0x0000989c, 0x000000d4, 0x000000d4},
-       {0x000098d0, 0x0000000f, 0x0010000f},
-};
-
-static const u32 ar5416Bank6TPC_9160[][3] = {
-       /* Addr      5G_HT20     5G_HT40   */
-       {0x0000989c, 0x00000000, 0x00000000},
-       {0x0000989c, 0x00000000, 0x00000000},
-       {0x0000989c, 0x00000000, 0x00000000},
-       {0x0000989c, 0x00e00000, 0x00e00000},
-       {0x0000989c, 0x005e0000, 0x005e0000},
-       {0x0000989c, 0x00120000, 0x00120000},
-       {0x0000989c, 0x00620000, 0x00620000},
-       {0x0000989c, 0x00020000, 0x00020000},
-       {0x0000989c, 0x00ff0000, 0x00ff0000},
-       {0x0000989c, 0x00ff0000, 0x00ff0000},
-       {0x0000989c, 0x00ff0000, 0x00ff0000},
-       {0x0000989c, 0x40ff0000, 0x40ff0000},
-       {0x0000989c, 0x005f0000, 0x005f0000},
-       {0x0000989c, 0x00870000, 0x00870000},
-       {0x0000989c, 0x00f90000, 0x00f90000},
-       {0x0000989c, 0x007b0000, 0x007b0000},
-       {0x0000989c, 0x00ff0000, 0x00ff0000},
-       {0x0000989c, 0x00f50000, 0x00f50000},
-       {0x0000989c, 0x00dc0000, 0x00dc0000},
-       {0x0000989c, 0x00110000, 0x00110000},
-       {0x0000989c, 0x006100a8, 0x006100a8},
-       {0x0000989c, 0x00423022, 0x00423022},
-       {0x0000989c, 0x2014008f, 0x2014008f},
-       {0x0000989c, 0x00c40002, 0x00c40002},
-       {0x0000989c, 0x003000f2, 0x003000f2},
-       {0x0000989c, 0x00440016, 0x00440016},
-       {0x0000989c, 0x00410040, 0x00410040},
-       {0x0000989c, 0x0001805e, 0x0001805e},
-       {0x0000989c, 0x0000c0ab, 0x0000c0ab},
-       {0x0000989c, 0x000000e1, 0x000000e1},
-       {0x0000989c, 0x00007080, 0x00007080},
-       {0x0000989c, 0x000000d4, 0x000000d4},
-       {0x000098d0, 0x0000000f, 0x0010000f},
-};
-
-static const u32 ar5416Bank7_9160[][2] = {
-       /* Addr      allmodes  */
-       {0x0000989c, 0x00000500},
-       {0x0000989c, 0x00000800},
-       {0x000098cc, 0x0000000e},
-};
-
 static const u32 ar5416Addac_9160[][2] = {
        /* Addr      allmodes  */
        {0x0000989c, 0x00000000},
index d190411ac8f51e5003fb2c639b7818be8df34b4c..e3f268900763a02374440717ba4490c2ebdca7c1 100644 (file)
@@ -35,11 +35,11 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
                INIT_INI_ARRAY(&ah->iniCommon, ar9271Common_9271,
                               ARRAY_SIZE(ar9271Common_9271), 2);
                INIT_INI_ARRAY(&ah->iniCommon_normal_cck_fir_coeff_9271,
-                              ar9271Common_normal_cck_fir_coeff_9271,
-                              ARRAY_SIZE(ar9271Common_normal_cck_fir_coeff_9271), 2);
+                              ar9287Common_normal_cck_fir_coeff_9287_1_1,
+                              ARRAY_SIZE(ar9287Common_normal_cck_fir_coeff_9287_1_1), 2);
                INIT_INI_ARRAY(&ah->iniCommon_japan_2484_cck_fir_coeff_9271,
-                              ar9271Common_japan_2484_cck_fir_coeff_9271,
-                              ARRAY_SIZE(ar9271Common_japan_2484_cck_fir_coeff_9271), 2);
+                              ar9287Common_japan_2484_cck_fir_coeff_9287_1_1,
+                              ARRAY_SIZE(ar9287Common_japan_2484_cck_fir_coeff_9287_1_1), 2);
                INIT_INI_ARRAY(&ah->iniModes_9271_1_0_only,
                               ar9271Modes_9271_1_0_only,
                               ARRAY_SIZE(ar9271Modes_9271_1_0_only), 5);
@@ -54,53 +54,31 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
                return;
        }
 
+       if (ah->config.pcie_clock_req)
+               INIT_INI_ARRAY(&ah->iniPcieSerdes,
+                          ar9280PciePhy_clkreq_off_L1_9280,
+                          ARRAY_SIZE(ar9280PciePhy_clkreq_off_L1_9280), 2);
+       else
+               INIT_INI_ARRAY(&ah->iniPcieSerdes,
+                          ar9280PciePhy_clkreq_always_on_L1_9280,
+                          ARRAY_SIZE(ar9280PciePhy_clkreq_always_on_L1_9280), 2);
+
        if (AR_SREV_9287_11_OR_LATER(ah)) {
                INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1,
                                ARRAY_SIZE(ar9287Modes_9287_1_1), 5);
                INIT_INI_ARRAY(&ah->iniCommon, ar9287Common_9287_1_1,
                                ARRAY_SIZE(ar9287Common_9287_1_1), 2);
-               if (ah->config.pcie_clock_req)
-                       INIT_INI_ARRAY(&ah->iniPcieSerdes,
-                       ar9287PciePhy_clkreq_off_L1_9287_1_1,
-                       ARRAY_SIZE(ar9287PciePhy_clkreq_off_L1_9287_1_1), 2);
-               else
-                       INIT_INI_ARRAY(&ah->iniPcieSerdes,
-                       ar9287PciePhy_clkreq_always_on_L1_9287_1_1,
-                       ARRAY_SIZE(ar9287PciePhy_clkreq_always_on_L1_9287_1_1),
-                                       2);
        } else if (AR_SREV_9285_12_OR_LATER(ah)) {
-
-
                INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285_1_2,
                               ARRAY_SIZE(ar9285Modes_9285_1_2), 5);
                INIT_INI_ARRAY(&ah->iniCommon, ar9285Common_9285_1_2,
                               ARRAY_SIZE(ar9285Common_9285_1_2), 2);
-
-               if (ah->config.pcie_clock_req) {
-                       INIT_INI_ARRAY(&ah->iniPcieSerdes,
-                       ar9285PciePhy_clkreq_off_L1_9285_1_2,
-                       ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285_1_2), 2);
-               } else {
-                       INIT_INI_ARRAY(&ah->iniPcieSerdes,
-                       ar9285PciePhy_clkreq_always_on_L1_9285_1_2,
-                       ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285_1_2),
-                                 2);
-               }
        } else if (AR_SREV_9280_20_OR_LATER(ah)) {
                INIT_INI_ARRAY(&ah->iniModes, ar9280Modes_9280_2,
                               ARRAY_SIZE(ar9280Modes_9280_2), 5);
                INIT_INI_ARRAY(&ah->iniCommon, ar9280Common_9280_2,
                               ARRAY_SIZE(ar9280Common_9280_2), 2);
 
-               if (ah->config.pcie_clock_req) {
-                       INIT_INI_ARRAY(&ah->iniPcieSerdes,
-                              ar9280PciePhy_clkreq_off_L1_9280,
-                              ARRAY_SIZE(ar9280PciePhy_clkreq_off_L1_9280), 2);
-               } else {
-                       INIT_INI_ARRAY(&ah->iniPcieSerdes,
-                              ar9280PciePhy_clkreq_always_on_L1_9280,
-                              ARRAY_SIZE(ar9280PciePhy_clkreq_always_on_L1_9280), 2);
-               }
                INIT_INI_ARRAY(&ah->iniModesAdditional,
                               ar9280Modes_fast_clock_9280_2,
                               ARRAY_SIZE(ar9280Modes_fast_clock_9280_2), 3);
@@ -109,22 +87,6 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
                               ARRAY_SIZE(ar5416Modes_9160), 5);
                INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9160,
                               ARRAY_SIZE(ar5416Common_9160), 2);
-               INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0_9160,
-                              ARRAY_SIZE(ar5416Bank0_9160), 2);
-               INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain_9160,
-                              ARRAY_SIZE(ar5416BB_RfGain_9160), 3);
-               INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1_9160,
-                              ARRAY_SIZE(ar5416Bank1_9160), 2);
-               INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2_9160,
-                              ARRAY_SIZE(ar5416Bank2_9160), 2);
-               INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3_9160,
-                              ARRAY_SIZE(ar5416Bank3_9160), 3);
-               INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6_9160,
-                              ARRAY_SIZE(ar5416Bank6_9160), 3);
-               INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC_9160,
-                              ARRAY_SIZE(ar5416Bank6TPC_9160), 3);
-               INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7_9160,
-                              ARRAY_SIZE(ar5416Bank7_9160), 2);
                if (AR_SREV_9160_11(ah)) {
                        INIT_INI_ARRAY(&ah->iniAddac,
                                       ar5416Addac_9160_1_1,
@@ -138,22 +100,8 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
                               ARRAY_SIZE(ar5416Modes_9100), 5);
                INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9100,
                               ARRAY_SIZE(ar5416Common_9100), 2);
-               INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0_9100,
-                              ARRAY_SIZE(ar5416Bank0_9100), 2);
-               INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain_9100,
-                              ARRAY_SIZE(ar5416BB_RfGain_9100), 3);
-               INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1_9100,
-                              ARRAY_SIZE(ar5416Bank1_9100), 2);
-               INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2_9100,
-                              ARRAY_SIZE(ar5416Bank2_9100), 2);
-               INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3_9100,
-                              ARRAY_SIZE(ar5416Bank3_9100), 3);
                INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6_9100,
                               ARRAY_SIZE(ar5416Bank6_9100), 3);
-               INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC_9100,
-                              ARRAY_SIZE(ar5416Bank6TPC_9100), 3);
-               INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7_9100,
-                              ARRAY_SIZE(ar5416Bank7_9100), 2);
                INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_9100,
                               ARRAY_SIZE(ar5416Addac_9100), 2);
        } else {
@@ -161,24 +109,37 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
                               ARRAY_SIZE(ar5416Modes), 5);
                INIT_INI_ARRAY(&ah->iniCommon, ar5416Common,
                               ARRAY_SIZE(ar5416Common), 2);
-               INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0,
-                              ARRAY_SIZE(ar5416Bank0), 2);
+               INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC,
+                              ARRAY_SIZE(ar5416Bank6TPC), 3);
+               INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac,
+                              ARRAY_SIZE(ar5416Addac), 2);
+       }
+
+       if (!AR_SREV_9280_20_OR_LATER(ah)) {
+               /* Common for AR5416, AR913x, AR9160 */
                INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain,
                               ARRAY_SIZE(ar5416BB_RfGain), 3);
+
+               INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0,
+                              ARRAY_SIZE(ar5416Bank0), 2);
                INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1,
                               ARRAY_SIZE(ar5416Bank1), 2);
                INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2,
                               ARRAY_SIZE(ar5416Bank2), 2);
                INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3,
                               ARRAY_SIZE(ar5416Bank3), 3);
-               INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6,
-                              ARRAY_SIZE(ar5416Bank6), 3);
-               INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC,
-                              ARRAY_SIZE(ar5416Bank6TPC), 3);
                INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7,
                               ARRAY_SIZE(ar5416Bank7), 2);
-               INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac,
-                              ARRAY_SIZE(ar5416Addac), 2);
+
+               /* Common for AR5416, AR9160 */
+               if (!AR_SREV_9100(ah))
+                       INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6,
+                                      ARRAY_SIZE(ar5416Bank6), 3);
+
+               /* Common for AR913x, AR9160 */
+               if (!AR_SREV_5416(ah))
+                       INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC_9100,
+                                      ARRAY_SIZE(ar5416Bank6TPC_9100), 3);
        }
 
        /* iniAddac needs to be modified for these chips */
index 863db321070d7b31a8c390129ee7e33588a14cef..d571c329ee597c4c32841bd987fc05dafec9fc90 100644 (file)
@@ -925,34 +925,6 @@ static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = {
        {0x00004044, 0x00000000},
 };
 
-static const u32 ar9285PciePhy_clkreq_always_on_L1_9285[][2] = {
-       /* Addr      allmodes  */
-       {0x00004040, 0x9248fd00},
-       {0x00004040, 0x24924924},
-       {0x00004040, 0xa8000019},
-       {0x00004040, 0x13160820},
-       {0x00004040, 0xe5980560},
-       {0x00004040, 0xc01dcffd},
-       {0x00004040, 0x1aaabe41},
-       {0x00004040, 0xbe105554},
-       {0x00004040, 0x00043007},
-       {0x00004044, 0x00000000},
-};
-
-static const u32 ar9285PciePhy_clkreq_off_L1_9285[][2] = {
-       /* Addr      allmodes  */
-       {0x00004040, 0x9248fd00},
-       {0x00004040, 0x24924924},
-       {0x00004040, 0xa8000019},
-       {0x00004040, 0x13160820},
-       {0x00004040, 0xe5980560},
-       {0x00004040, 0xc01dcffc},
-       {0x00004040, 0x1aaabe41},
-       {0x00004040, 0xbe105554},
-       {0x00004040, 0x00043007},
-       {0x00004044, 0x00000000},
-};
-
 static const u32 ar9285Modes_9285_1_2[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160},
@@ -1743,34 +1715,6 @@ static const u32 ar9285Modes_XE2_0_high_power[][5] = {
        {0x0000a3e0, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7},
 };
 
-static const u32 ar9285PciePhy_clkreq_always_on_L1_9285_1_2[][2] = {
-       /* Addr      allmodes  */
-       {0x00004040, 0x9248fd00},
-       {0x00004040, 0x24924924},
-       {0x00004040, 0xa8000019},
-       {0x00004040, 0x13160820},
-       {0x00004040, 0xe5980560},
-       {0x00004040, 0xc01dcffd},
-       {0x00004040, 0x1aaabe41},
-       {0x00004040, 0xbe105554},
-       {0x00004040, 0x00043007},
-       {0x00004044, 0x00000000},
-};
-
-static const u32 ar9285PciePhy_clkreq_off_L1_9285_1_2[][2] = {
-       /* Addr      allmodes  */
-       {0x00004040, 0x9248fd00},
-       {0x00004040, 0x24924924},
-       {0x00004040, 0xa8000019},
-       {0x00004040, 0x13160820},
-       {0x00004040, 0xe5980560},
-       {0x00004040, 0xc01dcffc},
-       {0x00004040, 0x1aaabe41},
-       {0x00004040, 0xbe105554},
-       {0x00004040, 0x00043007},
-       {0x00004044, 0x00000000},
-};
-
 static const u32 ar9287Modes_9287_1_1[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x00001030, 0x00000000, 0x00000000, 0x000002c0, 0x00000160},
@@ -2512,34 +2456,6 @@ static const u32 ar9287Modes_rx_gain_9287_1_1[][5] = {
        {0x0000a848, 0x00000000, 0x00000000, 0x00001067, 0x00001067},
 };
 
-static const u32 ar9287PciePhy_clkreq_always_on_L1_9287_1_1[][2] = {
-       /* Addr      allmodes  */
-       {0x00004040, 0x9248fd00},
-       {0x00004040, 0x24924924},
-       {0x00004040, 0xa8000019},
-       {0x00004040, 0x13160820},
-       {0x00004040, 0xe5980560},
-       {0x00004040, 0xc01dcffd},
-       {0x00004040, 0x1aaabe41},
-       {0x00004040, 0xbe105554},
-       {0x00004040, 0x00043007},
-       {0x00004044, 0x00000000},
-};
-
-static const u32 ar9287PciePhy_clkreq_off_L1_9287_1_1[][2] = {
-       /* Addr      allmodes  */
-       {0x00004040, 0x9248fd00},
-       {0x00004040, 0x24924924},
-       {0x00004040, 0xa8000019},
-       {0x00004040, 0x13160820},
-       {0x00004040, 0xe5980560},
-       {0x00004040, 0xc01dcffc},
-       {0x00004040, 0x1aaabe41},
-       {0x00004040, 0xbe105554},
-       {0x00004040, 0x00043007},
-       {0x00004044, 0x00000000},
-};
-
 static const u32 ar9271Modes_9271[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160},
@@ -3176,20 +3092,6 @@ static const u32 ar9271Common_9271[][2] = {
        {0x0000d384, 0xf3307ff0},
 };
 
-static const u32 ar9271Common_normal_cck_fir_coeff_9271[][2] = {
-       /* Addr      allmodes  */
-       {0x0000a1f4, 0x00fffeff},
-       {0x0000a1f8, 0x00f5f9ff},
-       {0x0000a1fc, 0xb79f6427},
-};
-
-static const u32 ar9271Common_japan_2484_cck_fir_coeff_9271[][2] = {
-       /* Addr      allmodes  */
-       {0x0000a1f4, 0x00000000},
-       {0x0000a1f8, 0xefff0301},
-       {0x0000a1fc, 0xca9228ee},
-};
-
 static const u32 ar9271Modes_9271_1_0_only[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x00009910, 0x30002311, 0x30002311, 0x30002311, 0x30002311},
index 8e70f0bc073e2d12a554428701e67184f538a3c5..63089cc1fafd6366d4209d33e1de28c5b4bd3bb0 100644 (file)
@@ -925,7 +925,6 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
 {
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_hw_cal_data *caldata = ah->caldata;
-       struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
        bool txiqcal_done = false, txclcal_done = false;
        bool is_reusable = true, status = true;
        bool run_rtt_cal = false, run_agc_cal;
@@ -998,30 +997,8 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
        } else if (caldata && !caldata->done_txiqcal_once)
                run_agc_cal = true;
 
-       if (mci && IS_CHAN_2GHZ(chan) &&
-           (mci_hw->bt_state  == MCI_BT_AWAKE) &&
-           run_agc_cal &&
-           !(mci_hw->config & ATH_MCI_CONFIG_DISABLE_MCI_CAL)) {
-
-               u32 pld[4] = {0, 0, 0, 0};
-
-               /* send CAL_REQ only when BT is AWAKE. */
-               ath_dbg(common, MCI, "MCI send WLAN_CAL_REQ 0x%x\n",
-                       mci_hw->wlan_cal_seq);
-               MCI_GPM_SET_CAL_TYPE(pld, MCI_GPM_WLAN_CAL_REQ);
-               pld[MCI_GPM_WLAN_CAL_W_SEQUENCE] = mci_hw->wlan_cal_seq++;
-               ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, true, false);
-
-               /* Wait BT_CAL_GRANT for 50ms */
-               ath_dbg(common, MCI, "MCI wait for BT_CAL_GRANT\n");
-
-               if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_GRANT, 0, 50000))
-                       ath_dbg(common, MCI, "MCI got BT_CAL_GRANT\n");
-               else {
-                       is_reusable = false;
-                       ath_dbg(common, MCI, "\nMCI BT is not responding\n");
-               }
-       }
+       if (mci && IS_CHAN_2GHZ(chan) && run_agc_cal)
+               ar9003_mci_init_cal_req(ah, &is_reusable);
 
        txiqcal_done = ar9003_hw_tx_iq_cal_run(ah);
        REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
@@ -1041,19 +1018,8 @@ skip_tx_iqcal:
                                       0, AH_WAIT_TIMEOUT);
        }
 
-       if (mci && IS_CHAN_2GHZ(chan) &&
-           (mci_hw->bt_state  == MCI_BT_AWAKE) &&
-           run_agc_cal &&
-           !(mci_hw->config & ATH_MCI_CONFIG_DISABLE_MCI_CAL)) {
-
-               u32 pld[4] = {0, 0, 0, 0};
-
-               ath_dbg(common, MCI, "MCI Send WLAN_CAL_DONE 0x%x\n",
-                       mci_hw->wlan_cal_done);
-               MCI_GPM_SET_CAL_TYPE(pld, MCI_GPM_WLAN_CAL_DONE);
-               pld[MCI_GPM_WLAN_CAL_W_SEQUENCE] = mci_hw->wlan_cal_done++;
-               ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, true, false);
-       }
+       if (mci && IS_CHAN_2GHZ(chan) && run_agc_cal)
+               ar9003_mci_init_cal_done(ah);
 
        if (rtt && !run_rtt_cal) {
                agc_ctrl |= agc_supp_cals;
index 9fbcbddea1658ece3080bc286eec0e8a353ee583..6bb4db052bb0b23aef5d50a607fcafdca9c20a16 100644 (file)
@@ -3603,10 +3603,6 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
        u32 value = ar9003_hw_ant_ctrl_common_get(ah, is2ghz);
 
        if (AR_SREV_9462(ah)) {
-               if (AR_SREV_9462_10(ah)) {
-                       value &= ~AR_SWITCH_TABLE_COM_SPDT;
-                       value |= 0x00100000;
-               }
                REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM,
                                AR_SWITCH_TABLE_COM_AR9462_ALL, value);
        } else
index fb937ba93e0c6a763dc82b476917bfc9c0d9409f..7b4aa000cc2ecdb3df3931b96e04dfe4f0597713 100644 (file)
@@ -22,7 +22,6 @@
 #include "ar9330_1p1_initvals.h"
 #include "ar9330_1p2_initvals.h"
 #include "ar9580_1p0_initvals.h"
-#include "ar9462_1p0_initvals.h"
 #include "ar9462_2p0_initvals.h"
 
 /* General hardware code for the AR9003 hadware family */
@@ -264,63 +263,6 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
                                ar9485_1_1_pcie_phy_clkreq_disable_L1,
                                ARRAY_SIZE(ar9485_1_1_pcie_phy_clkreq_disable_L1),
                                2);
-       } else if (AR_SREV_9462_10(ah)) {
-               INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
-               INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], ar9462_1p0_mac_core,
-                               ARRAY_SIZE(ar9462_1p0_mac_core), 2);
-               INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST],
-                               ar9462_1p0_mac_postamble,
-                               ARRAY_SIZE(ar9462_1p0_mac_postamble),
-                               5);
-
-               INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0);
-               INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE],
-                               ar9462_1p0_baseband_core,
-                               ARRAY_SIZE(ar9462_1p0_baseband_core),
-                               2);
-               INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST],
-                               ar9462_1p0_baseband_postamble,
-                               ARRAY_SIZE(ar9462_1p0_baseband_postamble), 5);
-
-               INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0);
-               INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE],
-                               ar9462_1p0_radio_core,
-                               ARRAY_SIZE(ar9462_1p0_radio_core), 2);
-               INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST],
-                               ar9462_1p0_radio_postamble,
-                               ARRAY_SIZE(ar9462_1p0_radio_postamble), 5);
-
-               INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE],
-                               ar9462_1p0_soc_preamble,
-                               ARRAY_SIZE(ar9462_1p0_soc_preamble), 2);
-               INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0);
-               INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST],
-                               ar9462_1p0_soc_postamble,
-                               ARRAY_SIZE(ar9462_1p0_soc_postamble), 5);
-
-               INIT_INI_ARRAY(&ah->iniModesRxGain,
-                               ar9462_common_rx_gain_table_1p0,
-                               ARRAY_SIZE(ar9462_common_rx_gain_table_1p0), 2);
-
-               /* Awake -> Sleep Setting */
-               INIT_INI_ARRAY(&ah->iniPcieSerdes,
-                       ar9462_pcie_phy_clkreq_disable_L1_1p0,
-                       ARRAY_SIZE(ar9462_pcie_phy_clkreq_disable_L1_1p0),
-                       2);
-
-               /* Sleep -> Awake Setting */
-               INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower,
-                       ar9462_pcie_phy_clkreq_disable_L1_1p0,
-                       ARRAY_SIZE(ar9462_pcie_phy_clkreq_disable_L1_1p0),
-                       2);
-
-               INIT_INI_ARRAY(&ah->iniModesAdditional,
-                               ar9462_modes_fast_clock_1p0,
-                               ARRAY_SIZE(ar9462_modes_fast_clock_1p0), 3);
-               INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
-                               AR9462_BB_CTX_COEFJ(1p0),
-                               ARRAY_SIZE(AR9462_BB_CTX_COEFJ(1p0)), 2);
-
        } else if (AR_SREV_9462_20(ah)) {
 
                INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
@@ -537,11 +479,6 @@ static void ar9003_tx_gain_table_mode0(struct ath_hw *ah)
                        ar9580_1p0_lowest_ob_db_tx_gain_table,
                        ARRAY_SIZE(ar9580_1p0_lowest_ob_db_tx_gain_table),
                        5);
-       else if (AR_SREV_9462_10(ah))
-               INIT_INI_ARRAY(&ah->iniModesTxGain,
-                       ar9462_modes_low_ob_db_tx_gain_table_1p0,
-                       ARRAY_SIZE(ar9462_modes_low_ob_db_tx_gain_table_1p0),
-                       5);
        else if (AR_SREV_9462_20(ah))
                INIT_INI_ARRAY(&ah->iniModesTxGain,
                        ar9462_modes_low_ob_db_tx_gain_table_2p0,
@@ -581,11 +518,6 @@ static void ar9003_tx_gain_table_mode1(struct ath_hw *ah)
                        ar9580_1p0_high_ob_db_tx_gain_table,
                        ARRAY_SIZE(ar9580_1p0_high_ob_db_tx_gain_table),
                        5);
-       else if (AR_SREV_9462_10(ah))
-               INIT_INI_ARRAY(&ah->iniModesTxGain,
-                       ar9462_modes_high_ob_db_tx_gain_table_1p0,
-                       ARRAY_SIZE(ar9462_modes_high_ob_db_tx_gain_table_1p0),
-                       5);
        else if (AR_SREV_9462_20(ah))
                INIT_INI_ARRAY(&ah->iniModesTxGain,
                        ar9462_modes_high_ob_db_tx_gain_table_2p0,
@@ -712,11 +644,6 @@ static void ar9003_rx_gain_table_mode0(struct ath_hw *ah)
                                ar9580_1p0_rx_gain_table,
                                ARRAY_SIZE(ar9580_1p0_rx_gain_table),
                                2);
-       else if (AR_SREV_9462_10(ah))
-               INIT_INI_ARRAY(&ah->iniModesRxGain,
-                               ar9462_common_rx_gain_table_1p0,
-                               ARRAY_SIZE(ar9462_common_rx_gain_table_1p0),
-                               2);
        else if (AR_SREV_9462_20(ah))
                INIT_INI_ARRAY(&ah->iniModesRxGain,
                                ar9462_common_rx_gain_table_2p0,
@@ -751,11 +678,6 @@ static void ar9003_rx_gain_table_mode1(struct ath_hw *ah)
                        ar9485Common_wo_xlna_rx_gain_1_1,
                        ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1),
                        2);
-       else if (AR_SREV_9462_10(ah))
-               INIT_INI_ARRAY(&ah->iniModesRxGain,
-                       ar9462_common_wo_xlna_rx_gain_table_1p0,
-                       ARRAY_SIZE(ar9462_common_wo_xlna_rx_gain_table_1p0),
-                       2);
        else if (AR_SREV_9462_20(ah))
                INIT_INI_ARRAY(&ah->iniModesRxGain,
                        ar9462_common_wo_xlna_rx_gain_table_2p0,
@@ -775,14 +697,10 @@ static void ar9003_rx_gain_table_mode1(struct ath_hw *ah)
 
 static void ar9003_rx_gain_table_mode2(struct ath_hw *ah)
 {
-       if (AR_SREV_9462_10(ah))
-               INIT_INI_ARRAY(&ah->iniModesRxGain,
-                       ar9462_common_mixed_rx_gain_table_1p0,
-                       ARRAY_SIZE(ar9462_common_mixed_rx_gain_table_1p0), 2);
-       else if (AR_SREV_9462_20(ah))
+       if (AR_SREV_9462_20(ah))
                INIT_INI_ARRAY(&ah->iniModesRxGain,
-                       ar9462_common_mixed_rx_gain_table_2p0,
-                       ARRAY_SIZE(ar9462_common_mixed_rx_gain_table_2p0), 2);
+                              ar9462_common_mixed_rx_gain_table_2p0,
+                              ARRAY_SIZE(ar9462_common_mixed_rx_gain_table_2p0), 2);
 }
 
 static void ar9003_rx_gain_table_apply(struct ath_hw *ah)
index 09b8c9dbf78f5e3267ebfadc2d4bed15f9562487..a66a13b768487746b96c1ebdca96c87df89681f4 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/export.h>
 #include "hw.h"
 #include "ar9003_mac.h"
+#include "ar9003_mci.h"
 
 static void ar9003_hw_rx_enable(struct ath_hw *hw)
 {
@@ -28,11 +29,14 @@ ar9003_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i)
        struct ar9003_txc *ads = ds;
        int checksum = 0;
        u32 val, ctl12, ctl17;
+       u8 desc_len;
+
+       desc_len = (AR_SREV_9462(ah) ? 0x18 : 0x17);
 
        val = (ATHEROS_VENDOR_ID << AR_DescId_S) |
              (1 << AR_TxRxDesc_S) |
              (1 << AR_CtrlStat_S) |
-             (i->qcu << AR_TxQcuNum_S) | 0x17;
+             (i->qcu << AR_TxQcuNum_S) | desc_len;
 
        checksum += val;
        ACCESS_ONCE(ads->info) = val;
@@ -81,6 +85,7 @@ ar9003_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i)
        ads->ctl20 = 0;
        ads->ctl21 = 0;
        ads->ctl22 = 0;
+       ads->ctl23 = 0;
 
        ctl17 = SM(i->keytype, AR_EncrType);
        if (!i->is_first) {
@@ -176,7 +181,6 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
        u32 mask2 = 0;
        struct ath9k_hw_capabilities *pCap = &ah->caps;
        struct ath_common *common = ath9k_hw_common(ah);
-       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
        u32 sync_cause = 0, async_cause;
 
        async_cause = REG_READ(ah, AR_INTR_ASYNC_CAUSE);
@@ -298,32 +302,8 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
                        ar9003_hw_bb_watchdog_read(ah);
        }
 
-       if (async_cause & AR_INTR_ASYNC_MASK_MCI) {
-               u32 raw_intr, rx_msg_intr;
-
-               rx_msg_intr = REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW);
-               raw_intr = REG_READ(ah, AR_MCI_INTERRUPT_RAW);
-
-               if ((raw_intr == 0xdeadbeef) || (rx_msg_intr == 0xdeadbeef))
-                       ath_dbg(common, MCI,
-                               "MCI gets 0xdeadbeef during MCI int processing new raw_intr=0x%08x, new rx_msg_raw=0x%08x, raw_intr=0x%08x, rx_msg_raw=0x%08x\n",
-                               raw_intr, rx_msg_intr, mci->raw_intr,
-                               mci->rx_msg_intr);
-               else {
-                       mci->rx_msg_intr |= rx_msg_intr;
-                       mci->raw_intr |= raw_intr;
-                       *masked |= ATH9K_INT_MCI;
-
-                       if (rx_msg_intr & AR_MCI_INTERRUPT_RX_MSG_CONT_INFO)
-                               mci->cont_status =
-                                       REG_READ(ah, AR_MCI_CONT_STATUS);
-
-                       REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, rx_msg_intr);
-                       REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, raw_intr);
-                       ath_dbg(common, MCI, "AR_INTR_SYNC_MCI\n");
-
-               }
-       }
+       if (async_cause & AR_INTR_ASYNC_MASK_MCI)
+               ar9003_mci_get_isr(ah, masked);
 
        if (sync_cause) {
                if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) {
@@ -346,7 +326,6 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
 static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds,
                                 struct ath_tx_status *ts)
 {
-       struct ar9003_txc *txc = (struct ar9003_txc *) ds;
        struct ar9003_txs *ads;
        u32 status;
 
@@ -356,11 +335,7 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds,
        if ((status & AR_TxDone) == 0)
                return -EINPROGRESS;
 
-       ts->qid = MS(ads->ds_info, AR_TxQcuNum);
-       if (!txc || (MS(txc->info, AR_TxQcuNum) == ts->qid))
-               ah->ts_tail = (ah->ts_tail + 1) % ah->ts_size;
-       else
-               return -ENOENT;
+       ah->ts_tail = (ah->ts_tail + 1) % ah->ts_size;
 
        if ((MS(ads->ds_info, AR_DescId) != ATHEROS_VENDOR_ID) ||
            (MS(ads->ds_info, AR_TxRxDesc) != 1)) {
@@ -374,6 +349,7 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds,
        ts->ts_seqnum = MS(status, AR_SeqNum);
        ts->tid = MS(status, AR_TxTid);
 
+       ts->qid = MS(ads->ds_info, AR_TxQcuNum);
        ts->desc_id = MS(ads->status1, AR_TxDescId);
        ts->ts_tstamp = ads->status4;
        ts->ts_status = 0;
@@ -460,20 +436,14 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs,
        struct ar9003_rxs *rxsp = (struct ar9003_rxs *) buf_addr;
        unsigned int phyerr;
 
-       /* TODO: byte swap on big endian for ar9300_10 */
-
-       if (!rxs) {
-               if ((rxsp->status11 & AR_RxDone) == 0)
-                       return -EINPROGRESS;
-
-               if (MS(rxsp->ds_info, AR_DescId) != 0x168c)
-                       return -EINVAL;
+       if ((rxsp->status11 & AR_RxDone) == 0)
+               return -EINPROGRESS;
 
-               if ((rxsp->ds_info & (AR_TxRxDesc | AR_CtrlStat)) != 0)
-                       return -EINPROGRESS;
+       if (MS(rxsp->ds_info, AR_DescId) != 0x168c)
+               return -EINVAL;
 
-               return 0;
-       }
+       if ((rxsp->ds_info & (AR_TxRxDesc | AR_CtrlStat)) != 0)
+               return -EINPROGRESS;
 
        rxs->rs_status = 0;
        rxs->rs_flags =  0;
@@ -530,7 +500,11 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs,
                 */
                if (rxsp->status11 & AR_CRCErr)
                        rxs->rs_status |= ATH9K_RXERR_CRC;
-               else if (rxsp->status11 & AR_PHYErr) {
+               else if (rxsp->status11 & AR_DecryptCRCErr)
+                       rxs->rs_status |= ATH9K_RXERR_DECRYPT;
+               else if (rxsp->status11 & AR_MichaelErr)
+                       rxs->rs_status |= ATH9K_RXERR_MIC;
+               if (rxsp->status11 & AR_PHYErr) {
                        phyerr = MS(rxsp->status11, AR_PHYErrCode);
                        /*
                         * If we reach a point here where AR_PostDelimCRCErr is
@@ -552,11 +526,7 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs,
                                rxs->rs_status |= ATH9K_RXERR_PHY;
                                rxs->rs_phyerr = phyerr;
                        }
-
-               } else if (rxsp->status11 & AR_DecryptCRCErr)
-                       rxs->rs_status |= ATH9K_RXERR_DECRYPT;
-               else if (rxsp->status11 & AR_MichaelErr)
-                       rxs->rs_status |= ATH9K_RXERR_MIC;
+               };
        }
 
        if (rxsp->status11 & AR_KeyMiss)
index e203b51e968bfbee59888697d733a59a5031e742..cbf60b090bd92dc62e3337349765ce7e8e37e68d 100644 (file)
@@ -92,7 +92,8 @@ struct ar9003_txc {
        u32 ctl20;  /* DMA control 20 */
        u32 ctl21;  /* DMA control 21 */
        u32 ctl22;  /* DMA control 22 */
-       u32 pad[9]; /* pad to cache line (128 bytes/32 dwords) */
+       u32 ctl23;  /* DMA control 23 */
+       u32 pad[8]; /* pad to cache line (128 bytes/32 dwords) */
 } __packed __aligned(4);
 
 struct ar9003_txs {
index 709520c6835bd62444a8aa1f713fd67264be6985..3cac293a284915c5f53097ac9224742d78557aed 100644 (file)
 
 #include <linux/export.h>
 #include "hw.h"
+#include "hw-ops.h"
 #include "ar9003_phy.h"
 #include "ar9003_mci.h"
 
 static void ar9003_mci_reset_req_wakeup(struct ath_hw *ah)
 {
-       if (!AR_SREV_9462_20(ah))
-               return;
-
        REG_RMW_FIELD(ah, AR_MCI_COMMAND2,
                      AR_MCI_COMMAND2_RESET_REQ_WAKEUP, 1);
        udelay(1);
@@ -37,13 +35,10 @@ static int ar9003_mci_wait_for_interrupt(struct ath_hw *ah, u32 address,
        struct ath_common *common = ath9k_hw_common(ah);
 
        while (time_out) {
-
                if (REG_READ(ah, address) & bit_position) {
-
                        REG_WRITE(ah, address, bit_position);
 
                        if (address == AR_MCI_INTERRUPT_RX_MSG_RAW) {
-
                                if (bit_position &
                                    AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)
                                        ar9003_mci_reset_req_wakeup(ah);
@@ -81,25 +76,19 @@ static int ar9003_mci_wait_for_interrupt(struct ath_hw *ah, u32 address,
        return time_out;
 }
 
-void ar9003_mci_remote_reset(struct ath_hw *ah, bool wait_done)
+static void ar9003_mci_remote_reset(struct ath_hw *ah, bool wait_done)
 {
        u32 payload[4] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffff00};
 
-       if (!ATH9K_HW_CAP_MCI)
-               return;
-
        ar9003_mci_send_message(ah, MCI_REMOTE_RESET, 0, payload, 16,
                                wait_done, false);
        udelay(5);
 }
 
-void ar9003_mci_send_lna_transfer(struct ath_hw *ah, bool wait_done)
+static void ar9003_mci_send_lna_transfer(struct ath_hw *ah, bool wait_done)
 {
        u32 payload = 0x00000000;
 
-       if (!ATH9K_HW_CAP_MCI)
-               return;
-
        ar9003_mci_send_message(ah, MCI_LNA_TRANS, 0, &payload, 1,
                                wait_done, false);
 }
@@ -111,11 +100,8 @@ static void ar9003_mci_send_req_wake(struct ath_hw *ah, bool wait_done)
        udelay(5);
 }
 
-void ar9003_mci_send_sys_waking(struct ath_hw *ah, bool wait_done)
+static void ar9003_mci_send_sys_waking(struct ath_hw *ah, bool wait_done)
 {
-       if (!ATH9K_HW_CAP_MCI)
-               return;
-
        ar9003_mci_send_message(ah, MCI_SYS_WAKING, MCI_FLAG_DISABLE_TIMESTAMP,
                                NULL, 0, wait_done, false);
 }
@@ -138,30 +124,27 @@ static void ar9003_mci_send_sys_sleeping(struct ath_hw *ah, bool wait_done)
 static void ar9003_mci_send_coex_version_query(struct ath_hw *ah,
                                               bool wait_done)
 {
-       struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
        u32 payload[4] = {0, 0, 0, 0};
 
        if (!mci->bt_version_known &&
-                       (mci->bt_state != MCI_BT_SLEEP)) {
-               ath_dbg(common, MCI, "MCI Send Coex version query\n");
+           (mci->bt_state != MCI_BT_SLEEP)) {
                MCI_GPM_SET_TYPE_OPCODE(payload,
-                               MCI_GPM_COEX_AGENT, MCI_GPM_COEX_VERSION_QUERY);
+                                       MCI_GPM_COEX_AGENT,
+                                       MCI_GPM_COEX_VERSION_QUERY);
                ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
-                               wait_done, true);
+                                       wait_done, true);
        }
 }
 
 static void ar9003_mci_send_coex_version_response(struct ath_hw *ah,
-                                                    bool wait_done)
+                                                 bool wait_done)
 {
-       struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
        u32 payload[4] = {0, 0, 0, 0};
 
-       ath_dbg(common, MCI, "MCI Send Coex version response\n");
        MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT,
-                       MCI_GPM_COEX_VERSION_RESPONSE);
+                               MCI_GPM_COEX_VERSION_RESPONSE);
        *(((u8 *)payload) + MCI_GPM_COEX_B_MAJOR_VERSION) =
                mci->wlan_ver_major;
        *(((u8 *)payload) + MCI_GPM_COEX_B_MINOR_VERSION) =
@@ -170,15 +153,16 @@ static void ar9003_mci_send_coex_version_response(struct ath_hw *ah,
 }
 
 static void ar9003_mci_send_coex_wlan_channels(struct ath_hw *ah,
-                                                 bool wait_done)
+                                              bool wait_done)
 {
        struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
        u32 *payload = &mci->wlan_channels[0];
 
        if ((mci->wlan_channels_update == true) &&
-                       (mci->bt_state != MCI_BT_SLEEP)) {
+           (mci->bt_state != MCI_BT_SLEEP)) {
                MCI_GPM_SET_TYPE_OPCODE(payload,
-               MCI_GPM_COEX_AGENT, MCI_GPM_COEX_WLAN_CHANNELS);
+                                       MCI_GPM_COEX_AGENT,
+                                       MCI_GPM_COEX_WLAN_CHANNELS);
                ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
                                        wait_done, true);
                MCI_GPM_SET_TYPE_OPCODE(payload, 0xff, 0xff);
@@ -188,7 +172,6 @@ static void ar9003_mci_send_coex_wlan_channels(struct ath_hw *ah,
 static void ar9003_mci_send_coex_bt_status_query(struct ath_hw *ah,
                                                bool wait_done, u8 query_type)
 {
-       struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
        u32 payload[4] = {0, 0, 0, 0};
        bool query_btinfo = !!(query_type & (MCI_GPM_COEX_QUERY_BT_ALL_INFO |
@@ -196,25 +179,19 @@ static void ar9003_mci_send_coex_bt_status_query(struct ath_hw *ah,
 
        if (mci->bt_state != MCI_BT_SLEEP) {
 
-               ath_dbg(common, MCI, "MCI Send Coex BT Status Query 0x%02X\n",
-                       query_type);
-
-               MCI_GPM_SET_TYPE_OPCODE(payload,
-                               MCI_GPM_COEX_AGENT, MCI_GPM_COEX_STATUS_QUERY);
+               MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT,
+                                       MCI_GPM_COEX_STATUS_QUERY);
 
                *(((u8 *)payload) + MCI_GPM_COEX_B_BT_BITMAP) = query_type;
+
                /*
                 * If bt_status_query message is  not sent successfully,
                 * then need_flush_btinfo should be set again.
                 */
                if (!ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
                                             wait_done, true)) {
-                       if (query_btinfo) {
+                       if (query_btinfo)
                                mci->need_flush_btinfo = true;
-
-                               ath_dbg(common, MCI,
-                                       "MCI send bt_status_query fail, set flush flag again\n");
-                       }
                }
 
                if (query_btinfo)
@@ -222,21 +199,14 @@ static void ar9003_mci_send_coex_bt_status_query(struct ath_hw *ah,
        }
 }
 
-void ar9003_mci_send_coex_halt_bt_gpm(struct ath_hw *ah, bool halt,
-                                     bool wait_done)
+static void ar9003_mci_send_coex_halt_bt_gpm(struct ath_hw *ah, bool halt,
+                                            bool wait_done)
 {
-       struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
        u32 payload[4] = {0, 0, 0, 0};
 
-       if (!ATH9K_HW_CAP_MCI)
-               return;
-
-       ath_dbg(common, MCI, "MCI Send Coex %s BT GPM\n",
-               (halt) ? "halt" : "unhalt");
-
-       MCI_GPM_SET_TYPE_OPCODE(payload,
-                               MCI_GPM_COEX_AGENT, MCI_GPM_COEX_HALT_BT_GPM);
+       MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT,
+                               MCI_GPM_COEX_HALT_BT_GPM);
 
        if (halt) {
                mci->query_bt = true;
@@ -252,7 +222,6 @@ void ar9003_mci_send_coex_halt_bt_gpm(struct ath_hw *ah, bool halt,
        ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, wait_done, true);
 }
 
-
 static void ar9003_mci_prep_interface(struct ath_hw *ah)
 {
        struct ath_common *common = ath9k_hw_common(ah);
@@ -269,30 +238,14 @@ static void ar9003_mci_prep_interface(struct ath_hw *ah)
        REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
                  REG_READ(ah, AR_MCI_INTERRUPT_RAW));
 
-       /* Remote Reset */
-       ath_dbg(common, MCI, "MCI Reset sequence start\n");
-       ath_dbg(common, MCI, "MCI send REMOTE_RESET\n");
        ar9003_mci_remote_reset(ah, true);
-
-       /*
-        * This delay is required for the reset delay worst case value 255 in
-        * MCI_COMMAND2 register
-        */
-
-       if (AR_SREV_9462_10(ah))
-               udelay(252);
-
-       ath_dbg(common, MCI, "MCI Send REQ_WAKE to remoter(BT)\n");
        ar9003_mci_send_req_wake(ah, true);
 
        if (ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
-                               AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING, 500)) {
+                                 AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING, 500)) {
 
-               ath_dbg(common, MCI, "MCI SYS_WAKING from remote(BT)\n");
                mci->bt_state = MCI_BT_AWAKE;
 
-               if (AR_SREV_9462_10(ah))
-                       udelay(10);
                /*
                 * we don't need to send more remote_reset at this moment.
                 * If BT receive first remote_reset, then BT HW will
@@ -309,11 +262,6 @@ static void ar9003_mci_prep_interface(struct ath_hw *ah)
                 * Similarly, if in any case, WLAN can receive BT's sys_waking,
                 * that means WLAN's RX is also fine.
                 */
-
-               /* Send SYS_WAKING to BT */
-
-               ath_dbg(common, MCI, "MCI send SW SYS_WAKING to remote BT\n");
-
                ar9003_mci_send_sys_waking(ah, true);
                udelay(10);
 
@@ -321,7 +269,6 @@ static void ar9003_mci_prep_interface(struct ath_hw *ah)
                 * Set BT priority interrupt value to be 0xff to
                 * avoid having too many BT PRIORITY interrupts.
                 */
-
                REG_WRITE(ah, AR_MCI_BT_PRI0, 0xFFFFFFFF);
                REG_WRITE(ah, AR_MCI_BT_PRI1, 0xFFFFFFFF);
                REG_WRITE(ah, AR_MCI_BT_PRI2, 0xFFFFFFFF);
@@ -339,77 +286,70 @@ static void ar9003_mci_prep_interface(struct ath_hw *ah)
                REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
                          AR_MCI_INTERRUPT_BT_PRI);
 
-               if (AR_SREV_9462_10(ah) || mci->is_2g) {
-                       /* Send LNA_TRANS */
-                       ath_dbg(common, MCI, "MCI send LNA_TRANS to BT\n");
+               if (mci->is_2g) {
                        ar9003_mci_send_lna_transfer(ah, true);
                        udelay(5);
                }
 
-               if (AR_SREV_9462_10(ah) || (mci->is_2g &&
-                                           !mci->update_2g5g)) {
+               if ((mci->is_2g && !mci->update_2g5g)) {
                        if (ar9003_mci_wait_for_interrupt(ah,
-                               AR_MCI_INTERRUPT_RX_MSG_RAW,
-                               AR_MCI_INTERRUPT_RX_MSG_LNA_INFO,
-                               mci_timeout))
+                                         AR_MCI_INTERRUPT_RX_MSG_RAW,
+                                         AR_MCI_INTERRUPT_RX_MSG_LNA_INFO,
+                                         mci_timeout))
                                ath_dbg(common, MCI,
                                        "MCI WLAN has control over the LNA & BT obeys it\n");
                        else
                                ath_dbg(common, MCI,
                                        "MCI BT didn't respond to LNA_TRANS\n");
                }
-
-               if (AR_SREV_9462_10(ah)) {
-                       /* Send another remote_reset to deassert BT clk_req. */
-                       ath_dbg(common, MCI,
-                               "MCI another remote_reset to deassert clk_req\n");
-                       ar9003_mci_remote_reset(ah, true);
-                       udelay(252);
-               }
        }
 
        /* Clear the extra redundant SYS_WAKING from BT */
        if ((mci->bt_state == MCI_BT_AWAKE) &&
                (REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
                                AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING)) &&
-               (REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
-                               AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING) == 0)) {
-
-                       REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
-                                 AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING);
-                       REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
-                                 AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE);
+           (REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
+                           AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING) == 0)) {
+               REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
+                         AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING);
+               REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
+                         AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE);
        }
 
        REG_WRITE(ah, AR_MCI_INTERRUPT_EN, saved_mci_int_en);
 }
 
-void ar9003_mci_disable_interrupt(struct ath_hw *ah)
+void ar9003_mci_set_full_sleep(struct ath_hw *ah)
 {
-       if (!ATH9K_HW_CAP_MCI)
-               return;
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+
+       if (ar9003_mci_state(ah, MCI_STATE_ENABLE, NULL) &&
+           (mci->bt_state != MCI_BT_SLEEP) &&
+           !mci->halted_bt_gpm) {
+               ar9003_mci_send_coex_halt_bt_gpm(ah, true, true);
+       }
+
+       mci->ready = false;
+       REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
+}
 
+static void ar9003_mci_disable_interrupt(struct ath_hw *ah)
+{
        REG_WRITE(ah, AR_MCI_INTERRUPT_EN, 0);
        REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, 0);
 }
 
-void ar9003_mci_enable_interrupt(struct ath_hw *ah)
+static void ar9003_mci_enable_interrupt(struct ath_hw *ah)
 {
-       if (!ATH9K_HW_CAP_MCI)
-               return;
-
        REG_WRITE(ah, AR_MCI_INTERRUPT_EN, AR_MCI_INTERRUPT_DEFAULT);
        REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN,
                  AR_MCI_INTERRUPT_RX_MSG_DEFAULT);
 }
 
-bool ar9003_mci_check_int(struct ath_hw *ah, u32 ints)
+static bool ar9003_mci_check_int(struct ath_hw *ah, u32 ints)
 {
        u32 intr;
 
-       if (!ATH9K_HW_CAP_MCI)
-               return false;
-
        intr = REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW);
        return ((intr & ints) == ints);
 }
@@ -419,9 +359,6 @@ void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr,
 {
        struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
 
-       if (!ATH9K_HW_CAP_MCI)
-               return;
-
        *raw_intr = mci->raw_intr;
        *rx_msg_intr = mci->rx_msg_intr;
 
@@ -431,12 +368,34 @@ void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr,
 }
 EXPORT_SYMBOL(ar9003_mci_get_interrupt);
 
-void ar9003_mci_2g5g_changed(struct ath_hw *ah, bool is_2g)
+void ar9003_mci_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
 {
+       struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+       u32 raw_intr, rx_msg_intr;
 
-       if (!ATH9K_HW_CAP_MCI)
-               return;
+       rx_msg_intr = REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW);
+       raw_intr = REG_READ(ah, AR_MCI_INTERRUPT_RAW);
+
+       if ((raw_intr == 0xdeadbeef) || (rx_msg_intr == 0xdeadbeef)) {
+               ath_dbg(common, MCI,
+                       "MCI gets 0xdeadbeef during int processing\n");
+       } else {
+               mci->rx_msg_intr |= rx_msg_intr;
+               mci->raw_intr |= raw_intr;
+               *masked |= ATH9K_INT_MCI;
+
+               if (rx_msg_intr & AR_MCI_INTERRUPT_RX_MSG_CONT_INFO)
+                       mci->cont_status = REG_READ(ah, AR_MCI_CONT_STATUS);
+
+               REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, rx_msg_intr);
+               REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, raw_intr);
+       }
+}
+
+static void ar9003_mci_2g5g_changed(struct ath_hw *ah, bool is_2g)
+{
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
 
        if (!mci->update_2g5g &&
            (mci->is_2g != is_2g))
@@ -447,7 +406,6 @@ void ar9003_mci_2g5g_changed(struct ath_hw *ah, bool is_2g)
 
 static bool ar9003_mci_is_gpm_valid(struct ath_hw *ah, u32 msg_index)
 {
-       struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
        u32 *payload;
        u32 recv_type, offset;
@@ -460,10 +418,8 @@ static bool ar9003_mci_is_gpm_valid(struct ath_hw *ah, u32 msg_index)
        payload = (u32 *)(mci->gpm_buf + offset);
        recv_type = MCI_GPM_TYPE(payload);
 
-       if (recv_type == MCI_GPM_RSVD_PATTERN) {
-               ath_dbg(common, MCI, "MCI Skip RSVD GPM\n");
+       if (recv_type == MCI_GPM_RSVD_PATTERN)
                return false;
-       }
 
        return true;
 }
@@ -471,42 +427,31 @@ static bool ar9003_mci_is_gpm_valid(struct ath_hw *ah, u32 msg_index)
 static void ar9003_mci_observation_set_up(struct ath_hw *ah)
 {
        struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
-       if (mci->config & ATH_MCI_CONFIG_MCI_OBS_MCI) {
 
-               ath9k_hw_cfg_output(ah, 3,
-                                       AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_DATA);
+       if (mci->config & ATH_MCI_CONFIG_MCI_OBS_MCI) {
+               ath9k_hw_cfg_output(ah, 3, AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_DATA);
                ath9k_hw_cfg_output(ah, 2, AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_CLK);
                ath9k_hw_cfg_output(ah, 1, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA);
                ath9k_hw_cfg_output(ah, 0, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK);
-
        } else if (mci->config & ATH_MCI_CONFIG_MCI_OBS_TXRX) {
-
                ath9k_hw_cfg_output(ah, 3, AR_GPIO_OUTPUT_MUX_AS_WL_IN_TX);
                ath9k_hw_cfg_output(ah, 2, AR_GPIO_OUTPUT_MUX_AS_WL_IN_RX);
                ath9k_hw_cfg_output(ah, 1, AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX);
                ath9k_hw_cfg_output(ah, 0, AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX);
                ath9k_hw_cfg_output(ah, 5, AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
-
        } else if (mci->config & ATH_MCI_CONFIG_MCI_OBS_BT) {
-
                ath9k_hw_cfg_output(ah, 3, AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX);
                ath9k_hw_cfg_output(ah, 2, AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX);
                ath9k_hw_cfg_output(ah, 1, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA);
                ath9k_hw_cfg_output(ah, 0, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK);
-
        } else
                return;
 
        REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);
 
-       if (AR_SREV_9462_20_OR_LATER(ah)) {
-               REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL,
-                             AR_GLB_DS_JTAG_DISABLE, 1);
-               REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL,
-                             AR_GLB_WLAN_UART_INTF_EN, 0);
-               REG_SET_BIT(ah, AR_GLB_GPIO_CONTROL,
-                           ATH_MCI_CONFIG_MCI_OBS_GPIO);
-       }
+       REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL, AR_GLB_DS_JTAG_DISABLE, 1);
+       REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL, AR_GLB_WLAN_UART_INTF_EN, 0);
+       REG_SET_BIT(ah, AR_GLB_GPIO_CONTROL, ATH_MCI_CONFIG_MCI_OBS_GPIO);
 
        REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_GPIO_OBS_SEL, 0);
        REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_MAC_BB_OBS_SEL, 1);
@@ -520,13 +465,12 @@ static void ar9003_mci_observation_set_up(struct ath_hw *ah)
 }
 
 static bool ar9003_mci_send_coex_bt_flags(struct ath_hw *ah, bool wait_done,
-                                               u8 opcode, u32 bt_flags)
+                                         u8 opcode, u32 bt_flags)
 {
-       struct ath_common *common = ath9k_hw_common(ah);
        u32 pld[4] = {0, 0, 0, 0};
 
-       MCI_GPM_SET_TYPE_OPCODE(pld,
-                       MCI_GPM_COEX_AGENT, MCI_GPM_COEX_BT_UPDATE_FLAGS);
+       MCI_GPM_SET_TYPE_OPCODE(pld, MCI_GPM_COEX_AGENT,
+                               MCI_GPM_COEX_BT_UPDATE_FLAGS);
 
        *(((u8 *)pld) + MCI_GPM_COEX_B_BT_FLAGS_OP)  = opcode;
        *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 0) = bt_flags & 0xFF;
@@ -534,222 +478,473 @@ static bool ar9003_mci_send_coex_bt_flags(struct ath_hw *ah, bool wait_done,
        *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 2) = (bt_flags >> 16) & 0xFF;
        *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 3) = (bt_flags >> 24) & 0xFF;
 
-       ath_dbg(common, MCI,
-               "MCI BT_MCI_FLAGS: Send Coex BT Update Flags %s 0x%08x\n",
-               opcode == MCI_GPM_COEX_BT_FLAGS_READ ? "READ" :
-               opcode == MCI_GPM_COEX_BT_FLAGS_SET ? "SET" : "CLEAR",
-               bt_flags);
-
        return ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16,
-                                                       wait_done, true);
+                                      wait_done, true);
 }
 
-void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
-                     bool is_full_sleep)
+static void ar9003_mci_sync_bt_state(struct ath_hw *ah)
 {
-       struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
-       u32 regval, thresh;
-
-       if (!ATH9K_HW_CAP_MCI)
-               return;
-
-       ath_dbg(common, MCI, "MCI full_sleep = %d, is_2g = %d\n",
-               is_full_sleep, is_2g);
-
-       /*
-        * GPM buffer and scheduling message buffer are not allocated
-        */
-
-       if (!mci->gpm_addr && !mci->sched_addr) {
-               ath_dbg(common, MCI,
-                       "MCI GPM and schedule buffers are not allocated\n");
-               return;
-       }
-
-       if (REG_READ(ah, AR_BTCOEX_CTRL) == 0xdeadbeef) {
-               ath_dbg(common, MCI, "MCI it's deadbeef, quit mci_reset\n");
-               return;
-       }
-
-       /* Program MCI DMA related registers */
-       REG_WRITE(ah, AR_MCI_GPM_0, mci->gpm_addr);
-       REG_WRITE(ah, AR_MCI_GPM_1, mci->gpm_len);
-       REG_WRITE(ah, AR_MCI_SCHD_TABLE_0, mci->sched_addr);
-
-       /*
-       * To avoid MCI state machine be affected by incoming remote MCI msgs,
-       * MCI mode will be enabled later, right before reset the MCI TX and RX.
-       */
-
-       regval = SM(1, AR_BTCOEX_CTRL_AR9462_MODE) |
-                SM(1, AR_BTCOEX_CTRL_WBTIMER_EN) |
-                SM(1, AR_BTCOEX_CTRL_PA_SHARED) |
-                SM(1, AR_BTCOEX_CTRL_LNA_SHARED) |
-                SM(2, AR_BTCOEX_CTRL_NUM_ANTENNAS) |
-                SM(3, AR_BTCOEX_CTRL_RX_CHAIN_MASK) |
-                SM(0, AR_BTCOEX_CTRL_1_CHAIN_ACK) |
-                SM(0, AR_BTCOEX_CTRL_1_CHAIN_BCN) |
-                SM(0, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
-
-       if (is_2g && (AR_SREV_9462_20(ah)) &&
-               !(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA)) {
-
-               regval |= SM(1, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
-               ath_dbg(common, MCI, "MCI sched one step look ahead\n");
-
-               if (!(mci->config &
-                     ATH_MCI_CONFIG_DISABLE_AGGR_THRESH)) {
-
-                       thresh = MS(mci->config,
-                                   ATH_MCI_CONFIG_AGGR_THRESH);
-                       thresh &= 7;
-                       regval |= SM(1,
-                                    AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN);
-                       regval |= SM(thresh, AR_BTCOEX_CTRL_AGGR_THRESH);
-
-                       REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2,
-                                     AR_MCI_SCHD_TABLE_2_HW_BASED, 1);
-                       REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2,
-                                     AR_MCI_SCHD_TABLE_2_MEM_BASED, 1);
-
-               } else
-                       ath_dbg(common, MCI, "MCI sched aggr thresh: off\n");
-       } else
-               ath_dbg(common, MCI, "MCI SCHED one step look ahead off\n");
-
-       if (AR_SREV_9462_10(ah))
-               regval |= SM(1, AR_BTCOEX_CTRL_SPDT_ENABLE_10);
-
-       REG_WRITE(ah, AR_BTCOEX_CTRL, regval);
-
-       if (AR_SREV_9462_20(ah)) {
-               REG_SET_BIT(ah, AR_PHY_GLB_CONTROL,
-                           AR_BTCOEX_CTRL_SPDT_ENABLE);
-               REG_RMW_FIELD(ah, AR_BTCOEX_CTRL3,
-                             AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT, 20);
-       }
-
-       REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_RX_DEWEIGHT, 1);
-       REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0);
+       u32 cur_bt_state;
 
-       thresh = MS(mci->config, ATH_MCI_CONFIG_CLK_DIV);
-       REG_RMW_FIELD(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_CLK_DIV, thresh);
-       REG_SET_BIT(ah, AR_BTCOEX_CTRL, AR_BTCOEX_CTRL_MCI_MODE_EN);
+       cur_bt_state = ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL);
 
-       /* Resetting the Rx and Tx paths of MCI */
-       regval = REG_READ(ah, AR_MCI_COMMAND2);
-       regval |= SM(1, AR_MCI_COMMAND2_RESET_TX);
-       REG_WRITE(ah, AR_MCI_COMMAND2, regval);
+       if (mci->bt_state != cur_bt_state)
+               mci->bt_state = cur_bt_state;
 
-       udelay(1);
+       if (mci->bt_state != MCI_BT_SLEEP) {
 
-       regval &= ~SM(1, AR_MCI_COMMAND2_RESET_TX);
-       REG_WRITE(ah, AR_MCI_COMMAND2, regval);
+               ar9003_mci_send_coex_version_query(ah, true);
+               ar9003_mci_send_coex_wlan_channels(ah, true);
 
-       if (is_full_sleep) {
-               ar9003_mci_mute_bt(ah);
-               udelay(100);
+               if (mci->unhalt_bt_gpm == true)
+                       ar9003_mci_send_coex_halt_bt_gpm(ah, false, true);
        }
-
-       regval |= SM(1, AR_MCI_COMMAND2_RESET_RX);
-       REG_WRITE(ah, AR_MCI_COMMAND2, regval);
-       udelay(1);
-       regval &= ~SM(1, AR_MCI_COMMAND2_RESET_RX);
-       REG_WRITE(ah, AR_MCI_COMMAND2, regval);
-
-       ar9003_mci_state(ah, MCI_STATE_INIT_GPM_OFFSET, NULL);
-       REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE,
-                 (SM(0xe801, AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR) |
-                  SM(0x0000, AR_MCI_MSG_ATTRIBUTES_TABLE_CHECKSUM)));
-
-       REG_CLR_BIT(ah, AR_MCI_TX_CTRL,
-                       AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
-
-       if (AR_SREV_9462_20_OR_LATER(ah))
-               ar9003_mci_observation_set_up(ah);
-
-       mci->ready = true;
-       ar9003_mci_prep_interface(ah);
-
-       if (en_int)
-               ar9003_mci_enable_interrupt(ah);
 }
 
-void ar9003_mci_mute_bt(struct ath_hw *ah)
+void ar9003_mci_check_bt(struct ath_hw *ah)
 {
-       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
 
-       if (!ATH9K_HW_CAP_MCI)
+       if (!mci_hw->ready)
                return;
 
-       /* disable all MCI messages */
-       REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE, 0xffff0000);
-       REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS0, 0xffffffff);
-       REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS1, 0xffffffff);
-       REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS2, 0xffffffff);
-       REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS3, 0xffffffff);
-       REG_SET_BIT(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
-
-       /* wait pending HW messages to flush out */
-       udelay(10);
-
        /*
-        * Send LNA_TAKE and SYS_SLEEPING when
-        * 1. reset not after resuming from full sleep
-        * 2. before reset MCI RX, to quiet BT and avoid MCI RX misalignment
+        * check BT state again to make
+        * sure it's not changed.
         */
+       ar9003_mci_sync_bt_state(ah);
+       ar9003_mci_2g5g_switch(ah, true);
 
-       ath_dbg(common, MCI, "MCI Send LNA take\n");
-       ar9003_mci_send_lna_take(ah, true);
-
-       udelay(5);
-
-       ath_dbg(common, MCI, "MCI Send sys sleeping\n");
-       ar9003_mci_send_sys_sleeping(ah, true);
+       if ((mci_hw->bt_state == MCI_BT_AWAKE) &&
+           (mci_hw->query_bt == true)) {
+               mci_hw->need_flush_btinfo = true;
+       }
 }
 
-void ar9003_mci_sync_bt_state(struct ath_hw *ah)
+static void ar9003_mci_process_gpm_extra(struct ath_hw *ah, u8 gpm_type,
+                                        u8 gpm_opcode, u32 *p_gpm)
 {
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
-       u32 cur_bt_state;
+       u8 *p_data = (u8 *) p_gpm;
 
-       if (!ATH9K_HW_CAP_MCI)
+       if (gpm_type != MCI_GPM_COEX_AGENT)
                return;
 
-       cur_bt_state = ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL);
-
-       if (mci->bt_state != cur_bt_state) {
+       switch (gpm_opcode) {
+       case MCI_GPM_COEX_VERSION_QUERY:
+               ath_dbg(common, MCI, "MCI Recv GPM COEX Version Query\n");
+               ar9003_mci_send_coex_version_response(ah, true);
+               break;
+       case MCI_GPM_COEX_VERSION_RESPONSE:
+               ath_dbg(common, MCI, "MCI Recv GPM COEX Version Response\n");
+               mci->bt_ver_major =
+                       *(p_data + MCI_GPM_COEX_B_MAJOR_VERSION);
+               mci->bt_ver_minor =
+                       *(p_data + MCI_GPM_COEX_B_MINOR_VERSION);
+               mci->bt_version_known = true;
+               ath_dbg(common, MCI, "MCI BT Coex version: %d.%d\n",
+                       mci->bt_ver_major, mci->bt_ver_minor);
+               break;
+       case MCI_GPM_COEX_STATUS_QUERY:
                ath_dbg(common, MCI,
-                       "MCI BT state mismatches. old: %d, new: %d\n",
-                       mci->bt_state, cur_bt_state);
-               mci->bt_state = cur_bt_state;
-       }
-
-       if (mci->bt_state != MCI_BT_SLEEP) {
-
-               ar9003_mci_send_coex_version_query(ah, true);
+                       "MCI Recv GPM COEX Status Query = 0x%02X\n",
+                       *(p_data + MCI_GPM_COEX_B_WLAN_BITMAP));
+               mci->wlan_channels_update = true;
                ar9003_mci_send_coex_wlan_channels(ah, true);
-
-               if (mci->unhalt_bt_gpm == true) {
-                       ath_dbg(common, MCI, "MCI unhalt BT GPM\n");
-                       ar9003_mci_send_coex_halt_bt_gpm(ah, false, true);
-               }
+               break;
+       case MCI_GPM_COEX_BT_PROFILE_INFO:
+               mci->query_bt = true;
+               ath_dbg(common, MCI, "MCI Recv GPM COEX BT_Profile_Info\n");
+               break;
+       case MCI_GPM_COEX_BT_STATUS_UPDATE:
+               mci->query_bt = true;
+               ath_dbg(common, MCI,
+                       "MCI Recv GPM COEX BT_Status_Update SEQ=%d (drop&query)\n",
+                       *(p_gpm + 3));
+               break;
+       default:
+               break;
        }
 }
 
-static void ar9003_mci_send_2g5g_status(struct ath_hw *ah, bool wait_done)
+static u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type,
+                                  u8 gpm_opcode, int time_out)
 {
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
-       u32 new_flags, to_set, to_clear;
+       u32 *p_gpm = NULL, mismatch = 0, more_data;
+       u32 offset;
+       u8 recv_type = 0, recv_opcode = 0;
+       bool b_is_bt_cal_done = (gpm_type == MCI_GPM_BT_CAL_DONE);
 
-       if (AR_SREV_9462_20(ah) &&
-           mci->update_2g5g &&
-           (mci->bt_state != MCI_BT_SLEEP)) {
+       more_data = time_out ? MCI_GPM_NOMORE : MCI_GPM_MORE;
 
-               if (mci->is_2g) {
+       while (time_out > 0) {
+               if (p_gpm) {
+                       MCI_GPM_RECYCLE(p_gpm);
+                       p_gpm = NULL;
+               }
+
+               if (more_data != MCI_GPM_MORE)
+                       time_out = ar9003_mci_wait_for_interrupt(ah,
+                                       AR_MCI_INTERRUPT_RX_MSG_RAW,
+                                       AR_MCI_INTERRUPT_RX_MSG_GPM,
+                                       time_out);
+
+               if (!time_out)
+                       break;
+
+               offset = ar9003_mci_state(ah, MCI_STATE_NEXT_GPM_OFFSET,
+                                         &more_data);
+
+               if (offset == MCI_GPM_INVALID)
+                       continue;
+
+               p_gpm = (u32 *) (mci->gpm_buf + offset);
+               recv_type = MCI_GPM_TYPE(p_gpm);
+               recv_opcode = MCI_GPM_OPCODE(p_gpm);
+
+               if (MCI_GPM_IS_CAL_TYPE(recv_type)) {
+                       if (recv_type == gpm_type) {
+                               if ((gpm_type == MCI_GPM_BT_CAL_DONE) &&
+                                   !b_is_bt_cal_done) {
+                                       gpm_type = MCI_GPM_BT_CAL_GRANT;
+                                       continue;
+                               }
+                               break;
+                       }
+               } else if ((recv_type == gpm_type) && (recv_opcode == gpm_opcode)) {
+                       break;
+               }
+
+               /*
+                * check if it's cal_grant
+                *
+                * When we're waiting for cal_grant in reset routine,
+                * it's possible that BT sends out cal_request at the
+                * same time. Since BT's calibration doesn't happen
+                * that often, we'll let BT completes calibration then
+                * we continue to wait for cal_grant from BT.
+                * Orginal: Wait BT_CAL_GRANT.
+                * New: Receive BT_CAL_REQ -> send WLAN_CAL_GRANT->wait
+                * BT_CAL_DONE -> Wait BT_CAL_GRANT.
+                */
+
+               if ((gpm_type == MCI_GPM_BT_CAL_GRANT) &&
+                   (recv_type == MCI_GPM_BT_CAL_REQ)) {
+
+                       u32 payload[4] = {0, 0, 0, 0};
+
+                       gpm_type = MCI_GPM_BT_CAL_DONE;
+                       MCI_GPM_SET_CAL_TYPE(payload,
+                                            MCI_GPM_WLAN_CAL_GRANT);
+                       ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
+                                               false, false);
+                       continue;
+               } else {
+                       ath_dbg(common, MCI, "MCI GPM subtype not match 0x%x\n",
+                               *(p_gpm + 1));
+                       mismatch++;
+                       ar9003_mci_process_gpm_extra(ah, recv_type,
+                                                    recv_opcode, p_gpm);
+               }
+       }
+
+       if (p_gpm) {
+               MCI_GPM_RECYCLE(p_gpm);
+               p_gpm = NULL;
+       }
+
+       if (time_out <= 0)
+               time_out = 0;
+
+       while (more_data == MCI_GPM_MORE) {
+               offset = ar9003_mci_state(ah, MCI_STATE_NEXT_GPM_OFFSET,
+                                         &more_data);
+               if (offset == MCI_GPM_INVALID)
+                       break;
+
+               p_gpm = (u32 *) (mci->gpm_buf + offset);
+               recv_type = MCI_GPM_TYPE(p_gpm);
+               recv_opcode = MCI_GPM_OPCODE(p_gpm);
+
+               if (!MCI_GPM_IS_CAL_TYPE(recv_type))
+                       ar9003_mci_process_gpm_extra(ah, recv_type,
+                                                    recv_opcode, p_gpm);
+
+               MCI_GPM_RECYCLE(p_gpm);
+       }
+
+       return time_out;
+}
+
+bool ar9003_mci_start_reset(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
+       u32 payload[4] = {0, 0, 0, 0};
+
+       ar9003_mci_2g5g_changed(ah, IS_CHAN_2GHZ(chan));
+
+       if (mci_hw->bt_state != MCI_BT_CAL_START)
+               return false;
+
+       mci_hw->bt_state = MCI_BT_CAL;
+
+       /*
+        * MCI FIX: disable mci interrupt here. This is to avoid
+        * SW_MSG_DONE or RX_MSG bits to trigger MCI_INT and
+        * lead to mci_intr reentry.
+        */
+       ar9003_mci_disable_interrupt(ah);
+
+       MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_GRANT);
+       ar9003_mci_send_message(ah, MCI_GPM, 0, payload,
+                               16, true, false);
+
+       /* Wait BT calibration to be completed for 25ms */
+
+       if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_DONE,
+                                   0, 25000))
+               ath_dbg(common, MCI, "MCI BT_CAL_DONE received\n");
+       else
+               ath_dbg(common, MCI,
+                       "MCI BT_CAL_DONE not received\n");
+
+       mci_hw->bt_state = MCI_BT_AWAKE;
+       /* MCI FIX: enable mci interrupt here */
+       ar9003_mci_enable_interrupt(ah);
+
+       return true;
+}
+
+int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan,
+                        struct ath9k_hw_cal_data *caldata)
+{
+       struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
+
+       if (!mci_hw->ready)
+               return 0;
+
+       if (!IS_CHAN_2GHZ(chan) || (mci_hw->bt_state != MCI_BT_SLEEP))
+               goto exit;
+
+       if (ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET) ||
+           ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)) {
+
+               /*
+                * BT is sleeping. Check if BT wakes up during
+                * WLAN calibration. If BT wakes up during
+                * WLAN calibration, need to go through all
+                * message exchanges again and recal.
+                */
+               REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
+                         AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET |
+                         AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE);
+
+               ar9003_mci_remote_reset(ah, true);
+               ar9003_mci_send_sys_waking(ah, true);
+               udelay(1);
+
+               if (IS_CHAN_2GHZ(chan))
+                       ar9003_mci_send_lna_transfer(ah, true);
+
+               mci_hw->bt_state = MCI_BT_AWAKE;
+
+               if (caldata) {
+                       caldata->done_txiqcal_once = false;
+                       caldata->done_txclcal_once = false;
+                       caldata->rtt_hist.num_readings = 0;
+               }
+
+               if (!ath9k_hw_init_cal(ah, chan))
+                       return -EIO;
+
+       }
+exit:
+       ar9003_mci_enable_interrupt(ah);
+       return 0;
+}
+
+static void ar9003_mci_mute_bt(struct ath_hw *ah)
+{
+       /* disable all MCI messages */
+       REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE, 0xffff0000);
+       REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS0, 0xffffffff);
+       REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS1, 0xffffffff);
+       REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS2, 0xffffffff);
+       REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS3, 0xffffffff);
+       REG_SET_BIT(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
+
+       /* wait pending HW messages to flush out */
+       udelay(10);
+
+       /*
+        * Send LNA_TAKE and SYS_SLEEPING when
+        * 1. reset not after resuming from full sleep
+        * 2. before reset MCI RX, to quiet BT and avoid MCI RX misalignment
+        */
+       ar9003_mci_send_lna_take(ah, true);
+
+       udelay(5);
+
+       ar9003_mci_send_sys_sleeping(ah, true);
+}
+
+static void ar9003_mci_osla_setup(struct ath_hw *ah, bool enable)
+{
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+       u32 thresh;
+
+       if (enable) {
+               REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2,
+                             AR_MCI_SCHD_TABLE_2_HW_BASED, 1);
+               REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2,
+                             AR_MCI_SCHD_TABLE_2_MEM_BASED, 1);
+
+               if (!(mci->config & ATH_MCI_CONFIG_DISABLE_AGGR_THRESH)) {
+                       thresh = MS(mci->config, ATH_MCI_CONFIG_AGGR_THRESH);
+                       REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
+                                     AR_BTCOEX_CTRL_AGGR_THRESH, thresh);
+                       REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
+                                     AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN, 1);
+               } else {
+                       REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
+                                     AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN, 0);
+               }
+
+               REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
+                             AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN, 1);
+       } else {
+               REG_CLR_BIT(ah, AR_BTCOEX_CTRL,
+                           AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
+       }
+}
+
+void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
+                     bool is_full_sleep)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+       u32 regval;
+
+       ath_dbg(common, MCI, "MCI Reset (full_sleep = %d, is_2g = %d)\n",
+               is_full_sleep, is_2g);
+
+       if (!mci->gpm_addr && !mci->sched_addr) {
+               ath_dbg(common, MCI,
+                       "MCI GPM and schedule buffers are not allocated\n");
+               return;
+       }
+
+       if (REG_READ(ah, AR_BTCOEX_CTRL) == 0xdeadbeef) {
+               ath_dbg(common, MCI, "BTCOEX control register is dead\n");
+               return;
+       }
+
+       /* Program MCI DMA related registers */
+       REG_WRITE(ah, AR_MCI_GPM_0, mci->gpm_addr);
+       REG_WRITE(ah, AR_MCI_GPM_1, mci->gpm_len);
+       REG_WRITE(ah, AR_MCI_SCHD_TABLE_0, mci->sched_addr);
+
+       /*
+       * To avoid MCI state machine be affected by incoming remote MCI msgs,
+       * MCI mode will be enabled later, right before reset the MCI TX and RX.
+       */
+
+       regval = SM(1, AR_BTCOEX_CTRL_AR9462_MODE) |
+                SM(1, AR_BTCOEX_CTRL_WBTIMER_EN) |
+                SM(1, AR_BTCOEX_CTRL_PA_SHARED) |
+                SM(1, AR_BTCOEX_CTRL_LNA_SHARED) |
+                SM(2, AR_BTCOEX_CTRL_NUM_ANTENNAS) |
+                SM(3, AR_BTCOEX_CTRL_RX_CHAIN_MASK) |
+                SM(0, AR_BTCOEX_CTRL_1_CHAIN_ACK) |
+                SM(0, AR_BTCOEX_CTRL_1_CHAIN_BCN) |
+                SM(0, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
+
+       REG_WRITE(ah, AR_BTCOEX_CTRL, regval);
+
+       if (is_2g && !(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA))
+               ar9003_mci_osla_setup(ah, true);
+       else
+               ar9003_mci_osla_setup(ah, false);
+
+       REG_SET_BIT(ah, AR_PHY_GLB_CONTROL,
+                   AR_BTCOEX_CTRL_SPDT_ENABLE);
+       REG_RMW_FIELD(ah, AR_BTCOEX_CTRL3,
+                     AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT, 20);
+
+       REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_RX_DEWEIGHT, 1);
+       REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0);
+
+       regval = MS(mci->config, ATH_MCI_CONFIG_CLK_DIV);
+       REG_RMW_FIELD(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_CLK_DIV, regval);
+       REG_SET_BIT(ah, AR_BTCOEX_CTRL, AR_BTCOEX_CTRL_MCI_MODE_EN);
+
+       /* Resetting the Rx and Tx paths of MCI */
+       regval = REG_READ(ah, AR_MCI_COMMAND2);
+       regval |= SM(1, AR_MCI_COMMAND2_RESET_TX);
+       REG_WRITE(ah, AR_MCI_COMMAND2, regval);
+
+       udelay(1);
+
+       regval &= ~SM(1, AR_MCI_COMMAND2_RESET_TX);
+       REG_WRITE(ah, AR_MCI_COMMAND2, regval);
+
+       if (is_full_sleep) {
+               ar9003_mci_mute_bt(ah);
+               udelay(100);
+       }
+
+       regval |= SM(1, AR_MCI_COMMAND2_RESET_RX);
+       REG_WRITE(ah, AR_MCI_COMMAND2, regval);
+       udelay(1);
+       regval &= ~SM(1, AR_MCI_COMMAND2_RESET_RX);
+       REG_WRITE(ah, AR_MCI_COMMAND2, regval);
+
+       ar9003_mci_state(ah, MCI_STATE_INIT_GPM_OFFSET, NULL);
+
+       REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE,
+                 (SM(0xe801, AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR) |
+                  SM(0x0000, AR_MCI_MSG_ATTRIBUTES_TABLE_CHECKSUM)));
+
+       REG_CLR_BIT(ah, AR_MCI_TX_CTRL,
+                   AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
+
+       ar9003_mci_observation_set_up(ah);
+
+       mci->ready = true;
+       ar9003_mci_prep_interface(ah);
+
+       if (en_int)
+               ar9003_mci_enable_interrupt(ah);
+}
+
+void ar9003_mci_stop_bt(struct ath_hw *ah, bool save_fullsleep)
+{
+       struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
+
+       ar9003_mci_disable_interrupt(ah);
+
+       if (mci_hw->ready && !save_fullsleep) {
+               ar9003_mci_mute_bt(ah);
+               udelay(20);
+               REG_WRITE(ah, AR_BTCOEX_CTRL, 0);
+       }
+
+       mci_hw->bt_state = MCI_BT_SLEEP;
+       mci_hw->ready = false;
+}
+
+static void ar9003_mci_send_2g5g_status(struct ath_hw *ah, bool wait_done)
+{
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+       u32 new_flags, to_set, to_clear;
+
+       if (mci->update_2g5g && (mci->bt_state != MCI_BT_SLEEP)) {
+               if (mci->is_2g) {
                        new_flags = MCI_2G_FLAGS;
                        to_clear = MCI_2G_FLAGS_CLEAR_MASK;
                        to_set = MCI_2G_FLAGS_SET_MASK;
@@ -759,44 +954,23 @@ static void ar9003_mci_send_2g5g_status(struct ath_hw *ah, bool wait_done)
                        to_set = MCI_5G_FLAGS_SET_MASK;
                }
 
-               ath_dbg(common, MCI,
-                       "MCI BT_MCI_FLAGS: %s 0x%08x clr=0x%08x, set=0x%08x\n",
-               mci->is_2g ? "2G" : "5G", new_flags, to_clear, to_set);
-
                if (to_clear)
                        ar9003_mci_send_coex_bt_flags(ah, wait_done,
-                                       MCI_GPM_COEX_BT_FLAGS_CLEAR, to_clear);
-
+                                             MCI_GPM_COEX_BT_FLAGS_CLEAR,
+                                             to_clear);
                if (to_set)
                        ar9003_mci_send_coex_bt_flags(ah, wait_done,
-                                       MCI_GPM_COEX_BT_FLAGS_SET, to_set);
+                                             MCI_GPM_COEX_BT_FLAGS_SET,
+                                             to_set);
        }
-
-       if (AR_SREV_9462_10(ah) && (mci->bt_state != MCI_BT_SLEEP))
-               mci->update_2g5g = false;
 }
 
 static void ar9003_mci_queue_unsent_gpm(struct ath_hw *ah, u8 header,
                                        u32 *payload, bool queue)
 {
-       struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
        u8 type, opcode;
 
-       if (queue) {
-
-               if (payload)
-                       ath_dbg(common, MCI,
-                               "MCI ERROR: Send fail: %02x: %02x %02x %02x\n",
-                               header,
-                               *(((u8 *)payload) + 4),
-                               *(((u8 *)payload) + 5),
-                               *(((u8 *)payload) + 6));
-               else
-                       ath_dbg(common, MCI, "MCI ERROR: Send fail: %02x\n",
-                               header);
-       }
-
        /* check if the message is to be queued */
        if (header != MCI_GPM)
                return;
@@ -809,64 +983,29 @@ static void ar9003_mci_queue_unsent_gpm(struct ath_hw *ah, u8 header,
 
        switch (opcode) {
        case MCI_GPM_COEX_BT_UPDATE_FLAGS:
-
-               if (AR_SREV_9462_10(ah))
-                       break;
-
                if (*(((u8 *)payload) + MCI_GPM_COEX_B_BT_FLAGS_OP) ==
-                               MCI_GPM_COEX_BT_FLAGS_READ)
+                   MCI_GPM_COEX_BT_FLAGS_READ)
                        break;
 
                mci->update_2g5g = queue;
 
-               if (queue)
-                       ath_dbg(common, MCI,
-                               "MCI BT_MCI_FLAGS: 2G5G status <queued> %s\n",
-                               mci->is_2g ? "2G" : "5G");
-               else
-                       ath_dbg(common, MCI,
-                               "MCI BT_MCI_FLAGS: 2G5G status <sent> %s\n",
-                               mci->is_2g ? "2G" : "5G");
-
                break;
-
        case MCI_GPM_COEX_WLAN_CHANNELS:
-
                mci->wlan_channels_update = queue;
-               if (queue)
-                       ath_dbg(common, MCI, "MCI WLAN channel map <queued>\n");
-               else
-                       ath_dbg(common, MCI, "MCI WLAN channel map <sent>\n");
                break;
-
        case MCI_GPM_COEX_HALT_BT_GPM:
-
                if (*(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) ==
-                               MCI_GPM_COEX_BT_GPM_UNHALT) {
-
+                   MCI_GPM_COEX_BT_GPM_UNHALT) {
                        mci->unhalt_bt_gpm = queue;
 
-                       if (queue)
-                               ath_dbg(common, MCI,
-                                       "MCI UNHALT BT GPM <queued>\n");
-                       else {
+                       if (!queue)
                                mci->halted_bt_gpm = false;
-                               ath_dbg(common, MCI,
-                                       "MCI UNHALT BT GPM <sent>\n");
-                       }
                }
 
                if (*(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) ==
                                MCI_GPM_COEX_BT_GPM_HALT) {
 
                        mci->halted_bt_gpm = !queue;
-
-                       if (queue)
-                               ath_dbg(common, MCI,
-                                       "MCI HALT BT GPM <not sent>\n");
-                       else
-                               ath_dbg(common, MCI,
-                                       "MCI UNHALT BT GPM <sent>\n");
                }
 
                break;
@@ -877,46 +1016,33 @@ static void ar9003_mci_queue_unsent_gpm(struct ath_hw *ah, u8 header,
 
 void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done)
 {
-       struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
 
-       if (!ATH9K_HW_CAP_MCI)
-               return;
-
        if (mci->update_2g5g) {
                if (mci->is_2g) {
-
                        ar9003_mci_send_2g5g_status(ah, true);
-                       ath_dbg(common, MCI, "MCI Send LNA trans\n");
                        ar9003_mci_send_lna_transfer(ah, true);
                        udelay(5);
 
                        REG_CLR_BIT(ah, AR_MCI_TX_CTRL,
                                    AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
+                       REG_CLR_BIT(ah, AR_PHY_GLB_CONTROL,
+                                   AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
 
-                       if (AR_SREV_9462_20(ah)) {
-                               REG_CLR_BIT(ah, AR_PHY_GLB_CONTROL,
-                                           AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
-                               if (!(mci->config &
-                                     ATH_MCI_CONFIG_DISABLE_OSLA)) {
-                                       REG_SET_BIT(ah, AR_BTCOEX_CTRL,
-                                       AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
-                               }
+                       if (!(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA)) {
+                               REG_SET_BIT(ah, AR_BTCOEX_CTRL,
+                                           AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
                        }
                } else {
-                       ath_dbg(common, MCI, "MCI Send LNA take\n");
                        ar9003_mci_send_lna_take(ah, true);
                        udelay(5);
 
                        REG_SET_BIT(ah, AR_MCI_TX_CTRL,
                                    AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
-
-                       if (AR_SREV_9462_20(ah)) {
-                               REG_SET_BIT(ah, AR_PHY_GLB_CONTROL,
-                                           AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
-                               REG_CLR_BIT(ah, AR_BTCOEX_CTRL,
-                                       AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
-                       }
+                       REG_SET_BIT(ah, AR_PHY_GLB_CONTROL,
+                                   AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
+                       REG_CLR_BIT(ah, AR_BTCOEX_CTRL,
+                                   AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
 
                        ar9003_mci_send_2g5g_status(ah, true);
                }
@@ -934,28 +1060,19 @@ bool ar9003_mci_send_message(struct ath_hw *ah, u8 header, u32 flag,
        u32 saved_mci_int_en;
        int i;
 
-       if (!ATH9K_HW_CAP_MCI)
-               return false;
-
        saved_mci_int_en = REG_READ(ah, AR_MCI_INTERRUPT_EN);
        regval = REG_READ(ah, AR_BTCOEX_CTRL);
 
        if ((regval == 0xdeadbeef) || !(regval & AR_BTCOEX_CTRL_MCI_MODE_EN)) {
-
                ath_dbg(common, MCI,
                        "MCI Not sending 0x%x. MCI is not enabled. full_sleep = %d\n",
-                       header,
-                       (ah->power_mode == ATH9K_PM_FULL_SLEEP) ? 1 : 0);
-
+                       header, (ah->power_mode == ATH9K_PM_FULL_SLEEP) ? 1 : 0);
                ar9003_mci_queue_unsent_gpm(ah, header, payload, true);
                return false;
-
        } else if (check_bt && (mci->bt_state == MCI_BT_SLEEP)) {
-
                ath_dbg(common, MCI,
                        "MCI Don't send message 0x%x. BT is in sleep state\n",
                        header);
-
                ar9003_mci_queue_unsent_gpm(ah, header, payload, true);
                return false;
        }
@@ -983,7 +1100,7 @@ bool ar9003_mci_send_message(struct ath_hw *ah, u8 header, u32 flag,
 
        if (wait_done &&
            !(ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RAW,
-                                       AR_MCI_INTERRUPT_SW_MSG_DONE, 500)))
+                                           AR_MCI_INTERRUPT_SW_MSG_DONE, 500)))
                ar9003_mci_queue_unsent_gpm(ah, header, payload, true);
        else {
                ar9003_mci_queue_unsent_gpm(ah, header, payload, false);
@@ -997,220 +1114,64 @@ bool ar9003_mci_send_message(struct ath_hw *ah, u8 header, u32 flag,
 }
 EXPORT_SYMBOL(ar9003_mci_send_message);
 
-void ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf,
-                     u16 len, u32 sched_addr)
+void ar9003_mci_init_cal_req(struct ath_hw *ah, bool *is_reusable)
 {
-       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
-       void *sched_buf = (void *)((char *) gpm_buf + (sched_addr - gpm_addr));
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
+       u32 pld[4] = {0, 0, 0, 0};
 
-       if (!ATH9K_HW_CAP_MCI)
+       if ((mci_hw->bt_state != MCI_BT_AWAKE) ||
+           (mci_hw->config & ATH_MCI_CONFIG_DISABLE_MCI_CAL))
                return;
 
-       mci->gpm_addr = gpm_addr;
-       mci->gpm_buf = gpm_buf;
-       mci->gpm_len = len;
-       mci->sched_addr = sched_addr;
-       mci->sched_buf = sched_buf;
+       MCI_GPM_SET_CAL_TYPE(pld, MCI_GPM_WLAN_CAL_REQ);
+       pld[MCI_GPM_WLAN_CAL_W_SEQUENCE] = mci_hw->wlan_cal_seq++;
 
-       ar9003_mci_reset(ah, true, true, true);
+       ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, true, false);
+
+       if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_GRANT, 0, 50000)) {
+               ath_dbg(common, MCI, "MCI BT_CAL_GRANT received\n");
+       } else {
+               is_reusable = false;
+               ath_dbg(common, MCI, "MCI BT_CAL_GRANT not received\n");
+       }
 }
-EXPORT_SYMBOL(ar9003_mci_setup);
 
-void ar9003_mci_cleanup(struct ath_hw *ah)
+void ar9003_mci_init_cal_done(struct ath_hw *ah)
 {
-       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
+       u32 pld[4] = {0, 0, 0, 0};
 
-       if (!ATH9K_HW_CAP_MCI)
+       if ((mci_hw->bt_state != MCI_BT_AWAKE) ||
+           (mci_hw->config & ATH_MCI_CONFIG_DISABLE_MCI_CAL))
                return;
 
-       /* Turn off MCI and Jupiter mode. */
-       REG_WRITE(ah, AR_BTCOEX_CTRL, 0x00);
-       ath_dbg(common, MCI, "MCI ar9003_mci_cleanup\n");
-       ar9003_mci_disable_interrupt(ah);
+       MCI_GPM_SET_CAL_TYPE(pld, MCI_GPM_WLAN_CAL_DONE);
+       pld[MCI_GPM_WLAN_CAL_W_SEQUENCE] = mci_hw->wlan_cal_done++;
+       ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, true, false);
 }
-EXPORT_SYMBOL(ar9003_mci_cleanup);
 
-static void ar9003_mci_process_gpm_extra(struct ath_hw *ah, u8 gpm_type,
-                                        u8 gpm_opcode, u32 *p_gpm)
+void ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf,
+                     u16 len, u32 sched_addr)
 {
-       struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
-       u8 *p_data = (u8 *) p_gpm;
 
-       if (gpm_type != MCI_GPM_COEX_AGENT)
-               return;
+       mci->gpm_addr = gpm_addr;
+       mci->gpm_buf = gpm_buf;
+       mci->gpm_len = len;
+       mci->sched_addr = sched_addr;
 
-       switch (gpm_opcode) {
-       case MCI_GPM_COEX_VERSION_QUERY:
-               ath_dbg(common, MCI, "MCI Recv GPM COEX Version Query\n");
-               ar9003_mci_send_coex_version_response(ah, true);
-               break;
-       case MCI_GPM_COEX_VERSION_RESPONSE:
-               ath_dbg(common, MCI, "MCI Recv GPM COEX Version Response\n");
-               mci->bt_ver_major =
-                       *(p_data + MCI_GPM_COEX_B_MAJOR_VERSION);
-               mci->bt_ver_minor =
-                       *(p_data + MCI_GPM_COEX_B_MINOR_VERSION);
-               mci->bt_version_known = true;
-               ath_dbg(common, MCI, "MCI BT Coex version: %d.%d\n",
-                       mci->bt_ver_major, mci->bt_ver_minor);
-               break;
-       case MCI_GPM_COEX_STATUS_QUERY:
-               ath_dbg(common, MCI,
-                       "MCI Recv GPM COEX Status Query = 0x%02X\n",
-                       *(p_data + MCI_GPM_COEX_B_WLAN_BITMAP));
-               mci->wlan_channels_update = true;
-               ar9003_mci_send_coex_wlan_channels(ah, true);
-               break;
-       case MCI_GPM_COEX_BT_PROFILE_INFO:
-               mci->query_bt = true;
-               ath_dbg(common, MCI, "MCI Recv GPM COEX BT_Profile_Info\n");
-               break;
-       case MCI_GPM_COEX_BT_STATUS_UPDATE:
-               mci->query_bt = true;
-               ath_dbg(common, MCI,
-                       "MCI Recv GPM COEX BT_Status_Update SEQ=%d (drop&query)\n",
-                       *(p_gpm + 3));
-               break;
-       default:
-               break;
-       }
+       ar9003_mci_reset(ah, true, true, true);
 }
+EXPORT_SYMBOL(ar9003_mci_setup);
 
-u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type,
-                           u8 gpm_opcode, int time_out)
+void ar9003_mci_cleanup(struct ath_hw *ah)
 {
-       struct ath_common *common = ath9k_hw_common(ah);
-       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
-       u32 *p_gpm = NULL, mismatch = 0, more_data;
-       u32 offset;
-       u8 recv_type = 0, recv_opcode = 0;
-       bool b_is_bt_cal_done = (gpm_type == MCI_GPM_BT_CAL_DONE);
-
-       if (!ATH9K_HW_CAP_MCI)
-               return 0;
-
-       more_data = time_out ? MCI_GPM_NOMORE : MCI_GPM_MORE;
-
-       while (time_out > 0) {
-               if (p_gpm) {
-                       MCI_GPM_RECYCLE(p_gpm);
-                       p_gpm = NULL;
-               }
-
-               if (more_data != MCI_GPM_MORE)
-                       time_out = ar9003_mci_wait_for_interrupt(ah,
-                                       AR_MCI_INTERRUPT_RX_MSG_RAW,
-                                       AR_MCI_INTERRUPT_RX_MSG_GPM,
-                                       time_out);
-
-               if (!time_out)
-                       break;
-
-               offset = ar9003_mci_state(ah,
-                               MCI_STATE_NEXT_GPM_OFFSET, &more_data);
-
-               if (offset == MCI_GPM_INVALID)
-                       continue;
-
-               p_gpm = (u32 *) (mci->gpm_buf + offset);
-               recv_type = MCI_GPM_TYPE(p_gpm);
-               recv_opcode = MCI_GPM_OPCODE(p_gpm);
-
-               if (MCI_GPM_IS_CAL_TYPE(recv_type)) {
-
-                       if (recv_type == gpm_type) {
-
-                               if ((gpm_type == MCI_GPM_BT_CAL_DONE) &&
-                                   !b_is_bt_cal_done) {
-                                       gpm_type = MCI_GPM_BT_CAL_GRANT;
-                                       ath_dbg(common, MCI,
-                                               "MCI Recv BT_CAL_DONE wait BT_CAL_GRANT\n");
-                                       continue;
-                               }
-
-                               break;
-                       }
-               } else if ((recv_type == gpm_type) &&
-                          (recv_opcode == gpm_opcode))
-                       break;
-
-               /* not expected message */
-
-               /*
-                * check if it's cal_grant
-                *
-                * When we're waiting for cal_grant in reset routine,
-                * it's possible that BT sends out cal_request at the
-                * same time. Since BT's calibration doesn't happen
-                * that often, we'll let BT completes calibration then
-                * we continue to wait for cal_grant from BT.
-                * Orginal: Wait BT_CAL_GRANT.
-                * New: Receive BT_CAL_REQ -> send WLAN_CAL_GRANT->wait
-                * BT_CAL_DONE -> Wait BT_CAL_GRANT.
-                */
-
-               if ((gpm_type == MCI_GPM_BT_CAL_GRANT) &&
-                   (recv_type == MCI_GPM_BT_CAL_REQ)) {
-
-                       u32 payload[4] = {0, 0, 0, 0};
-
-                       gpm_type = MCI_GPM_BT_CAL_DONE;
-                       ath_dbg(common, MCI,
-                               "MCI Rcv BT_CAL_REQ, send WLAN_CAL_GRANT\n");
-
-                       MCI_GPM_SET_CAL_TYPE(payload,
-                                       MCI_GPM_WLAN_CAL_GRANT);
-
-                       ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
-                                               false, false);
-
-                       ath_dbg(common, MCI, "MCI now wait for BT_CAL_DONE\n");
-
-                       continue;
-               } else {
-                       ath_dbg(common, MCI, "MCI GPM subtype not match 0x%x\n",
-                               *(p_gpm + 1));
-                       mismatch++;
-                       ar9003_mci_process_gpm_extra(ah, recv_type,
-                                       recv_opcode, p_gpm);
-               }
-       }
-       if (p_gpm) {
-               MCI_GPM_RECYCLE(p_gpm);
-               p_gpm = NULL;
-       }
-
-       if (time_out <= 0) {
-               time_out = 0;
-               ath_dbg(common, MCI,
-                       "MCI GPM received timeout, mismatch = %d\n", mismatch);
-       } else
-               ath_dbg(common, MCI, "MCI Receive GPM type=0x%x, code=0x%x\n",
-                       gpm_type, gpm_opcode);
-
-       while (more_data == MCI_GPM_MORE) {
-
-               ath_dbg(common, MCI, "MCI discard remaining GPM\n");
-               offset = ar9003_mci_state(ah, MCI_STATE_NEXT_GPM_OFFSET,
-                                         &more_data);
-
-               if (offset == MCI_GPM_INVALID)
-                       break;
-
-               p_gpm = (u32 *) (mci->gpm_buf + offset);
-               recv_type = MCI_GPM_TYPE(p_gpm);
-               recv_opcode = MCI_GPM_OPCODE(p_gpm);
-
-               if (!MCI_GPM_IS_CAL_TYPE(recv_type))
-                       ar9003_mci_process_gpm_extra(ah, recv_type,
-                                                    recv_opcode, p_gpm);
-
-               MCI_GPM_RECYCLE(p_gpm);
-       }
-
-       return time_out;
+       /* Turn off MCI and Jupiter mode. */
+       REG_WRITE(ah, AR_BTCOEX_CTRL, 0x00);
+       ar9003_mci_disable_interrupt(ah);
 }
+EXPORT_SYMBOL(ar9003_mci_cleanup);
 
 u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
 {
@@ -1219,13 +1180,9 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
        u32 value = 0, more_gpm = 0, gpm_ptr;
        u8 query_type;
 
-       if (!ATH9K_HW_CAP_MCI)
-               return 0;
-
        switch (state_type) {
        case MCI_STATE_ENABLE:
                if (mci->ready) {
-
                        value = REG_READ(ah, AR_BTCOEX_CTRL);
 
                        if ((value == 0xdeadbeef) || (value == 0xffffffff))
@@ -1235,7 +1192,6 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
                break;
        case MCI_STATE_INIT_GPM_OFFSET:
                value = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR);
-               ath_dbg(common, MCI, "MCI GPM initial WRITE_PTR=%d\n", value);
                mci->gpm_idx = value;
                break;
        case MCI_STATE_NEXT_GPM_OFFSET:
@@ -1258,32 +1214,21 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
                if (value == 0)
                        value = mci->gpm_len - 1;
                else if (value >= mci->gpm_len) {
-                       if (value != 0xFFFF) {
+                       if (value != 0xFFFF)
                                value = 0;
-                               ath_dbg(common, MCI,
-                                       "MCI GPM offset out of range\n");
-                       }
-               } else
+               } else {
                        value--;
+               }
 
                if (value == 0xFFFF) {
                        value = MCI_GPM_INVALID;
                        more_gpm = MCI_GPM_NOMORE;
-                       ath_dbg(common, MCI,
-                               "MCI GPM ptr invalid @ptr=%d, offset=%d, more=GPM_NOMORE\n",
-                               gpm_ptr, value);
                } else if (state_type == MCI_STATE_NEXT_GPM_OFFSET) {
-
                        if (gpm_ptr == mci->gpm_idx) {
                                value = MCI_GPM_INVALID;
                                more_gpm = MCI_GPM_NOMORE;
-
-                               ath_dbg(common, MCI,
-                                       "MCI GPM message not available @ptr=%d, @offset=%d, more=GPM_NOMORE\n",
-                                       gpm_ptr, value);
                        } else {
                                for (;;) {
-
                                        u32 temp_index;
 
                                        /* skip reserved GPM if any */
@@ -1300,13 +1245,8 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
                                            mci->gpm_len)
                                                mci->gpm_idx = 0;
 
-                                       ath_dbg(common, MCI,
-                                               "MCI GPM message got ptr=%d, @offset=%d, more=%d\n",
-                                               gpm_ptr, temp_index,
-                                               (more_gpm == MCI_GPM_MORE));
-
                                        if (ar9003_mci_is_gpm_valid(ah,
-                                                               temp_index)) {
+                                                                   temp_index)) {
                                                value = temp_index;
                                                break;
                                        }
@@ -1331,79 +1271,59 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
                /* Make it in bytes */
                value <<= 4;
                break;
-
        case MCI_STATE_REMOTE_SLEEP:
                value = MS(REG_READ(ah, AR_MCI_RX_STATUS),
                           AR_MCI_RX_REMOTE_SLEEP) ?
                        MCI_BT_SLEEP : MCI_BT_AWAKE;
                break;
-
        case MCI_STATE_CONT_RSSI_POWER:
                value = MS(mci->cont_status, AR_MCI_CONT_RSSI_POWER);
-                       break;
-
+               break;
        case MCI_STATE_CONT_PRIORITY:
                value = MS(mci->cont_status, AR_MCI_CONT_RRIORITY);
                break;
-
        case MCI_STATE_CONT_TXRX:
                value = MS(mci->cont_status, AR_MCI_CONT_TXRX);
                break;
-
        case MCI_STATE_BT:
                value = mci->bt_state;
                break;
-
        case MCI_STATE_SET_BT_SLEEP:
                mci->bt_state = MCI_BT_SLEEP;
                break;
-
        case MCI_STATE_SET_BT_AWAKE:
                mci->bt_state = MCI_BT_AWAKE;
                ar9003_mci_send_coex_version_query(ah, true);
                ar9003_mci_send_coex_wlan_channels(ah, true);
 
-               if (mci->unhalt_bt_gpm) {
-
-                       ath_dbg(common, MCI, "MCI unhalt BT GPM\n");
+               if (mci->unhalt_bt_gpm)
                        ar9003_mci_send_coex_halt_bt_gpm(ah, false, true);
-               }
 
                ar9003_mci_2g5g_switch(ah, true);
                break;
-
        case MCI_STATE_SET_BT_CAL_START:
                mci->bt_state = MCI_BT_CAL_START;
                break;
-
        case MCI_STATE_SET_BT_CAL:
                mci->bt_state = MCI_BT_CAL;
                break;
-
        case MCI_STATE_RESET_REQ_WAKE:
                ar9003_mci_reset_req_wakeup(ah);
                mci->update_2g5g = true;
 
-               if ((AR_SREV_9462_20_OR_LATER(ah)) &&
-                   (mci->config & ATH_MCI_CONFIG_MCI_OBS_MASK)) {
+               if (mci->config & ATH_MCI_CONFIG_MCI_OBS_MASK) {
                        /* Check if we still have control of the GPIOs */
                        if ((REG_READ(ah, AR_GLB_GPIO_CONTROL) &
-                                     ATH_MCI_CONFIG_MCI_OBS_GPIO) !=
-                                       ATH_MCI_CONFIG_MCI_OBS_GPIO) {
-
-                               ath_dbg(common, MCI,
-                                       "MCI reconfigure observation\n");
+                            ATH_MCI_CONFIG_MCI_OBS_GPIO) !=
+                           ATH_MCI_CONFIG_MCI_OBS_GPIO) {
                                ar9003_mci_observation_set_up(ah);
                        }
                }
                break;
-
        case MCI_STATE_SEND_WLAN_COEX_VERSION:
                ar9003_mci_send_coex_version_response(ah, true);
                break;
-
        case MCI_STATE_SET_BT_COEX_VERSION:
-
                if (!p_data)
                        ath_dbg(common, MCI,
                                "MCI Set BT Coex version with NULL data!!\n");
@@ -1415,7 +1335,6 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
                                mci->bt_ver_major, mci->bt_ver_minor);
                }
                break;
-
        case MCI_STATE_SEND_WLAN_CHANNELS:
                if (p_data) {
                        if (((mci->wlan_channels[1] & 0xffff0000) ==
@@ -1432,19 +1351,13 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
                mci->wlan_channels_update = true;
                ar9003_mci_send_coex_wlan_channels(ah, true);
                break;
-
        case MCI_STATE_SEND_VERSION_QUERY:
                ar9003_mci_send_coex_version_query(ah, true);
                break;
-
        case MCI_STATE_SEND_STATUS_QUERY:
-               query_type = (AR_SREV_9462_10(ah)) ?
-                               MCI_GPM_COEX_QUERY_BT_ALL_INFO :
-                               MCI_GPM_COEX_QUERY_BT_TOPOLOGY;
-
+               query_type = MCI_GPM_COEX_QUERY_BT_TOPOLOGY;
                ar9003_mci_send_coex_bt_status_query(ah, true, query_type);
                break;
-
        case MCI_STATE_NEED_FLUSH_BT_INFO:
                        /*
                         * btcoex_hw.mci.unhalt_bt_gpm means whether it's
@@ -1464,28 +1377,21 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
                                mci->need_flush_btinfo =
                                        (*p_data != 0) ? true : false;
                        break;
-
        case MCI_STATE_RECOVER_RX:
-
-               ath_dbg(common, MCI, "MCI hw RECOVER_RX\n");
                ar9003_mci_prep_interface(ah);
                mci->query_bt = true;
                mci->need_flush_btinfo = true;
                ar9003_mci_send_coex_wlan_channels(ah, true);
                ar9003_mci_2g5g_switch(ah, true);
                break;
-
        case MCI_STATE_NEED_FTP_STOMP:
                value = !(mci->config & ATH_MCI_CONFIG_DISABLE_FTP_STOMP);
                break;
-
        case MCI_STATE_NEED_TUNING:
                value = !(mci->config & ATH_MCI_CONFIG_DISABLE_TUNING);
                break;
-
        default:
                break;
-
        }
 
        return value;
index 798da116a44c4b8f720cd22676e0519f482ce2ef..4842f6c06b8c3bc1640b17c7d90d606997a8b840 100644 (file)
@@ -99,4 +99,237 @@ enum mci_gpm_coex_bt_update_flags_op {
                                         ATH_MCI_CONFIG_MCI_OBS_BT)
 #define ATH_MCI_CONFIG_MCI_OBS_GPIO     0x0000002F
 
+enum mci_message_header {              /* length of payload */
+       MCI_LNA_CTRL     = 0x10,        /* len = 0 */
+       MCI_CONT_NACK    = 0x20,        /* len = 0 */
+       MCI_CONT_INFO    = 0x30,        /* len = 4 */
+       MCI_CONT_RST     = 0x40,        /* len = 0 */
+       MCI_SCHD_INFO    = 0x50,        /* len = 16 */
+       MCI_CPU_INT      = 0x60,        /* len = 4 */
+       MCI_SYS_WAKING   = 0x70,        /* len = 0 */
+       MCI_GPM          = 0x80,        /* len = 16 */
+       MCI_LNA_INFO     = 0x90,        /* len = 1 */
+       MCI_LNA_STATE    = 0x94,
+       MCI_LNA_TAKE     = 0x98,
+       MCI_LNA_TRANS    = 0x9c,
+       MCI_SYS_SLEEPING = 0xa0,        /* len = 0 */
+       MCI_REQ_WAKE     = 0xc0,        /* len = 0 */
+       MCI_DEBUG_16     = 0xfe,        /* len = 2 */
+       MCI_REMOTE_RESET = 0xff         /* len = 16 */
+};
+
+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
+};
+
+/* MCI GPM/Coex opcode/type definitions */
+enum {
+       MCI_GPM_COEX_W_GPM_PAYLOAD      = 1,
+       MCI_GPM_COEX_B_GPM_TYPE         = 4,
+       MCI_GPM_COEX_B_GPM_OPCODE       = 5,
+       /* MCI_GPM_WLAN_CAL_REQ, MCI_GPM_WLAN_CAL_DONE */
+       MCI_GPM_WLAN_CAL_W_SEQUENCE     = 2,
+
+       /* MCI_GPM_COEX_VERSION_QUERY */
+       /* MCI_GPM_COEX_VERSION_RESPONSE */
+       MCI_GPM_COEX_B_MAJOR_VERSION    = 6,
+       MCI_GPM_COEX_B_MINOR_VERSION    = 7,
+       /* MCI_GPM_COEX_STATUS_QUERY */
+       MCI_GPM_COEX_B_BT_BITMAP        = 6,
+       MCI_GPM_COEX_B_WLAN_BITMAP      = 7,
+       /* MCI_GPM_COEX_HALT_BT_GPM */
+       MCI_GPM_COEX_B_HALT_STATE       = 6,
+       /* MCI_GPM_COEX_WLAN_CHANNELS */
+       MCI_GPM_COEX_B_CHANNEL_MAP      = 6,
+       /* MCI_GPM_COEX_BT_PROFILE_INFO */
+       MCI_GPM_COEX_B_PROFILE_TYPE     = 6,
+       MCI_GPM_COEX_B_PROFILE_LINKID   = 7,
+       MCI_GPM_COEX_B_PROFILE_STATE    = 8,
+       MCI_GPM_COEX_B_PROFILE_ROLE     = 9,
+       MCI_GPM_COEX_B_PROFILE_RATE     = 10,
+       MCI_GPM_COEX_B_PROFILE_VOTYPE   = 11,
+       MCI_GPM_COEX_H_PROFILE_T        = 12,
+       MCI_GPM_COEX_B_PROFILE_W        = 14,
+       MCI_GPM_COEX_B_PROFILE_A        = 15,
+       /* MCI_GPM_COEX_BT_STATUS_UPDATE */
+       MCI_GPM_COEX_B_STATUS_TYPE      = 6,
+       MCI_GPM_COEX_B_STATUS_LINKID    = 7,
+       MCI_GPM_COEX_B_STATUS_STATE     = 8,
+       /* MCI_GPM_COEX_BT_UPDATE_FLAGS */
+       MCI_GPM_COEX_W_BT_FLAGS         = 6,
+       MCI_GPM_COEX_B_BT_FLAGS_OP      = 10
+};
+
+enum mci_gpm_subtype {
+       MCI_GPM_BT_CAL_REQ      = 0,
+       MCI_GPM_BT_CAL_GRANT    = 1,
+       MCI_GPM_BT_CAL_DONE     = 2,
+       MCI_GPM_WLAN_CAL_REQ    = 3,
+       MCI_GPM_WLAN_CAL_GRANT  = 4,
+       MCI_GPM_WLAN_CAL_DONE   = 5,
+       MCI_GPM_COEX_AGENT      = 0x0c,
+       MCI_GPM_RSVD_PATTERN    = 0xfe,
+       MCI_GPM_RSVD_PATTERN32  = 0xfefefefe,
+       MCI_GPM_BT_DEBUG        = 0xff
+};
+
+enum mci_bt_state {
+       MCI_BT_SLEEP,
+       MCI_BT_AWAKE,
+       MCI_BT_CAL_START,
+       MCI_BT_CAL
+};
+
+/* Type of state query */
+enum mci_state_type {
+       MCI_STATE_ENABLE,
+       MCI_STATE_INIT_GPM_OFFSET,
+       MCI_STATE_NEXT_GPM_OFFSET,
+       MCI_STATE_LAST_GPM_OFFSET,
+       MCI_STATE_BT,
+       MCI_STATE_SET_BT_SLEEP,
+       MCI_STATE_SET_BT_AWAKE,
+       MCI_STATE_SET_BT_CAL_START,
+       MCI_STATE_SET_BT_CAL,
+       MCI_STATE_LAST_SCHD_MSG_OFFSET,
+       MCI_STATE_REMOTE_SLEEP,
+       MCI_STATE_CONT_RSSI_POWER,
+       MCI_STATE_CONT_PRIORITY,
+       MCI_STATE_CONT_TXRX,
+       MCI_STATE_RESET_REQ_WAKE,
+       MCI_STATE_SEND_WLAN_COEX_VERSION,
+       MCI_STATE_SET_BT_COEX_VERSION,
+       MCI_STATE_SEND_WLAN_CHANNELS,
+       MCI_STATE_SEND_VERSION_QUERY,
+       MCI_STATE_SEND_STATUS_QUERY,
+       MCI_STATE_NEED_FLUSH_BT_INFO,
+       MCI_STATE_SET_CONCUR_TX_PRI,
+       MCI_STATE_RECOVER_RX,
+       MCI_STATE_NEED_FTP_STOMP,
+       MCI_STATE_NEED_TUNING,
+       MCI_STATE_DEBUG,
+       MCI_STATE_MAX
+};
+
+enum mci_gpm_coex_opcode {
+       MCI_GPM_COEX_VERSION_QUERY,
+       MCI_GPM_COEX_VERSION_RESPONSE,
+       MCI_GPM_COEX_STATUS_QUERY,
+       MCI_GPM_COEX_HALT_BT_GPM,
+       MCI_GPM_COEX_WLAN_CHANNELS,
+       MCI_GPM_COEX_BT_PROFILE_INFO,
+       MCI_GPM_COEX_BT_STATUS_UPDATE,
+       MCI_GPM_COEX_BT_UPDATE_FLAGS
+};
+
+#define MCI_GPM_NOMORE  0
+#define MCI_GPM_MORE    1
+#define MCI_GPM_INVALID 0xffffffff
+
+#define MCI_GPM_RECYCLE(_p_gpm)        do {                      \
+       *(((u32 *)_p_gpm) + MCI_GPM_COEX_W_GPM_PAYLOAD) = \
+                               MCI_GPM_RSVD_PATTERN32;   \
+} while (0)
+
+#define MCI_GPM_TYPE(_p_gpm)   \
+       (*(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_TYPE) & 0xff)
+
+#define MCI_GPM_OPCODE(_p_gpm) \
+       (*(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_OPCODE) & 0xff)
+
+#define MCI_GPM_SET_CAL_TYPE(_p_gpm, _cal_type)        do {                       \
+       *(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_TYPE) = (_cal_type) & 0xff;\
+} while (0)
+
+#define MCI_GPM_SET_TYPE_OPCODE(_p_gpm, _type, _opcode) do {              \
+       *(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_TYPE) = (_type) & 0xff;    \
+       *(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_OPCODE) = (_opcode) & 0xff;\
+} while (0)
+
+#define MCI_GPM_IS_CAL_TYPE(_type) ((_type) <= MCI_GPM_WLAN_CAL_DONE)
+
+/*
+ * Functions that are available to the MCI driver core.
+ */
+bool ar9003_mci_send_message(struct ath_hw *ah, u8 header, u32 flag,
+                            u32 *payload, u8 len, bool wait_done,
+                            bool check_bt);
+u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data);
+void ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf,
+                     u16 len, u32 sched_addr);
+void ar9003_mci_cleanup(struct ath_hw *ah);
+void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr,
+                             u32 *rx_msg_intr);
+
+/*
+ * These functions are used by ath9k_hw.
+ */
+
+#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
+
+static inline bool ar9003_mci_is_ready(struct ath_hw *ah)
+{
+       return ah->btcoex_hw.mci.ready;
+}
+void ar9003_mci_stop_bt(struct ath_hw *ah, bool save_fullsleep);
+void ar9003_mci_init_cal_req(struct ath_hw *ah, bool *is_reusable);
+void ar9003_mci_init_cal_done(struct ath_hw *ah);
+void ar9003_mci_set_full_sleep(struct ath_hw *ah);
+void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done);
+void ar9003_mci_check_bt(struct ath_hw *ah);
+bool ar9003_mci_start_reset(struct ath_hw *ah, struct ath9k_channel *chan);
+int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan,
+                        struct ath9k_hw_cal_data *caldata);
+void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
+                     bool is_full_sleep);
+void ar9003_mci_get_isr(struct ath_hw *ah, enum ath9k_int *masked);
+
+#else
+
+static inline bool ar9003_mci_is_ready(struct ath_hw *ah)
+{
+       return false;
+}
+static inline void ar9003_mci_stop_bt(struct ath_hw *ah, bool save_fullsleep)
+{
+}
+static inline void ar9003_mci_init_cal_req(struct ath_hw *ah, bool *is_reusable)
+{
+}
+static inline void ar9003_mci_init_cal_done(struct ath_hw *ah)
+{
+}
+static inline void ar9003_mci_set_full_sleep(struct ath_hw *ah)
+{
+}
+static inline void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done)
+{
+}
+static inline void ar9003_mci_check_bt(struct ath_hw *ah)
+{
+}
+static inline bool ar9003_mci_start_reset(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+       return false;
+}
+static inline int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan,
+                                      struct ath9k_hw_cal_data *caldata)
+{
+       return 0;
+}
+static inline void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
+                                   bool is_full_sleep)
+{
+}
+static inline void ar9003_mci_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
+{
+}
+#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
+
 #endif
index 2b0bfb8cca02d023da420b842f058b904807f646..70e27d2a5e43e76d4a59859c6ea26f6c7830c76e 100644 (file)
@@ -1099,13 +1099,20 @@ static void ar9003_hw_set_nf_limits(struct ath_hw *ah)
 {
        ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9300_2GHZ;
        ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9300_2GHZ;
-       if (AR_SREV_9330(ah))
-               ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9330_2GHZ;
-       else
-               ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9300_2GHZ;
+       ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9300_2GHZ;
        ah->nf_5g.max = AR_PHY_CCA_MAX_GOOD_VAL_9300_5GHZ;
        ah->nf_5g.min = AR_PHY_CCA_MIN_GOOD_VAL_9300_5GHZ;
        ah->nf_5g.nominal = AR_PHY_CCA_NOM_VAL_9300_5GHZ;
+
+       if (AR_SREV_9330(ah))
+               ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9330_2GHZ;
+
+       if (AR_SREV_9462(ah)) {
+               ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9462_2GHZ;
+               ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9462_2GHZ;
+               ah->nf_5g.min = AR_PHY_CCA_MIN_GOOD_VAL_9462_5GHZ;
+               ah->nf_5g.nominal = AR_PHY_CCA_NOM_VAL_9462_5GHZ;
+       }
 }
 
 /*
index ed64114571fcc133dffb3e1279015c51c82b0c27..d834d97fe7276e279402d4e3a75e6e6db1ac983f 100644 (file)
 
 #define AR_PHY_RX_OCGAIN        (AR_AGC_BASE + 0x200)
 
-#define AR_PHY_CCA_NOM_VAL_9300_2GHZ          (AR_SREV_9462(ah) ? -127 : -110)
-#define AR_PHY_CCA_NOM_VAL_9300_5GHZ          (AR_SREV_9462(ah) ? -127 : -115)
-#define AR_PHY_CCA_MIN_GOOD_VAL_9300_2GHZ     (AR_SREV_9462(ah) ? -127 : -125)
-#define AR_PHY_CCA_MIN_GOOD_VAL_9300_5GHZ     (AR_SREV_9462(ah) ? -127 : -125)
+#define AR_PHY_CCA_NOM_VAL_9300_2GHZ          -110
+#define AR_PHY_CCA_NOM_VAL_9300_5GHZ          -115
+#define AR_PHY_CCA_MIN_GOOD_VAL_9300_2GHZ     -125
+#define AR_PHY_CCA_MIN_GOOD_VAL_9300_5GHZ     -125
 #define AR_PHY_CCA_MAX_GOOD_VAL_9300_2GHZ     -95
 #define AR_PHY_CCA_MAX_GOOD_VAL_9300_5GHZ     -100
 
+#define AR_PHY_CCA_NOM_VAL_9462_2GHZ          -127
+#define AR_PHY_CCA_MIN_GOOD_VAL_9462_2GHZ     -127
+#define AR_PHY_CCA_NOM_VAL_9462_5GHZ          -127
+#define AR_PHY_CCA_MIN_GOOD_VAL_9462_5GHZ     -127
+
 #define AR_PHY_CCA_NOM_VAL_9330_2GHZ          -118
 
 /*
 #define AR_PHY_AIC_CTRL_1_B0   (AR_SM_BASE + 0x4b4)
 #define AR_PHY_AIC_CTRL_2_B0   (AR_SM_BASE + 0x4b8)
 #define AR_PHY_AIC_CTRL_3_B0   (AR_SM_BASE + 0x4bc)
-#define AR_PHY_AIC_STAT_0_B0   (AR_SM_BASE + (AR_SREV_9462_10(ah) ? \
-                                       0x4c0 : 0x4c4))
-#define AR_PHY_AIC_STAT_1_B0   (AR_SM_BASE + (AR_SREV_9462_10(ah) ? \
-                                       0x4c4 : 0x4c8))
+#define AR_PHY_AIC_STAT_0_B0   (AR_SM_BASE + 0x4c4))
+#define AR_PHY_AIC_STAT_1_B0   (AR_SM_BASE + 0x4c8))
 #define AR_PHY_AIC_CTRL_4_B0   (AR_SM_BASE + 0x4c0)
 #define AR_PHY_AIC_STAT_2_B0   (AR_SM_BASE + 0x4cc)
 
 #define AR_PHY_65NM_CH0_SYNTH4      0x1608c
-#define AR_PHY_SYNTH4_LONG_SHIFT_SELECT   0x00000002
-#define AR_PHY_SYNTH4_LONG_SHIFT_SELECT_S 1
+#define AR_PHY_SYNTH4_LONG_SHIFT_SELECT   (AR_SREV_9462(ah) ? 0x00000001 : 0x00000002)
+#define AR_PHY_SYNTH4_LONG_SHIFT_SELECT_S (AR_SREV_9462(ah) ? 0 : 1)
 #define AR_PHY_65NM_CH0_SYNTH7      0x16098
 #define AR_PHY_65NM_CH0_BIAS1       0x160c0
 #define AR_PHY_65NM_CH0_BIAS2       0x160c4
diff --git a/drivers/net/wireless/ath/ath9k/ar9462_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9462_1p0_initvals.h
deleted file mode 100644 (file)
index 5c55ae3..0000000
+++ /dev/null
@@ -1,1833 +0,0 @@
-/*
- * Copyright (c) 2010 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 INITVALS_9462_1P0_H
-#define INITVALS_9462_1P0_H
-
-/* AR9462 1.0 */
-
-static const u32 ar9462_1p0_mac_core[][2] = {
-       /* Addr      allmodes  */
-       {0x00000008, 0x00000000},
-       {0x00000030, 0x00060085},
-       {0x00000034, 0x00000005},
-       {0x00000040, 0x00000000},
-       {0x00000044, 0x00000000},
-       {0x00000048, 0x00000008},
-       {0x0000004c, 0x00000010},
-       {0x00000050, 0x00000000},
-       {0x00001040, 0x002ffc0f},
-       {0x00001044, 0x002ffc0f},
-       {0x00001048, 0x002ffc0f},
-       {0x0000104c, 0x002ffc0f},
-       {0x00001050, 0x002ffc0f},
-       {0x00001054, 0x002ffc0f},
-       {0x00001058, 0x002ffc0f},
-       {0x0000105c, 0x002ffc0f},
-       {0x00001060, 0x002ffc0f},
-       {0x00001064, 0x002ffc0f},
-       {0x000010f0, 0x00000100},
-       {0x00001270, 0x00000000},
-       {0x000012b0, 0x00000000},
-       {0x000012f0, 0x00000000},
-       {0x0000143c, 0x00000000},
-       {0x0000147c, 0x00000000},
-       {0x00001810, 0x0f000003},
-       {0x00008000, 0x00000000},
-       {0x00008004, 0x00000000},
-       {0x00008008, 0x00000000},
-       {0x0000800c, 0x00000000},
-       {0x00008018, 0x00000000},
-       {0x00008020, 0x00000000},
-       {0x00008038, 0x00000000},
-       {0x0000803c, 0x00080000},
-       {0x00008040, 0x00000000},
-       {0x00008044, 0x00000000},
-       {0x00008048, 0x00000000},
-       {0x0000804c, 0xffffffff},
-       {0x00008050, 0xffffffff},
-       {0x00008054, 0x00000000},
-       {0x00008058, 0x00000000},
-       {0x0000805c, 0x000fc78f},
-       {0x00008060, 0x0000000f},
-       {0x00008064, 0x00000000},
-       {0x00008070, 0x00000310},
-       {0x00008074, 0x00000020},
-       {0x00008078, 0x00000000},
-       {0x0000809c, 0x0000000f},
-       {0x000080a0, 0x00000000},
-       {0x000080a4, 0x02ff0000},
-       {0x000080a8, 0x0e070605},
-       {0x000080ac, 0x0000000d},
-       {0x000080b0, 0x00000000},
-       {0x000080b4, 0x00000000},
-       {0x000080b8, 0x00000000},
-       {0x000080bc, 0x00000000},
-       {0x000080c0, 0x2a800000},
-       {0x000080c4, 0x06900168},
-       {0x000080c8, 0x13881c20},
-       {0x000080cc, 0x01f40000},
-       {0x000080d0, 0x00252500},
-       {0x000080d4, 0x00a00005},
-       {0x000080d8, 0x00400002},
-       {0x000080dc, 0x00000000},
-       {0x000080e0, 0xffffffff},
-       {0x000080e4, 0x0000ffff},
-       {0x000080e8, 0x3f3f3f3f},
-       {0x000080ec, 0x00000000},
-       {0x000080f0, 0x00000000},
-       {0x000080f4, 0x00000000},
-       {0x000080fc, 0x00020000},
-       {0x00008100, 0x00000000},
-       {0x00008108, 0x00000052},
-       {0x0000810c, 0x00000000},
-       {0x00008110, 0x00000000},
-       {0x00008114, 0x000007ff},
-       {0x00008118, 0x000000aa},
-       {0x0000811c, 0x00003210},
-       {0x00008124, 0x00000000},
-       {0x00008128, 0x00000000},
-       {0x0000812c, 0x00000000},
-       {0x00008130, 0x00000000},
-       {0x00008134, 0x00000000},
-       {0x00008138, 0x00000000},
-       {0x0000813c, 0x0000ffff},
-       {0x00008144, 0xffffffff},
-       {0x00008168, 0x00000000},
-       {0x0000816c, 0x00000000},
-       {0x00008170, 0x18486e00},
-       {0x00008174, 0x33332210},
-       {0x00008178, 0x00000000},
-       {0x0000817c, 0x00020000},
-       {0x000081c4, 0x33332210},
-       {0x000081c8, 0x00000000},
-       {0x000081cc, 0x00000000},
-       {0x000081d4, 0x00000000},
-       {0x000081ec, 0x00000000},
-       {0x000081f0, 0x00000000},
-       {0x000081f4, 0x00000000},
-       {0x000081f8, 0x00000000},
-       {0x000081fc, 0x00000000},
-       {0x00008240, 0x00100000},
-       {0x00008244, 0x0010f400},
-       {0x00008248, 0x00000800},
-       {0x0000824c, 0x0001e800},
-       {0x00008250, 0x00000000},
-       {0x00008254, 0x00000000},
-       {0x00008258, 0x00000000},
-       {0x0000825c, 0x40000000},
-       {0x00008260, 0x00080922},
-       {0x00008264, 0x99c00010},
-       {0x00008268, 0xffffffff},
-       {0x0000826c, 0x0000ffff},
-       {0x00008270, 0x00000000},
-       {0x00008274, 0x40000000},
-       {0x00008278, 0x003e4180},
-       {0x0000827c, 0x00000004},
-       {0x00008284, 0x0000002c},
-       {0x00008288, 0x0000002c},
-       {0x0000828c, 0x000000ff},
-       {0x00008294, 0x00000000},
-       {0x00008298, 0x00000000},
-       {0x0000829c, 0x00000000},
-       {0x00008300, 0x00000140},
-       {0x00008314, 0x00000000},
-       {0x0000831c, 0x0000010d},
-       {0x00008328, 0x00000000},
-       {0x0000832c, 0x0000001f},
-       {0x00008330, 0x00000302},
-       {0x00008334, 0x00000700},
-       {0x00008338, 0xffff0000},
-       {0x0000833c, 0x02400000},
-       {0x00008340, 0x000107ff},
-       {0x00008344, 0xaa48105b},
-       {0x00008348, 0x008f0000},
-       {0x0000835c, 0x00000000},
-       {0x00008360, 0xffffffff},
-       {0x00008364, 0xffffffff},
-       {0x00008368, 0x00000000},
-       {0x00008370, 0x00000000},
-       {0x00008374, 0x000000ff},
-       {0x00008378, 0x00000000},
-       {0x0000837c, 0x00000000},
-       {0x00008380, 0xffffffff},
-       {0x00008384, 0xffffffff},
-       {0x00008390, 0xffffffff},
-       {0x00008394, 0xffffffff},
-       {0x00008398, 0x00000000},
-       {0x0000839c, 0x00000000},
-       {0x000083a4, 0x0000fa14},
-       {0x000083a8, 0x000f0c00},
-       {0x000083ac, 0x33332210},
-       {0x000083b0, 0x33332210},
-       {0x000083b4, 0x33332210},
-       {0x000083b8, 0x33332210},
-       {0x000083bc, 0x00000000},
-       {0x000083c0, 0x00000000},
-       {0x000083c4, 0x00000000},
-       {0x000083c8, 0x00000000},
-       {0x000083cc, 0x00000200},
-       {0x000083d0, 0x000301ff},
-};
-
-static const u32 ar9462_1p0_baseband_core_txfir_coeff_japan_2484[][2] = {
-       /* Addr      allmodes  */
-       {0x0000a398, 0x00000000},
-       {0x0000a39c, 0x6f7f0301},
-       {0x0000a3a0, 0xca9228ee},
-};
-
-static const u32 ar9462_1p0_sys3ant[][2] = {
-       /* Addr      allmodes  */
-       {0x00063280, 0x00040807},
-       {0x00063284, 0x104ccccc},
-};
-
-static const u32 ar9462_pcie_phy_clkreq_enable_L1_1p0[][2] = {
-       /* Addr      allmodes  */
-       {0x00018c00, 0x10053e5e},
-       {0x00018c04, 0x000801d8},
-       {0x00018c08, 0x0000580c},
-};
-
-static const u32 ar9462_1p0_mac_core_emulation[][2] = {
-       /* Addr      allmodes  */
-       {0x00000030, 0x00060085},
-       {0x00000044, 0x00000008},
-       {0x0000805c, 0xffffc7ff},
-       {0x00008344, 0xaa4a105b},
-};
-
-static const u32 ar9462_common_rx_gain_table_ar9280_2p0_1p0[][2] = {
-       /* Addr      allmodes  */
-       {0x0000a000, 0x02000101},
-       {0x0000a004, 0x02000102},
-       {0x0000a008, 0x02000103},
-       {0x0000a00c, 0x02000104},
-       {0x0000a010, 0x02000200},
-       {0x0000a014, 0x02000201},
-       {0x0000a018, 0x02000202},
-       {0x0000a01c, 0x02000203},
-       {0x0000a020, 0x02000204},
-       {0x0000a024, 0x02000205},
-       {0x0000a028, 0x02000208},
-       {0x0000a02c, 0x02000302},
-       {0x0000a030, 0x02000303},
-       {0x0000a034, 0x02000304},
-       {0x0000a038, 0x02000400},
-       {0x0000a03c, 0x02010300},
-       {0x0000a040, 0x02010301},
-       {0x0000a044, 0x02010302},
-       {0x0000a048, 0x02000500},
-       {0x0000a04c, 0x02010400},
-       {0x0000a050, 0x02020300},
-       {0x0000a054, 0x02020301},
-       {0x0000a058, 0x02020302},
-       {0x0000a05c, 0x02020303},
-       {0x0000a060, 0x02020400},
-       {0x0000a064, 0x02030300},
-       {0x0000a068, 0x02030301},
-       {0x0000a06c, 0x02030302},
-       {0x0000a070, 0x02030303},
-       {0x0000a074, 0x02030400},
-       {0x0000a078, 0x02040300},
-       {0x0000a07c, 0x02040301},
-       {0x0000a080, 0x02040302},
-       {0x0000a084, 0x02040303},
-       {0x0000a088, 0x02030500},
-       {0x0000a08c, 0x02040400},
-       {0x0000a090, 0x02050203},
-       {0x0000a094, 0x02050204},
-       {0x0000a098, 0x02050205},
-       {0x0000a09c, 0x02040500},
-       {0x0000a0a0, 0x02050301},
-       {0x0000a0a4, 0x02050302},
-       {0x0000a0a8, 0x02050303},
-       {0x0000a0ac, 0x02050400},
-       {0x0000a0b0, 0x02050401},
-       {0x0000a0b4, 0x02050402},
-       {0x0000a0b8, 0x02050403},
-       {0x0000a0bc, 0x02050500},
-       {0x0000a0c0, 0x02050501},
-       {0x0000a0c4, 0x02050502},
-       {0x0000a0c8, 0x02050503},
-       {0x0000a0cc, 0x02050504},
-       {0x0000a0d0, 0x02050600},
-       {0x0000a0d4, 0x02050601},
-       {0x0000a0d8, 0x02050602},
-       {0x0000a0dc, 0x02050603},
-       {0x0000a0e0, 0x02050604},
-       {0x0000a0e4, 0x02050700},
-       {0x0000a0e8, 0x02050701},
-       {0x0000a0ec, 0x02050702},
-       {0x0000a0f0, 0x02050703},
-       {0x0000a0f4, 0x02050704},
-       {0x0000a0f8, 0x02050705},
-       {0x0000a0fc, 0x02050708},
-       {0x0000a100, 0x02050709},
-       {0x0000a104, 0x0205070a},
-       {0x0000a108, 0x0205070b},
-       {0x0000a10c, 0x0205070c},
-       {0x0000a110, 0x0205070d},
-       {0x0000a114, 0x02050710},
-       {0x0000a118, 0x02050711},
-       {0x0000a11c, 0x02050712},
-       {0x0000a120, 0x02050713},
-       {0x0000a124, 0x02050714},
-       {0x0000a128, 0x02050715},
-       {0x0000a12c, 0x02050730},
-       {0x0000a130, 0x02050731},
-       {0x0000a134, 0x02050732},
-       {0x0000a138, 0x02050733},
-       {0x0000a13c, 0x02050734},
-       {0x0000a140, 0x02050735},
-       {0x0000a144, 0x02050750},
-       {0x0000a148, 0x02050751},
-       {0x0000a14c, 0x02050752},
-       {0x0000a150, 0x02050753},
-       {0x0000a154, 0x02050754},
-       {0x0000a158, 0x02050755},
-       {0x0000a15c, 0x02050770},
-       {0x0000a160, 0x02050771},
-       {0x0000a164, 0x02050772},
-       {0x0000a168, 0x02050773},
-       {0x0000a16c, 0x02050774},
-       {0x0000a170, 0x02050775},
-       {0x0000a174, 0x00000776},
-       {0x0000a178, 0x00000776},
-       {0x0000a17c, 0x00000776},
-       {0x0000a180, 0x00000776},
-       {0x0000a184, 0x00000776},
-       {0x0000a188, 0x00000776},
-       {0x0000a18c, 0x00000776},
-       {0x0000a190, 0x00000776},
-       {0x0000a194, 0x00000776},
-       {0x0000a198, 0x00000776},
-       {0x0000a19c, 0x00000776},
-       {0x0000a1a0, 0x00000776},
-       {0x0000a1a4, 0x00000776},
-       {0x0000a1a8, 0x00000776},
-       {0x0000a1ac, 0x00000776},
-       {0x0000a1b0, 0x00000776},
-       {0x0000a1b4, 0x00000776},
-       {0x0000a1b8, 0x00000776},
-       {0x0000a1bc, 0x00000776},
-       {0x0000a1c0, 0x00000776},
-       {0x0000a1c4, 0x00000776},
-       {0x0000a1c8, 0x00000776},
-       {0x0000a1cc, 0x00000776},
-       {0x0000a1d0, 0x00000776},
-       {0x0000a1d4, 0x00000776},
-       {0x0000a1d8, 0x00000776},
-       {0x0000a1dc, 0x00000776},
-       {0x0000a1e0, 0x00000776},
-       {0x0000a1e4, 0x00000776},
-       {0x0000a1e8, 0x00000776},
-       {0x0000a1ec, 0x00000776},
-       {0x0000a1f0, 0x00000776},
-       {0x0000a1f4, 0x00000776},
-       {0x0000a1f8, 0x00000776},
-       {0x0000a1fc, 0x00000776},
-       {0x0000b000, 0x02000101},
-       {0x0000b004, 0x02000102},
-       {0x0000b008, 0x02000103},
-       {0x0000b00c, 0x02000104},
-       {0x0000b010, 0x02000200},
-       {0x0000b014, 0x02000201},
-       {0x0000b018, 0x02000202},
-       {0x0000b01c, 0x02000203},
-       {0x0000b020, 0x02000204},
-       {0x0000b024, 0x02000205},
-       {0x0000b028, 0x02000208},
-       {0x0000b02c, 0x02000302},
-       {0x0000b030, 0x02000303},
-       {0x0000b034, 0x02000304},
-       {0x0000b038, 0x02000400},
-       {0x0000b03c, 0x02010300},
-       {0x0000b040, 0x02010301},
-       {0x0000b044, 0x02010302},
-       {0x0000b048, 0x02000500},
-       {0x0000b04c, 0x02010400},
-       {0x0000b050, 0x02020300},
-       {0x0000b054, 0x02020301},
-       {0x0000b058, 0x02020302},
-       {0x0000b05c, 0x02020303},
-       {0x0000b060, 0x02020400},
-       {0x0000b064, 0x02030300},
-       {0x0000b068, 0x02030301},
-       {0x0000b06c, 0x02030302},
-       {0x0000b070, 0x02030303},
-       {0x0000b074, 0x02030400},
-       {0x0000b078, 0x02040300},
-       {0x0000b07c, 0x02040301},
-       {0x0000b080, 0x02040302},
-       {0x0000b084, 0x02040303},
-       {0x0000b088, 0x02030500},
-       {0x0000b08c, 0x02040400},
-       {0x0000b090, 0x02050203},
-       {0x0000b094, 0x02050204},
-       {0x0000b098, 0x02050205},
-       {0x0000b09c, 0x02040500},
-       {0x0000b0a0, 0x02050301},
-       {0x0000b0a4, 0x02050302},
-       {0x0000b0a8, 0x02050303},
-       {0x0000b0ac, 0x02050400},
-       {0x0000b0b0, 0x02050401},
-       {0x0000b0b4, 0x02050402},
-       {0x0000b0b8, 0x02050403},
-       {0x0000b0bc, 0x02050500},
-       {0x0000b0c0, 0x02050501},
-       {0x0000b0c4, 0x02050502},
-       {0x0000b0c8, 0x02050503},
-       {0x0000b0cc, 0x02050504},
-       {0x0000b0d0, 0x02050600},
-       {0x0000b0d4, 0x02050601},
-       {0x0000b0d8, 0x02050602},
-       {0x0000b0dc, 0x02050603},
-       {0x0000b0e0, 0x02050604},
-       {0x0000b0e4, 0x02050700},
-       {0x0000b0e8, 0x02050701},
-       {0x0000b0ec, 0x02050702},
-       {0x0000b0f0, 0x02050703},
-       {0x0000b0f4, 0x02050704},
-       {0x0000b0f8, 0x02050705},
-       {0x0000b0fc, 0x02050708},
-       {0x0000b100, 0x02050709},
-       {0x0000b104, 0x0205070a},
-       {0x0000b108, 0x0205070b},
-       {0x0000b10c, 0x0205070c},
-       {0x0000b110, 0x0205070d},
-       {0x0000b114, 0x02050710},
-       {0x0000b118, 0x02050711},
-       {0x0000b11c, 0x02050712},
-       {0x0000b120, 0x02050713},
-       {0x0000b124, 0x02050714},
-       {0x0000b128, 0x02050715},
-       {0x0000b12c, 0x02050730},
-       {0x0000b130, 0x02050731},
-       {0x0000b134, 0x02050732},
-       {0x0000b138, 0x02050733},
-       {0x0000b13c, 0x02050734},
-       {0x0000b140, 0x02050735},
-       {0x0000b144, 0x02050750},
-       {0x0000b148, 0x02050751},
-       {0x0000b14c, 0x02050752},
-       {0x0000b150, 0x02050753},
-       {0x0000b154, 0x02050754},
-       {0x0000b158, 0x02050755},
-       {0x0000b15c, 0x02050770},
-       {0x0000b160, 0x02050771},
-       {0x0000b164, 0x02050772},
-       {0x0000b168, 0x02050773},
-       {0x0000b16c, 0x02050774},
-       {0x0000b170, 0x02050775},
-       {0x0000b174, 0x00000776},
-       {0x0000b178, 0x00000776},
-       {0x0000b17c, 0x00000776},
-       {0x0000b180, 0x00000776},
-       {0x0000b184, 0x00000776},
-       {0x0000b188, 0x00000776},
-       {0x0000b18c, 0x00000776},
-       {0x0000b190, 0x00000776},
-       {0x0000b194, 0x00000776},
-       {0x0000b198, 0x00000776},
-       {0x0000b19c, 0x00000776},
-       {0x0000b1a0, 0x00000776},
-       {0x0000b1a4, 0x00000776},
-       {0x0000b1a8, 0x00000776},
-       {0x0000b1ac, 0x00000776},
-       {0x0000b1b0, 0x00000776},
-       {0x0000b1b4, 0x00000776},
-       {0x0000b1b8, 0x00000776},
-       {0x0000b1bc, 0x00000776},
-       {0x0000b1c0, 0x00000776},
-       {0x0000b1c4, 0x00000776},
-       {0x0000b1c8, 0x00000776},
-       {0x0000b1cc, 0x00000776},
-       {0x0000b1d0, 0x00000776},
-       {0x0000b1d4, 0x00000776},
-       {0x0000b1d8, 0x00000776},
-       {0x0000b1dc, 0x00000776},
-       {0x0000b1e0, 0x00000776},
-       {0x0000b1e4, 0x00000776},
-       {0x0000b1e8, 0x00000776},
-       {0x0000b1ec, 0x00000776},
-       {0x0000b1f0, 0x00000776},
-       {0x0000b1f4, 0x00000776},
-       {0x0000b1f8, 0x00000776},
-       {0x0000b1fc, 0x00000776},
-};
-
-static const u32 ar9200_ar9280_2p0_radio_core_1p0[][2] = {
-       /* Addr      allmodes  */
-       {0x00007800, 0x00040000},
-       {0x00007804, 0xdb005012},
-       {0x00007808, 0x04924914},
-       {0x0000780c, 0x21084210},
-       {0x00007810, 0x6d801300},
-       {0x00007814, 0x0019beff},
-       {0x00007818, 0x07e41000},
-       {0x0000781c, 0x00392000},
-       {0x00007820, 0x92592480},
-       {0x00007824, 0x00040000},
-       {0x00007828, 0xdb005012},
-       {0x0000782c, 0x04924914},
-       {0x00007830, 0x21084210},
-       {0x00007834, 0x6d801300},
-       {0x00007838, 0x0019beff},
-       {0x0000783c, 0x07e40000},
-       {0x00007840, 0x00392000},
-       {0x00007844, 0x92592480},
-       {0x00007848, 0x00100000},
-       {0x0000784c, 0x773f0567},
-       {0x00007850, 0x54214514},
-       {0x00007854, 0x12035828},
-       {0x00007858, 0x92592692},
-       {0x0000785c, 0x00000000},
-       {0x00007860, 0x56400000},
-       {0x00007864, 0x0a8e370e},
-       {0x00007868, 0xc0102850},
-       {0x0000786c, 0x812d4000},
-       {0x00007870, 0x807ec400},
-       {0x00007874, 0x001b6db0},
-       {0x00007878, 0x00376b63},
-       {0x0000787c, 0x06db6db6},
-       {0x00007880, 0x006d8000},
-       {0x00007884, 0xffeffffe},
-       {0x00007888, 0xffeffffe},
-       {0x0000788c, 0x00010000},
-       {0x00007890, 0x02060aeb},
-       {0x00007894, 0x5a108000},
-};
-
-static const u32 ar9462_1p0_baseband_postamble_emulation[][5] = {
-       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-       {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x00009e3c, 0xcf946221, 0xcf946221, 0xcf946221, 0xcf946221},
-       {0x00009e44, 0x005c0000, 0x005c0000, 0x005c0000, 0x005c0000},
-       {0x0000a258, 0x02020200, 0x02020200, 0x02020200, 0x02020200},
-       {0x0000a25c, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
-       {0x0000a28c, 0x00011111, 0x00011111, 0x00011111, 0x00011111},
-       {0x0000a2c4, 0x00148d18, 0x00148d18, 0x00148d20, 0x00148d20},
-       {0x0000a2d8, 0xf999a800, 0xf999a800, 0xf999a80c, 0xf999a80c},
-       {0x0000a50c, 0x0000c00a, 0x0000c00a, 0x0000c00a, 0x0000c00a},
-       {0x0000a538, 0x00038e8c, 0x00038e8c, 0x00038e8c, 0x00038e8c},
-       {0x0000a53c, 0x0003cecc, 0x0003cecc, 0x0003cecc, 0x0003cecc},
-       {0x0000a540, 0x00040ed4, 0x00040ed4, 0x00040ed4, 0x00040ed4},
-       {0x0000a544, 0x00044edc, 0x00044edc, 0x00044edc, 0x00044edc},
-       {0x0000a548, 0x00048ede, 0x00048ede, 0x00048ede, 0x00048ede},
-       {0x0000a54c, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e},
-       {0x0000a550, 0x00050f5e, 0x00050f5e, 0x00050f5e, 0x00050f5e},
-       {0x0000a554, 0x00054f9e, 0x00054f9e, 0x00054f9e, 0x00054f9e},
-       {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-};
-
-static const u32 ar9462_pcie_phy_pll_on_clkreq_disable_L1_1p0[][2] = {
-       /* Addr      allmodes  */
-       {0x00018c00, 0x10012e5e},
-       {0x00018c04, 0x000801d8},
-       {0x00018c08, 0x0000580c},
-};
-
-static const u32 ar9462_common_rx_gain_table_1p0[][2] = {
-       /* Addr      allmodes  */
-       {0x0000a000, 0x00010000},
-       {0x0000a004, 0x00030002},
-       {0x0000a008, 0x00050004},
-       {0x0000a00c, 0x00810080},
-       {0x0000a010, 0x00830082},
-       {0x0000a014, 0x01810180},
-       {0x0000a018, 0x01830182},
-       {0x0000a01c, 0x01850184},
-       {0x0000a020, 0x01890188},
-       {0x0000a024, 0x018b018a},
-       {0x0000a028, 0x018d018c},
-       {0x0000a02c, 0x01910190},
-       {0x0000a030, 0x01930192},
-       {0x0000a034, 0x01950194},
-       {0x0000a038, 0x038a0196},
-       {0x0000a03c, 0x038c038b},
-       {0x0000a040, 0x0390038d},
-       {0x0000a044, 0x03920391},
-       {0x0000a048, 0x03940393},
-       {0x0000a04c, 0x03960395},
-       {0x0000a050, 0x00000000},
-       {0x0000a054, 0x00000000},
-       {0x0000a058, 0x00000000},
-       {0x0000a05c, 0x00000000},
-       {0x0000a060, 0x00000000},
-       {0x0000a064, 0x00000000},
-       {0x0000a068, 0x00000000},
-       {0x0000a06c, 0x00000000},
-       {0x0000a070, 0x00000000},
-       {0x0000a074, 0x00000000},
-       {0x0000a078, 0x00000000},
-       {0x0000a07c, 0x00000000},
-       {0x0000a080, 0x22222229},
-       {0x0000a084, 0x1d1d1d1d},
-       {0x0000a088, 0x1d1d1d1d},
-       {0x0000a08c, 0x1d1d1d1d},
-       {0x0000a090, 0x171d1d1d},
-       {0x0000a094, 0x11111717},
-       {0x0000a098, 0x00030311},
-       {0x0000a09c, 0x00000000},
-       {0x0000a0a0, 0x00000000},
-       {0x0000a0a4, 0x00000000},
-       {0x0000a0a8, 0x00000000},
-       {0x0000a0ac, 0x00000000},
-       {0x0000a0b0, 0x00000000},
-       {0x0000a0b4, 0x00000000},
-       {0x0000a0b8, 0x00000000},
-       {0x0000a0bc, 0x00000000},
-       {0x0000a0c0, 0x001f0000},
-       {0x0000a0c4, 0x01000101},
-       {0x0000a0c8, 0x011e011f},
-       {0x0000a0cc, 0x011c011d},
-       {0x0000a0d0, 0x02030204},
-       {0x0000a0d4, 0x02010202},
-       {0x0000a0d8, 0x021f0200},
-       {0x0000a0dc, 0x0302021e},
-       {0x0000a0e0, 0x03000301},
-       {0x0000a0e4, 0x031e031f},
-       {0x0000a0e8, 0x0402031d},
-       {0x0000a0ec, 0x04000401},
-       {0x0000a0f0, 0x041e041f},
-       {0x0000a0f4, 0x0502041d},
-       {0x0000a0f8, 0x05000501},
-       {0x0000a0fc, 0x051e051f},
-       {0x0000a100, 0x06010602},
-       {0x0000a104, 0x061f0600},
-       {0x0000a108, 0x061d061e},
-       {0x0000a10c, 0x07020703},
-       {0x0000a110, 0x07000701},
-       {0x0000a114, 0x00000000},
-       {0x0000a118, 0x00000000},
-       {0x0000a11c, 0x00000000},
-       {0x0000a120, 0x00000000},
-       {0x0000a124, 0x00000000},
-       {0x0000a128, 0x00000000},
-       {0x0000a12c, 0x00000000},
-       {0x0000a130, 0x00000000},
-       {0x0000a134, 0x00000000},
-       {0x0000a138, 0x00000000},
-       {0x0000a13c, 0x00000000},
-       {0x0000a140, 0x001f0000},
-       {0x0000a144, 0x01000101},
-       {0x0000a148, 0x011e011f},
-       {0x0000a14c, 0x011c011d},
-       {0x0000a150, 0x02030204},
-       {0x0000a154, 0x02010202},
-       {0x0000a158, 0x021f0200},
-       {0x0000a15c, 0x0302021e},
-       {0x0000a160, 0x03000301},
-       {0x0000a164, 0x031e031f},
-       {0x0000a168, 0x0402031d},
-       {0x0000a16c, 0x04000401},
-       {0x0000a170, 0x041e041f},
-       {0x0000a174, 0x0502041d},
-       {0x0000a178, 0x05000501},
-       {0x0000a17c, 0x051e051f},
-       {0x0000a180, 0x06010602},
-       {0x0000a184, 0x061f0600},
-       {0x0000a188, 0x061d061e},
-       {0x0000a18c, 0x07020703},
-       {0x0000a190, 0x07000701},
-       {0x0000a194, 0x00000000},
-       {0x0000a198, 0x00000000},
-       {0x0000a19c, 0x00000000},
-       {0x0000a1a0, 0x00000000},
-       {0x0000a1a4, 0x00000000},
-       {0x0000a1a8, 0x00000000},
-       {0x0000a1ac, 0x00000000},
-       {0x0000a1b0, 0x00000000},
-       {0x0000a1b4, 0x00000000},
-       {0x0000a1b8, 0x00000000},
-       {0x0000a1bc, 0x00000000},
-       {0x0000a1c0, 0x00000000},
-       {0x0000a1c4, 0x00000000},
-       {0x0000a1c8, 0x00000000},
-       {0x0000a1cc, 0x00000000},
-       {0x0000a1d0, 0x00000000},
-       {0x0000a1d4, 0x00000000},
-       {0x0000a1d8, 0x00000000},
-       {0x0000a1dc, 0x00000000},
-       {0x0000a1e0, 0x00000000},
-       {0x0000a1e4, 0x00000000},
-       {0x0000a1e8, 0x00000000},
-       {0x0000a1ec, 0x00000000},
-       {0x0000a1f0, 0x00000396},
-       {0x0000a1f4, 0x00000396},
-       {0x0000a1f8, 0x00000396},
-       {0x0000a1fc, 0x00000196},
-       {0x0000b000, 0x00010000},
-       {0x0000b004, 0x00030002},
-       {0x0000b008, 0x00050004},
-       {0x0000b00c, 0x00810080},
-       {0x0000b010, 0x00830082},
-       {0x0000b014, 0x01810180},
-       {0x0000b018, 0x01830182},
-       {0x0000b01c, 0x01850184},
-       {0x0000b020, 0x02810280},
-       {0x0000b024, 0x02830282},
-       {0x0000b028, 0x02850284},
-       {0x0000b02c, 0x02890288},
-       {0x0000b030, 0x028b028a},
-       {0x0000b034, 0x0388028c},
-       {0x0000b038, 0x038a0389},
-       {0x0000b03c, 0x038c038b},
-       {0x0000b040, 0x0390038d},
-       {0x0000b044, 0x03920391},
-       {0x0000b048, 0x03940393},
-       {0x0000b04c, 0x03960395},
-       {0x0000b050, 0x00000000},
-       {0x0000b054, 0x00000000},
-       {0x0000b058, 0x00000000},
-       {0x0000b05c, 0x00000000},
-       {0x0000b060, 0x00000000},
-       {0x0000b064, 0x00000000},
-       {0x0000b068, 0x00000000},
-       {0x0000b06c, 0x00000000},
-       {0x0000b070, 0x00000000},
-       {0x0000b074, 0x00000000},
-       {0x0000b078, 0x00000000},
-       {0x0000b07c, 0x00000000},
-       {0x0000b080, 0x2a2d2f32},
-       {0x0000b084, 0x21232328},
-       {0x0000b088, 0x19191c1e},
-       {0x0000b08c, 0x12141417},
-       {0x0000b090, 0x07070e0e},
-       {0x0000b094, 0x03030305},
-       {0x0000b098, 0x00000003},
-       {0x0000b09c, 0x00000000},
-       {0x0000b0a0, 0x00000000},
-       {0x0000b0a4, 0x00000000},
-       {0x0000b0a8, 0x00000000},
-       {0x0000b0ac, 0x00000000},
-       {0x0000b0b0, 0x00000000},
-       {0x0000b0b4, 0x00000000},
-       {0x0000b0b8, 0x00000000},
-       {0x0000b0bc, 0x00000000},
-       {0x0000b0c0, 0x003f0020},
-       {0x0000b0c4, 0x00400041},
-       {0x0000b0c8, 0x0140005f},
-       {0x0000b0cc, 0x0160015f},
-       {0x0000b0d0, 0x017e017f},
-       {0x0000b0d4, 0x02410242},
-       {0x0000b0d8, 0x025f0240},
-       {0x0000b0dc, 0x027f0260},
-       {0x0000b0e0, 0x0341027e},
-       {0x0000b0e4, 0x035f0340},
-       {0x0000b0e8, 0x037f0360},
-       {0x0000b0ec, 0x04400441},
-       {0x0000b0f0, 0x0460045f},
-       {0x0000b0f4, 0x0541047f},
-       {0x0000b0f8, 0x055f0540},
-       {0x0000b0fc, 0x057f0560},
-       {0x0000b100, 0x06400641},
-       {0x0000b104, 0x0660065f},
-       {0x0000b108, 0x067e067f},
-       {0x0000b10c, 0x07410742},
-       {0x0000b110, 0x075f0740},
-       {0x0000b114, 0x077f0760},
-       {0x0000b118, 0x07800781},
-       {0x0000b11c, 0x07a0079f},
-       {0x0000b120, 0x07c107bf},
-       {0x0000b124, 0x000007c0},
-       {0x0000b128, 0x00000000},
-       {0x0000b12c, 0x00000000},
-       {0x0000b130, 0x00000000},
-       {0x0000b134, 0x00000000},
-       {0x0000b138, 0x00000000},
-       {0x0000b13c, 0x00000000},
-       {0x0000b140, 0x003f0020},
-       {0x0000b144, 0x00400041},
-       {0x0000b148, 0x0140005f},
-       {0x0000b14c, 0x0160015f},
-       {0x0000b150, 0x017e017f},
-       {0x0000b154, 0x02410242},
-       {0x0000b158, 0x025f0240},
-       {0x0000b15c, 0x027f0260},
-       {0x0000b160, 0x0341027e},
-       {0x0000b164, 0x035f0340},
-       {0x0000b168, 0x037f0360},
-       {0x0000b16c, 0x04400441},
-       {0x0000b170, 0x0460045f},
-       {0x0000b174, 0x0541047f},
-       {0x0000b178, 0x055f0540},
-       {0x0000b17c, 0x057f0560},
-       {0x0000b180, 0x06400641},
-       {0x0000b184, 0x0660065f},
-       {0x0000b188, 0x067e067f},
-       {0x0000b18c, 0x07410742},
-       {0x0000b190, 0x075f0740},
-       {0x0000b194, 0x077f0760},
-       {0x0000b198, 0x07800781},
-       {0x0000b19c, 0x07a0079f},
-       {0x0000b1a0, 0x07c107bf},
-       {0x0000b1a4, 0x000007c0},
-       {0x0000b1a8, 0x00000000},
-       {0x0000b1ac, 0x00000000},
-       {0x0000b1b0, 0x00000000},
-       {0x0000b1b4, 0x00000000},
-       {0x0000b1b8, 0x00000000},
-       {0x0000b1bc, 0x00000000},
-       {0x0000b1c0, 0x00000000},
-       {0x0000b1c4, 0x00000000},
-       {0x0000b1c8, 0x00000000},
-       {0x0000b1cc, 0x00000000},
-       {0x0000b1d0, 0x00000000},
-       {0x0000b1d4, 0x00000000},
-       {0x0000b1d8, 0x00000000},
-       {0x0000b1dc, 0x00000000},
-       {0x0000b1e0, 0x00000000},
-       {0x0000b1e4, 0x00000000},
-       {0x0000b1e8, 0x00000000},
-       {0x0000b1ec, 0x00000000},
-       {0x0000b1f0, 0x00000396},
-       {0x0000b1f4, 0x00000396},
-       {0x0000b1f8, 0x00000396},
-       {0x0000b1fc, 0x00000196},
-};
-
-static const u32 ar9462_modes_high_ob_db_tx_gain_table_1p0[][5] = {
-       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-       {0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
-       {0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
-       {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
-       {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
-       {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
-       {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
-       {0x0000a504, 0x06002223, 0x06002223, 0x04000002, 0x04000002},
-       {0x0000a508, 0x0a022220, 0x0a022220, 0x08000004, 0x08000004},
-       {0x0000a50c, 0x0f022223, 0x0f022223, 0x0b000200, 0x0b000200},
-       {0x0000a510, 0x14022620, 0x14022620, 0x0f000202, 0x0f000202},
-       {0x0000a514, 0x18022622, 0x18022622, 0x11000400, 0x11000400},
-       {0x0000a518, 0x1b022822, 0x1b022822, 0x15000402, 0x15000402},
-       {0x0000a51c, 0x20022842, 0x20022842, 0x19000404, 0x19000404},
-       {0x0000a520, 0x22022c41, 0x22022c41, 0x1b000603, 0x1b000603},
-       {0x0000a524, 0x28023042, 0x28023042, 0x1f000a02, 0x1f000a02},
-       {0x0000a528, 0x2c023044, 0x2c023044, 0x23000a04, 0x23000a04},
-       {0x0000a52c, 0x2f023644, 0x2f023644, 0x26000a20, 0x26000a20},
-       {0x0000a530, 0x34025643, 0x34025643, 0x2a000e20, 0x2a000e20},
-       {0x0000a534, 0x38025a44, 0x38025a44, 0x2e000e22, 0x2e000e22},
-       {0x0000a538, 0x3b025e45, 0x3b025e45, 0x31000e24, 0x31000e24},
-       {0x0000a53c, 0x41025e4a, 0x41025e4a, 0x34001640, 0x34001640},
-       {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},
-       {0x0000a554, 0x62025f56, 0x62025f56, 0x48001ce3, 0x48001ce3},
-       {0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5},
-       {0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9},
-       {0x0000a560, 0x70049f56, 0x70049f56, 0x54001ceb, 0x54001ceb},
-       {0x0000a564, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-       {0x0000a568, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-       {0x0000a56c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-       {0x0000a570, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-       {0x0000a574, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-       {0x0000a578, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-       {0x0000a57c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-       {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000},
-       {0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000},
-       {0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501},
-       {0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501},
-       {0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03},
-       {0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04},
-       {0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04},
-       {0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-       {0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-       {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-       {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-       {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-       {0x0000b2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
-       {0x0000b2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
-       {0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
-       {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
-       {0x00016044, 0x056d82e4, 0x056d82e4, 0x056d82e4, 0x056d82e4},
-       {0x00016048, 0x8db49060, 0x8db49060, 0x8db49060, 0x8db49060},
-       {0x00016444, 0x056d82e4, 0x056d82e4, 0x056d82e4, 0x056d82e4},
-       {0x00016448, 0x8db49000, 0x8db49000, 0x8db49000, 0x8db49000},
-};
-
-static const u32 ar9462_common_wo_xlna_rx_gain_table_1p0[][2] = {
-       /* Addr      allmodes  */
-       {0x0000a000, 0x00010000},
-       {0x0000a004, 0x00030002},
-       {0x0000a008, 0x00050004},
-       {0x0000a00c, 0x00810080},
-       {0x0000a010, 0x00830082},
-       {0x0000a014, 0x01810180},
-       {0x0000a018, 0x01830182},
-       {0x0000a01c, 0x01850184},
-       {0x0000a020, 0x01890188},
-       {0x0000a024, 0x018b018a},
-       {0x0000a028, 0x018d018c},
-       {0x0000a02c, 0x03820190},
-       {0x0000a030, 0x03840383},
-       {0x0000a034, 0x03880385},
-       {0x0000a038, 0x038a0389},
-       {0x0000a03c, 0x038c038b},
-       {0x0000a040, 0x0390038d},
-       {0x0000a044, 0x03920391},
-       {0x0000a048, 0x03940393},
-       {0x0000a04c, 0x03960395},
-       {0x0000a050, 0x00000000},
-       {0x0000a054, 0x00000000},
-       {0x0000a058, 0x00000000},
-       {0x0000a05c, 0x00000000},
-       {0x0000a060, 0x00000000},
-       {0x0000a064, 0x00000000},
-       {0x0000a068, 0x00000000},
-       {0x0000a06c, 0x00000000},
-       {0x0000a070, 0x00000000},
-       {0x0000a074, 0x00000000},
-       {0x0000a078, 0x00000000},
-       {0x0000a07c, 0x00000000},
-       {0x0000a080, 0x29292929},
-       {0x0000a084, 0x29292929},
-       {0x0000a088, 0x29292929},
-       {0x0000a08c, 0x29292929},
-       {0x0000a090, 0x22292929},
-       {0x0000a094, 0x1d1d2222},
-       {0x0000a098, 0x0c111117},
-       {0x0000a09c, 0x00030303},
-       {0x0000a0a0, 0x00000000},
-       {0x0000a0a4, 0x00000000},
-       {0x0000a0a8, 0x00000000},
-       {0x0000a0ac, 0x00000000},
-       {0x0000a0b0, 0x00000000},
-       {0x0000a0b4, 0x00000000},
-       {0x0000a0b8, 0x00000000},
-       {0x0000a0bc, 0x00000000},
-       {0x0000a0c0, 0x001f0000},
-       {0x0000a0c4, 0x01000101},
-       {0x0000a0c8, 0x011e011f},
-       {0x0000a0cc, 0x011c011d},
-       {0x0000a0d0, 0x02030204},
-       {0x0000a0d4, 0x02010202},
-       {0x0000a0d8, 0x021f0200},
-       {0x0000a0dc, 0x0302021e},
-       {0x0000a0e0, 0x03000301},
-       {0x0000a0e4, 0x031e031f},
-       {0x0000a0e8, 0x0402031d},
-       {0x0000a0ec, 0x04000401},
-       {0x0000a0f0, 0x041e041f},
-       {0x0000a0f4, 0x0502041d},
-       {0x0000a0f8, 0x05000501},
-       {0x0000a0fc, 0x051e051f},
-       {0x0000a100, 0x06010602},
-       {0x0000a104, 0x061f0600},
-       {0x0000a108, 0x061d061e},
-       {0x0000a10c, 0x07020703},
-       {0x0000a110, 0x07000701},
-       {0x0000a114, 0x00000000},
-       {0x0000a118, 0x00000000},
-       {0x0000a11c, 0x00000000},
-       {0x0000a120, 0x00000000},
-       {0x0000a124, 0x00000000},
-       {0x0000a128, 0x00000000},
-       {0x0000a12c, 0x00000000},
-       {0x0000a130, 0x00000000},
-       {0x0000a134, 0x00000000},
-       {0x0000a138, 0x00000000},
-       {0x0000a13c, 0x00000000},
-       {0x0000a140, 0x001f0000},
-       {0x0000a144, 0x01000101},
-       {0x0000a148, 0x011e011f},
-       {0x0000a14c, 0x011c011d},
-       {0x0000a150, 0x02030204},
-       {0x0000a154, 0x02010202},
-       {0x0000a158, 0x021f0200},
-       {0x0000a15c, 0x0302021e},
-       {0x0000a160, 0x03000301},
-       {0x0000a164, 0x031e031f},
-       {0x0000a168, 0x0402031d},
-       {0x0000a16c, 0x04000401},
-       {0x0000a170, 0x041e041f},
-       {0x0000a174, 0x0502041d},
-       {0x0000a178, 0x05000501},
-       {0x0000a17c, 0x051e051f},
-       {0x0000a180, 0x06010602},
-       {0x0000a184, 0x061f0600},
-       {0x0000a188, 0x061d061e},
-       {0x0000a18c, 0x07020703},
-       {0x0000a190, 0x07000701},
-       {0x0000a194, 0x00000000},
-       {0x0000a198, 0x00000000},
-       {0x0000a19c, 0x00000000},
-       {0x0000a1a0, 0x00000000},
-       {0x0000a1a4, 0x00000000},
-       {0x0000a1a8, 0x00000000},
-       {0x0000a1ac, 0x00000000},
-       {0x0000a1b0, 0x00000000},
-       {0x0000a1b4, 0x00000000},
-       {0x0000a1b8, 0x00000000},
-       {0x0000a1bc, 0x00000000},
-       {0x0000a1c0, 0x00000000},
-       {0x0000a1c4, 0x00000000},
-       {0x0000a1c8, 0x00000000},
-       {0x0000a1cc, 0x00000000},
-       {0x0000a1d0, 0x00000000},
-       {0x0000a1d4, 0x00000000},
-       {0x0000a1d8, 0x00000000},
-       {0x0000a1dc, 0x00000000},
-       {0x0000a1e0, 0x00000000},
-       {0x0000a1e4, 0x00000000},
-       {0x0000a1e8, 0x00000000},
-       {0x0000a1ec, 0x00000000},
-       {0x0000a1f0, 0x00000396},
-       {0x0000a1f4, 0x00000396},
-       {0x0000a1f8, 0x00000396},
-       {0x0000a1fc, 0x00000196},
-       {0x0000b000, 0x00010000},
-       {0x0000b004, 0x00030002},
-       {0x0000b008, 0x00050004},
-       {0x0000b00c, 0x00810080},
-       {0x0000b010, 0x00830082},
-       {0x0000b014, 0x01810180},
-       {0x0000b018, 0x01830182},
-       {0x0000b01c, 0x01850184},
-       {0x0000b020, 0x02810280},
-       {0x0000b024, 0x02830282},
-       {0x0000b028, 0x02850284},
-       {0x0000b02c, 0x02890288},
-       {0x0000b030, 0x028b028a},
-       {0x0000b034, 0x0388028c},
-       {0x0000b038, 0x038a0389},
-       {0x0000b03c, 0x038c038b},
-       {0x0000b040, 0x0390038d},
-       {0x0000b044, 0x03920391},
-       {0x0000b048, 0x03940393},
-       {0x0000b04c, 0x03960395},
-       {0x0000b050, 0x00000000},
-       {0x0000b054, 0x00000000},
-       {0x0000b058, 0x00000000},
-       {0x0000b05c, 0x00000000},
-       {0x0000b060, 0x00000000},
-       {0x0000b064, 0x00000000},
-       {0x0000b068, 0x00000000},
-       {0x0000b06c, 0x00000000},
-       {0x0000b070, 0x00000000},
-       {0x0000b074, 0x00000000},
-       {0x0000b078, 0x00000000},
-       {0x0000b07c, 0x00000000},
-       {0x0000b080, 0x32323232},
-       {0x0000b084, 0x2f2f3232},
-       {0x0000b088, 0x23282a2d},
-       {0x0000b08c, 0x1c1e2123},
-       {0x0000b090, 0x14171919},
-       {0x0000b094, 0x0e0e1214},
-       {0x0000b098, 0x03050707},
-       {0x0000b09c, 0x00030303},
-       {0x0000b0a0, 0x00000000},
-       {0x0000b0a4, 0x00000000},
-       {0x0000b0a8, 0x00000000},
-       {0x0000b0ac, 0x00000000},
-       {0x0000b0b0, 0x00000000},
-       {0x0000b0b4, 0x00000000},
-       {0x0000b0b8, 0x00000000},
-       {0x0000b0bc, 0x00000000},
-       {0x0000b0c0, 0x003f0020},
-       {0x0000b0c4, 0x00400041},
-       {0x0000b0c8, 0x0140005f},
-       {0x0000b0cc, 0x0160015f},
-       {0x0000b0d0, 0x017e017f},
-       {0x0000b0d4, 0x02410242},
-       {0x0000b0d8, 0x025f0240},
-       {0x0000b0dc, 0x027f0260},
-       {0x0000b0e0, 0x0341027e},
-       {0x0000b0e4, 0x035f0340},
-       {0x0000b0e8, 0x037f0360},
-       {0x0000b0ec, 0x04400441},
-       {0x0000b0f0, 0x0460045f},
-       {0x0000b0f4, 0x0541047f},
-       {0x0000b0f8, 0x055f0540},
-       {0x0000b0fc, 0x057f0560},
-       {0x0000b100, 0x06400641},
-       {0x0000b104, 0x0660065f},
-       {0x0000b108, 0x067e067f},
-       {0x0000b10c, 0x07410742},
-       {0x0000b110, 0x075f0740},
-       {0x0000b114, 0x077f0760},
-       {0x0000b118, 0x07800781},
-       {0x0000b11c, 0x07a0079f},
-       {0x0000b120, 0x07c107bf},
-       {0x0000b124, 0x000007c0},
-       {0x0000b128, 0x00000000},
-       {0x0000b12c, 0x00000000},
-       {0x0000b130, 0x00000000},
-       {0x0000b134, 0x00000000},
-       {0x0000b138, 0x00000000},
-       {0x0000b13c, 0x00000000},
-       {0x0000b140, 0x003f0020},
-       {0x0000b144, 0x00400041},
-       {0x0000b148, 0x0140005f},
-       {0x0000b14c, 0x0160015f},
-       {0x0000b150, 0x017e017f},
-       {0x0000b154, 0x02410242},
-       {0x0000b158, 0x025f0240},
-       {0x0000b15c, 0x027f0260},
-       {0x0000b160, 0x0341027e},
-       {0x0000b164, 0x035f0340},
-       {0x0000b168, 0x037f0360},
-       {0x0000b16c, 0x04400441},
-       {0x0000b170, 0x0460045f},
-       {0x0000b174, 0x0541047f},
-       {0x0000b178, 0x055f0540},
-       {0x0000b17c, 0x057f0560},
-       {0x0000b180, 0x06400641},
-       {0x0000b184, 0x0660065f},
-       {0x0000b188, 0x067e067f},
-       {0x0000b18c, 0x07410742},
-       {0x0000b190, 0x075f0740},
-       {0x0000b194, 0x077f0760},
-       {0x0000b198, 0x07800781},
-       {0x0000b19c, 0x07a0079f},
-       {0x0000b1a0, 0x07c107bf},
-       {0x0000b1a4, 0x000007c0},
-       {0x0000b1a8, 0x00000000},
-       {0x0000b1ac, 0x00000000},
-       {0x0000b1b0, 0x00000000},
-       {0x0000b1b4, 0x00000000},
-       {0x0000b1b8, 0x00000000},
-       {0x0000b1bc, 0x00000000},
-       {0x0000b1c0, 0x00000000},
-       {0x0000b1c4, 0x00000000},
-       {0x0000b1c8, 0x00000000},
-       {0x0000b1cc, 0x00000000},
-       {0x0000b1d0, 0x00000000},
-       {0x0000b1d4, 0x00000000},
-       {0x0000b1d8, 0x00000000},
-       {0x0000b1dc, 0x00000000},
-       {0x0000b1e0, 0x00000000},
-       {0x0000b1e4, 0x00000000},
-       {0x0000b1e8, 0x00000000},
-       {0x0000b1ec, 0x00000000},
-       {0x0000b1f0, 0x00000396},
-       {0x0000b1f4, 0x00000396},
-       {0x0000b1f8, 0x00000396},
-       {0x0000b1fc, 0x00000196},
-};
-
-static const u32 ar9462_1p0_mac_postamble[][5] = {
-       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-       {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160},
-       {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c},
-       {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38},
-       {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00},
-       {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b},
-       {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810},
-       {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a},
-       {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440},
-};
-
-static const u32 ar9462_1p0_mac_postamble_emulation[][5] = {
-       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-       {0x00008014, 0x10f810f8, 0x10f810f8, 0x10f810f8, 0x10f810f8},
-       {0x0000801c, 0x0e8d8017, 0x0e8d8017, 0x0e8d8017, 0x0e8d8017},
-};
-
-static const u32 ar9462_1p0_tx_gain_table_baseband_postamble_emulation[][5] = {
-       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-       {0x0000a410, 0x000000d5, 0x000000d5, 0x000000d5, 0x000000d5},
-       {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a504, 0x00004002, 0x00004002, 0x00004002, 0x00004002},
-       {0x0000a508, 0x00008004, 0x00008004, 0x00008004, 0x00008004},
-       {0x0000a510, 0x0001000c, 0x0001000c, 0x0001000c, 0x0001000c},
-       {0x0000a514, 0x0001420b, 0x0001420b, 0x0001420b, 0x0001420b},
-       {0x0000a518, 0x0001824a, 0x0001824a, 0x0001824a, 0x0001824a},
-       {0x0000a51c, 0x0001c44a, 0x0001c44a, 0x0001c44a, 0x0001c44a},
-       {0x0000a520, 0x0002064a, 0x0002064a, 0x0002064a, 0x0002064a},
-       {0x0000a524, 0x0002484a, 0x0002484a, 0x0002484a, 0x0002484a},
-       {0x0000a528, 0x00028a4a, 0x00028a4a, 0x00028a4a, 0x00028a4a},
-       {0x0000a52c, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a},
-       {0x0000a530, 0x00030e4a, 0x00030e4a, 0x00030e4a, 0x00030e4a},
-       {0x0000a534, 0x00034e8a, 0x00034e8a, 0x00034e8a, 0x00034e8a},
-};
-
-static const u32 ar9462_1p0_radio_postamble[][5] = {
-       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-       {0x0001609c, 0x0b8ee524, 0x0b8ee524, 0x0b8ee524, 0x0b8ee524},
-       {0x000160ac, 0xa4646c08, 0xa4646c08, 0x24646c08, 0x24646c08},
-       {0x000160b0, 0x01d67f70, 0x01d67f70, 0x01d67f70, 0x01d67f70},
-       {0x0001610c, 0x48000000, 0x40000000, 0x40000000, 0x40000000},
-       {0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
-       {0x0001650c, 0x48000000, 0x40000000, 0x40000000, 0x40000000},
-       {0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
-};
-
-static const u32 ar9462_1p0_soc_postamble_emulation[][5] = {
-       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-       {0x00007010, 0x00001133, 0x00001133, 0x00001133, 0x00001133},
-};
-
-static const u32 ar9462_1p0_baseband_core[][2] = {
-       /* Addr      allmodes  */
-       {0x00009800, 0xafe68e30},
-       {0x00009804, 0xfd14e000},
-       {0x00009808, 0x9c0a9f6b},
-       {0x0000980c, 0x04900000},
-       {0x00009814, 0x9280c00a},
-       {0x00009818, 0x00000000},
-       {0x0000981c, 0x00020028},
-       {0x00009834, 0x6400a290},
-       {0x00009838, 0x0108ecff},
-       {0x0000983c, 0x0d000600},
-       {0x00009880, 0x201fff00},
-       {0x00009884, 0x00001042},
-       {0x000098a4, 0x00200400},
-       {0x000098b0, 0x32840bbe},
-       {0x000098d0, 0x004b6a8e},
-       {0x000098d4, 0x00000820},
-       {0x000098dc, 0x00000000},
-       {0x000098e4, 0x01ffffff},
-       {0x000098e8, 0x01ffffff},
-       {0x000098ec, 0x01ffffff},
-       {0x000098f0, 0x00000000},
-       {0x000098f4, 0x00000000},
-       {0x00009c04, 0xff55ff55},
-       {0x00009c08, 0x0320ff55},
-       {0x00009c0c, 0x00000000},
-       {0x00009c10, 0x00000000},
-       {0x00009c14, 0x00046384},
-       {0x00009c18, 0x05b6b440},
-       {0x00009c1c, 0x00b6b440},
-       {0x00009d00, 0xc080a333},
-       {0x00009d04, 0x40206c10},
-       {0x00009d08, 0x009c4060},
-       {0x00009d0c, 0x9883800a},
-       {0x00009d10, 0x01834061},
-       {0x00009d14, 0x00c0040b},
-       {0x00009d18, 0x00000000},
-       {0x00009e08, 0x0038230c},
-       {0x00009e24, 0x990bb514},
-       {0x00009e28, 0x0c6f0000},
-       {0x00009e30, 0x06336f77},
-       {0x00009e34, 0x6af6532f},
-       {0x00009e38, 0x0cc80c00},
-       {0x00009e40, 0x0d261820},
-       {0x00009e4c, 0x00001004},
-       {0x00009e50, 0x00ff03f1},
-       {0x00009e54, 0x64c355c7},
-       {0x00009e58, 0xfd897735},
-       {0x00009e5c, 0xe9198724},
-       {0x00009fc0, 0x803e4788},
-       {0x00009fc4, 0x0001efb5},
-       {0x00009fcc, 0x40000014},
-       {0x00009fd0, 0x01193b93},
-       {0x0000a20c, 0x00000000},
-       {0x0000a220, 0x00000000},
-       {0x0000a224, 0x00000000},
-       {0x0000a228, 0x10002310},
-       {0x0000a23c, 0x00000000},
-       {0x0000a244, 0x0c000000},
-       {0x0000a2a0, 0x00000001},
-       {0x0000a2c0, 0x00000001},
-       {0x0000a2c8, 0x00000000},
-       {0x0000a2cc, 0x18c43433},
-       {0x0000a2d4, 0x00000000},
-       {0x0000a2ec, 0x00000000},
-       {0x0000a2f0, 0x00000000},
-       {0x0000a2f4, 0x00000000},
-       {0x0000a2f8, 0x00000000},
-       {0x0000a344, 0x00000000},
-       {0x0000a34c, 0x00000000},
-       {0x0000a350, 0x0000a000},
-       {0x0000a364, 0x00000000},
-       {0x0000a370, 0x00000000},
-       {0x0000a390, 0x00000001},
-       {0x0000a394, 0x00000444},
-       {0x0000a398, 0x001f0e0f},
-       {0x0000a39c, 0x0075393f},
-       {0x0000a3a0, 0xb79f6427},
-       {0x0000a3a4, 0x00000000},
-       {0x0000a3a8, 0xaaaaaaaa},
-       {0x0000a3ac, 0x3c466478},
-       {0x0000a3c0, 0x20202020},
-       {0x0000a3c4, 0x22222220},
-       {0x0000a3c8, 0x20200020},
-       {0x0000a3cc, 0x20202020},
-       {0x0000a3d0, 0x20202020},
-       {0x0000a3d4, 0x20202020},
-       {0x0000a3d8, 0x20202020},
-       {0x0000a3dc, 0x20202020},
-       {0x0000a3e0, 0x20202020},
-       {0x0000a3e4, 0x20202020},
-       {0x0000a3e8, 0x20202020},
-       {0x0000a3ec, 0x20202020},
-       {0x0000a3f0, 0x00000000},
-       {0x0000a3f4, 0x00000006},
-       {0x0000a3f8, 0x0c9bd380},
-       {0x0000a3fc, 0x000f0f01},
-       {0x0000a400, 0x8fa91f01},
-       {0x0000a404, 0x00000000},
-       {0x0000a408, 0x0e79e5c6},
-       {0x0000a40c, 0x00820820},
-       {0x0000a414, 0x1ce739ce},
-       {0x0000a418, 0x2d001dce},
-       {0x0000a41c, 0x1ce739ce},
-       {0x0000a420, 0x000001ce},
-       {0x0000a424, 0x1ce739ce},
-       {0x0000a428, 0x000001ce},
-       {0x0000a42c, 0x1ce739ce},
-       {0x0000a430, 0x1ce739ce},
-       {0x0000a434, 0x00000000},
-       {0x0000a438, 0x00001801},
-       {0x0000a43c, 0x00100000},
-       {0x0000a440, 0x00000000},
-       {0x0000a444, 0x00000000},
-       {0x0000a448, 0x05000080},
-       {0x0000a44c, 0x00000001},
-       {0x0000a450, 0x00010000},
-       {0x0000a458, 0x00000000},
-       {0x0000a644, 0xbfad9d74},
-       {0x0000a648, 0x0048060a},
-       {0x0000a64c, 0x00003c37},
-       {0x0000a670, 0x03020100},
-       {0x0000a674, 0x09080504},
-       {0x0000a678, 0x0d0c0b0a},
-       {0x0000a67c, 0x13121110},
-       {0x0000a680, 0x31301514},
-       {0x0000a684, 0x35343332},
-       {0x0000a688, 0x00000036},
-       {0x0000a690, 0x00000838},
-       {0x0000a6b0, 0x0000000a},
-       {0x0000a6b4, 0x28f12c01},
-       {0x0000a7c0, 0x00000000},
-       {0x0000a7c4, 0xfffffffc},
-       {0x0000a7c8, 0x00000000},
-       {0x0000a7cc, 0x00000000},
-       {0x0000a7d0, 0x00000000},
-       {0x0000a7d4, 0x00000004},
-       {0x0000a7dc, 0x00000001},
-       {0x0000a8d0, 0x004b6a8e},
-       {0x0000a8d4, 0x00000820},
-       {0x0000a8dc, 0x00000000},
-       {0x0000a8f0, 0x00000000},
-       {0x0000a8f4, 0x00000000},
-       {0x0000b2d0, 0x00000080},
-       {0x0000b2d4, 0x00000000},
-       {0x0000b2ec, 0x00000000},
-       {0x0000b2f0, 0x00000000},
-       {0x0000b2f4, 0x00000000},
-       {0x0000b2f8, 0x00000000},
-       {0x0000b408, 0x0e79e5c0},
-       {0x0000b40c, 0x00820820},
-       {0x0000b420, 0x00000000},
-       {0x0000b6b0, 0x0000000a},
-       {0x0000b6b4, 0x00c00001},
-};
-
-static const u32 ar9462_1p0_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},
-       {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, 0x3379605e, 0x33795d5e},
-       {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
-       {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
-       {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
-       {0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c782},
-       {0x00009e44, 0x02321e27, 0x02321e27, 0x02291e27, 0x02291e27},
-       {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
-       {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
-       {0x0000a204, 0x0131b7c0, 0x0131b7c4, 0x0131b7c4, 0x0131b7c0},
-       {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
-       {0x0000a22c, 0x01026a2f, 0x01026a27, 0x01026a2f, 0x01026a2f},
-       {0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b},
-       {0x0000a234, 0x00000fff, 0x10000fff, 0x10000fff, 0x00000fff},
-       {0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018},
-       {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108},
-       {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898},
-       {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002},
-       {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e},
-       {0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501},
-       {0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
-       {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b},
-       {0x0000a284, 0x00000000, 0x00000000, 0x00000150, 0x00000150},
-       {0x0000a288, 0x00000110, 0x00000110, 0x00100110, 0x00100110},
-       {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222},
-       {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
-       {0x0000a2d0, 0x00041981, 0x00041981, 0x00041981, 0x00041982},
-       {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b},
-       {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
-       {0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x00100000},
-       {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
-       {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce},
-       {0x0000b284, 0x00000000, 0x00000000, 0x00000550, 0x00000550},
-};
-
-static const u32 ar9462_modes_fast_clock_1p0[][3] = {
-       /* Addr      5G_HT20     5G_HT40   */
-       {0x00001030, 0x00000268, 0x000004d0},
-       {0x00001070, 0x0000018c, 0x00000318},
-       {0x000010b0, 0x00000fd0, 0x00001fa0},
-       {0x00008014, 0x044c044c, 0x08980898},
-       {0x0000801c, 0x148ec02b, 0x148ec057},
-       {0x00008318, 0x000044c0, 0x00008980},
-       {0x00009e00, 0x0372131c, 0x0372131c},
-       {0x0000a230, 0x0000400b, 0x00004016},
-       {0x0000a254, 0x00000898, 0x00001130},
-};
-
-static const u32 ar9462_modes_low_ob_db_tx_gain_table_1p0[][5] = {
-       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-       {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
-       {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
-       {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
-       {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
-       {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
-       {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
-       {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
-       {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
-       {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202},
-       {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400},
-       {0x0000a518, 0x21020220, 0x21020220, 0x16000402, 0x16000402},
-       {0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404},
-       {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603},
-       {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02},
-       {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04},
-       {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20},
-       {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20},
-       {0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22},
-       {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24},
-       {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640},
-       {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660},
-       {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861},
-       {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81},
-       {0x0000a54c, 0x5c04286b, 0x5c04286b, 0x47001a83, 0x47001a83},
-       {0x0000a550, 0x61042a6c, 0x61042a6c, 0x4a001c84, 0x4a001c84},
-       {0x0000a554, 0x66062a6c, 0x66062a6c, 0x4e001ce3, 0x4e001ce3},
-       {0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x52001ce5, 0x52001ce5},
-       {0x0000a55c, 0x7006308c, 0x7006308c, 0x56001ce9, 0x56001ce9},
-       {0x0000a560, 0x730a308a, 0x730a308a, 0x5a001ceb, 0x5a001ceb},
-       {0x0000a564, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-       {0x0000a568, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-       {0x0000a56c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-       {0x0000a570, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-       {0x0000a574, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-       {0x0000a578, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-       {0x0000a57c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-       {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000},
-       {0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501},
-       {0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501},
-       {0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03},
-       {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04},
-       {0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04},
-       {0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005},
-       {0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
-       {0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
-       {0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
-       {0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
-       {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
-       {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
-       {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
-       {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
-       {0x00016044, 0x012482d4, 0x012482d4, 0x012482d4, 0x012482d4},
-       {0x00016048, 0x64992060, 0x64992060, 0x64992060, 0x64992060},
-       {0x00016444, 0x012482d4, 0x012482d4, 0x012482d4, 0x012482d4},
-       {0x00016448, 0x64992000, 0x64992000, 0x64992000, 0x64992000},
-};
-
-static const u32 ar9462_1p0_soc_postamble[][5] = {
-       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-       {0x00007010, 0x00002233, 0x00002233, 0x00002233, 0x00002233},
-};
-
-static const u32 ar9462_common_mixed_rx_gain_table_1p0[][2] = {
-       /* Addr      allmodes  */
-       {0x0000a000, 0x00010000},
-       {0x0000a004, 0x00030002},
-       {0x0000a008, 0x00050004},
-       {0x0000a00c, 0x00810080},
-       {0x0000a010, 0x00830082},
-       {0x0000a014, 0x01810180},
-       {0x0000a018, 0x01830182},
-       {0x0000a01c, 0x01850184},
-       {0x0000a020, 0x01890188},
-       {0x0000a024, 0x018b018a},
-       {0x0000a028, 0x018d018c},
-       {0x0000a02c, 0x03820190},
-       {0x0000a030, 0x03840383},
-       {0x0000a034, 0x03880385},
-       {0x0000a038, 0x038a0389},
-       {0x0000a03c, 0x038c038b},
-       {0x0000a040, 0x0390038d},
-       {0x0000a044, 0x03920391},
-       {0x0000a048, 0x03940393},
-       {0x0000a04c, 0x03960395},
-       {0x0000a050, 0x00000000},
-       {0x0000a054, 0x00000000},
-       {0x0000a058, 0x00000000},
-       {0x0000a05c, 0x00000000},
-       {0x0000a060, 0x00000000},
-       {0x0000a064, 0x00000000},
-       {0x0000a068, 0x00000000},
-       {0x0000a06c, 0x00000000},
-       {0x0000a070, 0x00000000},
-       {0x0000a074, 0x00000000},
-       {0x0000a078, 0x00000000},
-       {0x0000a07c, 0x00000000},
-       {0x0000a080, 0x29292929},
-       {0x0000a084, 0x29292929},
-       {0x0000a088, 0x29292929},
-       {0x0000a08c, 0x29292929},
-       {0x0000a090, 0x22292929},
-       {0x0000a094, 0x1d1d2222},
-       {0x0000a098, 0x0c111117},
-       {0x0000a09c, 0x00030303},
-       {0x0000a0a0, 0x00000000},
-       {0x0000a0a4, 0x00000000},
-       {0x0000a0a8, 0x00000000},
-       {0x0000a0ac, 0x00000000},
-       {0x0000a0b0, 0x00000000},
-       {0x0000a0b4, 0x00000000},
-       {0x0000a0b8, 0x00000000},
-       {0x0000a0bc, 0x00000000},
-       {0x0000a0c0, 0x001f0000},
-       {0x0000a0c4, 0x01000101},
-       {0x0000a0c8, 0x011e011f},
-       {0x0000a0cc, 0x011c011d},
-       {0x0000a0d0, 0x02030204},
-       {0x0000a0d4, 0x02010202},
-       {0x0000a0d8, 0x021f0200},
-       {0x0000a0dc, 0x0302021e},
-       {0x0000a0e0, 0x03000301},
-       {0x0000a0e4, 0x031e031f},
-       {0x0000a0e8, 0x0402031d},
-       {0x0000a0ec, 0x04000401},
-       {0x0000a0f0, 0x041e041f},
-       {0x0000a0f4, 0x0502041d},
-       {0x0000a0f8, 0x05000501},
-       {0x0000a0fc, 0x051e051f},
-       {0x0000a100, 0x06010602},
-       {0x0000a104, 0x061f0600},
-       {0x0000a108, 0x061d061e},
-       {0x0000a10c, 0x07020703},
-       {0x0000a110, 0x07000701},
-       {0x0000a114, 0x00000000},
-       {0x0000a118, 0x00000000},
-       {0x0000a11c, 0x00000000},
-       {0x0000a120, 0x00000000},
-       {0x0000a124, 0x00000000},
-       {0x0000a128, 0x00000000},
-       {0x0000a12c, 0x00000000},
-       {0x0000a130, 0x00000000},
-       {0x0000a134, 0x00000000},
-       {0x0000a138, 0x00000000},
-       {0x0000a13c, 0x00000000},
-       {0x0000a140, 0x001f0000},
-       {0x0000a144, 0x01000101},
-       {0x0000a148, 0x011e011f},
-       {0x0000a14c, 0x011c011d},
-       {0x0000a150, 0x02030204},
-       {0x0000a154, 0x02010202},
-       {0x0000a158, 0x021f0200},
-       {0x0000a15c, 0x0302021e},
-       {0x0000a160, 0x03000301},
-       {0x0000a164, 0x031e031f},
-       {0x0000a168, 0x0402031d},
-       {0x0000a16c, 0x04000401},
-       {0x0000a170, 0x041e041f},
-       {0x0000a174, 0x0502041d},
-       {0x0000a178, 0x05000501},
-       {0x0000a17c, 0x051e051f},
-       {0x0000a180, 0x06010602},
-       {0x0000a184, 0x061f0600},
-       {0x0000a188, 0x061d061e},
-       {0x0000a18c, 0x07020703},
-       {0x0000a190, 0x07000701},
-       {0x0000a194, 0x00000000},
-       {0x0000a198, 0x00000000},
-       {0x0000a19c, 0x00000000},
-       {0x0000a1a0, 0x00000000},
-       {0x0000a1a4, 0x00000000},
-       {0x0000a1a8, 0x00000000},
-       {0x0000a1ac, 0x00000000},
-       {0x0000a1b0, 0x00000000},
-       {0x0000a1b4, 0x00000000},
-       {0x0000a1b8, 0x00000000},
-       {0x0000a1bc, 0x00000000},
-       {0x0000a1c0, 0x00000000},
-       {0x0000a1c4, 0x00000000},
-       {0x0000a1c8, 0x00000000},
-       {0x0000a1cc, 0x00000000},
-       {0x0000a1d0, 0x00000000},
-       {0x0000a1d4, 0x00000000},
-       {0x0000a1d8, 0x00000000},
-       {0x0000a1dc, 0x00000000},
-       {0x0000a1e0, 0x00000000},
-       {0x0000a1e4, 0x00000000},
-       {0x0000a1e8, 0x00000000},
-       {0x0000a1ec, 0x00000000},
-       {0x0000a1f0, 0x00000396},
-       {0x0000a1f4, 0x00000396},
-       {0x0000a1f8, 0x00000396},
-       {0x0000a1fc, 0x00000196},
-       {0x0000b000, 0x00010000},
-       {0x0000b004, 0x00030002},
-       {0x0000b008, 0x00050004},
-       {0x0000b00c, 0x00810080},
-       {0x0000b010, 0x00830082},
-       {0x0000b014, 0x01810180},
-       {0x0000b018, 0x01830182},
-       {0x0000b01c, 0x01850184},
-       {0x0000b020, 0x02810280},
-       {0x0000b024, 0x02830282},
-       {0x0000b028, 0x02850284},
-       {0x0000b02c, 0x02890288},
-       {0x0000b030, 0x028b028a},
-       {0x0000b034, 0x0388028c},
-       {0x0000b038, 0x038a0389},
-       {0x0000b03c, 0x038c038b},
-       {0x0000b040, 0x0390038d},
-       {0x0000b044, 0x03920391},
-       {0x0000b048, 0x03940393},
-       {0x0000b04c, 0x03960395},
-       {0x0000b050, 0x00000000},
-       {0x0000b054, 0x00000000},
-       {0x0000b058, 0x00000000},
-       {0x0000b05c, 0x00000000},
-       {0x0000b060, 0x00000000},
-       {0x0000b064, 0x00000000},
-       {0x0000b068, 0x00000000},
-       {0x0000b06c, 0x00000000},
-       {0x0000b070, 0x00000000},
-       {0x0000b074, 0x00000000},
-       {0x0000b078, 0x00000000},
-       {0x0000b07c, 0x00000000},
-       {0x0000b080, 0x2a2d2f32},
-       {0x0000b084, 0x21232328},
-       {0x0000b088, 0x19191c1e},
-       {0x0000b08c, 0x12141417},
-       {0x0000b090, 0x07070e0e},
-       {0x0000b094, 0x03030305},
-       {0x0000b098, 0x00000003},
-       {0x0000b09c, 0x00000000},
-       {0x0000b0a0, 0x00000000},
-       {0x0000b0a4, 0x00000000},
-       {0x0000b0a8, 0x00000000},
-       {0x0000b0ac, 0x00000000},
-       {0x0000b0b0, 0x00000000},
-       {0x0000b0b4, 0x00000000},
-       {0x0000b0b8, 0x00000000},
-       {0x0000b0bc, 0x00000000},
-       {0x0000b0c0, 0x003f0020},
-       {0x0000b0c4, 0x00400041},
-       {0x0000b0c8, 0x0140005f},
-       {0x0000b0cc, 0x0160015f},
-       {0x0000b0d0, 0x017e017f},
-       {0x0000b0d4, 0x02410242},
-       {0x0000b0d8, 0x025f0240},
-       {0x0000b0dc, 0x027f0260},
-       {0x0000b0e0, 0x0341027e},
-       {0x0000b0e4, 0x035f0340},
-       {0x0000b0e8, 0x037f0360},
-       {0x0000b0ec, 0x04400441},
-       {0x0000b0f0, 0x0460045f},
-       {0x0000b0f4, 0x0541047f},
-       {0x0000b0f8, 0x055f0540},
-       {0x0000b0fc, 0x057f0560},
-       {0x0000b100, 0x06400641},
-       {0x0000b104, 0x0660065f},
-       {0x0000b108, 0x067e067f},
-       {0x0000b10c, 0x07410742},
-       {0x0000b110, 0x075f0740},
-       {0x0000b114, 0x077f0760},
-       {0x0000b118, 0x07800781},
-       {0x0000b11c, 0x07a0079f},
-       {0x0000b120, 0x07c107bf},
-       {0x0000b124, 0x000007c0},
-       {0x0000b128, 0x00000000},
-       {0x0000b12c, 0x00000000},
-       {0x0000b130, 0x00000000},
-       {0x0000b134, 0x00000000},
-       {0x0000b138, 0x00000000},
-       {0x0000b13c, 0x00000000},
-       {0x0000b140, 0x003f0020},
-       {0x0000b144, 0x00400041},
-       {0x0000b148, 0x0140005f},
-       {0x0000b14c, 0x0160015f},
-       {0x0000b150, 0x017e017f},
-       {0x0000b154, 0x02410242},
-       {0x0000b158, 0x025f0240},
-       {0x0000b15c, 0x027f0260},
-       {0x0000b160, 0x0341027e},
-       {0x0000b164, 0x035f0340},
-       {0x0000b168, 0x037f0360},
-       {0x0000b16c, 0x04400441},
-       {0x0000b170, 0x0460045f},
-       {0x0000b174, 0x0541047f},
-       {0x0000b178, 0x055f0540},
-       {0x0000b17c, 0x057f0560},
-       {0x0000b180, 0x06400641},
-       {0x0000b184, 0x0660065f},
-       {0x0000b188, 0x067e067f},
-       {0x0000b18c, 0x07410742},
-       {0x0000b190, 0x075f0740},
-       {0x0000b194, 0x077f0760},
-       {0x0000b198, 0x07800781},
-       {0x0000b19c, 0x07a0079f},
-       {0x0000b1a0, 0x07c107bf},
-       {0x0000b1a4, 0x000007c0},
-       {0x0000b1a8, 0x00000000},
-       {0x0000b1ac, 0x00000000},
-       {0x0000b1b0, 0x00000000},
-       {0x0000b1b4, 0x00000000},
-       {0x0000b1b8, 0x00000000},
-       {0x0000b1bc, 0x00000000},
-       {0x0000b1c0, 0x00000000},
-       {0x0000b1c4, 0x00000000},
-       {0x0000b1c8, 0x00000000},
-       {0x0000b1cc, 0x00000000},
-       {0x0000b1d0, 0x00000000},
-       {0x0000b1d4, 0x00000000},
-       {0x0000b1d8, 0x00000000},
-       {0x0000b1dc, 0x00000000},
-       {0x0000b1e0, 0x00000000},
-       {0x0000b1e4, 0x00000000},
-       {0x0000b1e8, 0x00000000},
-       {0x0000b1ec, 0x00000000},
-       {0x0000b1f0, 0x00000396},
-       {0x0000b1f4, 0x00000396},
-       {0x0000b1f8, 0x00000396},
-       {0x0000b1fc, 0x00000196},
-};
-
-static const u32 ar9462_pcie_phy_clkreq_disable_L1_1p0[][2] = {
-       /* Addr      allmodes  */
-       {0x00018c00, 0x10013e5e},
-       {0x00018c04, 0x000801d8},
-       {0x00018c08, 0x0000580c},
-};
-
-static const u32 ar9462_1p0_baseband_core_emulation[][2] = {
-       /* Addr      allmodes  */
-       {0x00009800, 0xafa68e30},
-       {0x00009884, 0x00002842},
-       {0x00009c04, 0xff55ff55},
-       {0x00009c08, 0x0320ff55},
-       {0x00009e50, 0x00000000},
-       {0x00009fcc, 0x00000014},
-       {0x0000a344, 0x00000010},
-       {0x0000a398, 0x00000000},
-       {0x0000a39c, 0x71733d01},
-       {0x0000a3a0, 0xd0ad5c12},
-       {0x0000a3c0, 0x22222220},
-       {0x0000a3c4, 0x22222222},
-       {0x0000a404, 0x00418a11},
-       {0x0000a418, 0x050001ce},
-       {0x0000a438, 0x00001800},
-       {0x0000a458, 0x01444452},
-       {0x0000a644, 0x3fad9d74},
-       {0x0000a690, 0x00000038},
-};
-
-static const u32 ar9462_1p0_radio_core[][2] = {
-       /* Addr      allmodes  */
-       {0x00016000, 0x36db6db6},
-       {0x00016004, 0x6db6db40},
-       {0x00016008, 0x73f00000},
-       {0x0001600c, 0x00000000},
-       {0x00016010, 0x6d820001},
-       {0x00016040, 0x7f80fff8},
-       {0x0001604c, 0x2699e04f},
-       {0x00016050, 0x6db6db6c},
-       {0x00016054, 0x6db60000},
-       {0x00016058, 0x6c200000},
-       {0x00016080, 0x00040000},
-       {0x00016084, 0x9a68048c},
-       {0x00016088, 0x54214514},
-       {0x0001608c, 0x12030409},
-       {0x00016090, 0x24926490},
-       {0x00016098, 0xd2888888},
-       {0x000160a0, 0x0a108ffe},
-       {0x000160a4, 0x812fc490},
-       {0x000160a8, 0x423c8000},
-       {0x000160b4, 0x92000000},
-       {0x000160b8, 0x0285dddc},
-       {0x000160bc, 0x02908888},
-       {0x000160c0, 0x00adb6d0},
-       {0x000160c4, 0x6db6db60},
-       {0x000160c8, 0x6db6db6c},
-       {0x000160cc, 0x0de6c1b0},
-       {0x00016100, 0x3fffbe04},
-       {0x00016104, 0xfff80000},
-       {0x00016108, 0x00200400},
-       {0x00016110, 0x00000000},
-       {0x00016144, 0x02084080},
-       {0x00016148, 0x000080c0},
-       {0x00016280, 0x050a0001},
-       {0x00016284, 0x3d841400},
-       {0x00016288, 0x00000000},
-       {0x0001628c, 0xe3000000},
-       {0x00016290, 0xa1005080},
-       {0x00016294, 0x00000020},
-       {0x00016298, 0x50a02900},
-       {0x00016340, 0x121e4276},
-       {0x00016344, 0x00300000},
-       {0x00016400, 0x36db6db6},
-       {0x00016404, 0x6db6db40},
-       {0x00016408, 0x73f00000},
-       {0x0001640c, 0x00000000},
-       {0x00016410, 0x6c800001},
-       {0x00016440, 0x7f80fff8},
-       {0x0001644c, 0x4699e04f},
-       {0x00016450, 0x6db6db6c},
-       {0x00016454, 0x6db60000},
-       {0x00016500, 0x3fffbe04},
-       {0x00016504, 0xfff80000},
-       {0x00016508, 0x00200400},
-       {0x00016510, 0x00000000},
-       {0x00016544, 0x02084080},
-       {0x00016548, 0x000080c0},
-};
-
-static const u32 ar9462_1p0_soc_preamble[][2] = {
-       /* Addr      allmodes  */
-       {0x00007020, 0x00000000},
-       {0x00007034, 0x00000002},
-       {0x00007038, 0x000004c2},
-};
-
-static const u32 ar9462_1p0_sys2ant[][2] = {
-       /* Addr      allmodes  */
-       {0x00063120, 0x00801980},
-};
-
-#endif /* INITVALS_9462_1P0_H */
index dc2054f0378ee46344d30607159214887bc3f89c..b6ba1e8149be5eaf85022eaecf662c9d016d452e 100644 (file)
@@ -98,14 +98,6 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = {
        {0x0000b284, 0x00000000, 0x00000000, 0x00000550, 0x00000550},
 };
 
-static const u32 ar9462_2p0_mac_core_emulation[][2] = {
-       /* Addr      allmodes  */
-       {0x00000030, 0x000e0085},
-       {0x00000044, 0x00000008},
-       {0x0000805c, 0xffffc7ff},
-       {0x00008344, 0xaa4a105b},
-};
-
 static const u32 ar9462_common_rx_gain_table_2p0[][2] = {
        /* Addr      allmodes  */
        {0x0000a000, 0x00010000},
@@ -380,349 +372,6 @@ static const u32 ar9462_pciephy_pll_on_clkreq_disable_L1_2p0[][2] = {
        {0x00018c08, 0x0003580c},
 };
 
-static const u32 ar9462_2p0_sys3ant[][2] = {
-       /* Addr      allmodes  */
-       {0x00063280, 0x00040807},
-       {0x00063284, 0x104ccccc},
-};
-
-static const u32 ar9462_common_rx_gain_table_ar9280_2p0[][2] = {
-       /* Addr      allmodes  */
-       {0x0000a000, 0x02000101},
-       {0x0000a004, 0x02000102},
-       {0x0000a008, 0x02000103},
-       {0x0000a00c, 0x02000104},
-       {0x0000a010, 0x02000200},
-       {0x0000a014, 0x02000201},
-       {0x0000a018, 0x02000202},
-       {0x0000a01c, 0x02000203},
-       {0x0000a020, 0x02000204},
-       {0x0000a024, 0x02000205},
-       {0x0000a028, 0x02000208},
-       {0x0000a02c, 0x02000302},
-       {0x0000a030, 0x02000303},
-       {0x0000a034, 0x02000304},
-       {0x0000a038, 0x02000400},
-       {0x0000a03c, 0x02010300},
-       {0x0000a040, 0x02010301},
-       {0x0000a044, 0x02010302},
-       {0x0000a048, 0x02000500},
-       {0x0000a04c, 0x02010400},
-       {0x0000a050, 0x02020300},
-       {0x0000a054, 0x02020301},
-       {0x0000a058, 0x02020302},
-       {0x0000a05c, 0x02020303},
-       {0x0000a060, 0x02020400},
-       {0x0000a064, 0x02030300},
-       {0x0000a068, 0x02030301},
-       {0x0000a06c, 0x02030302},
-       {0x0000a070, 0x02030303},
-       {0x0000a074, 0x02030400},
-       {0x0000a078, 0x02040300},
-       {0x0000a07c, 0x02040301},
-       {0x0000a080, 0x02040302},
-       {0x0000a084, 0x02040303},
-       {0x0000a088, 0x02030500},
-       {0x0000a08c, 0x02040400},
-       {0x0000a090, 0x02050203},
-       {0x0000a094, 0x02050204},
-       {0x0000a098, 0x02050205},
-       {0x0000a09c, 0x02040500},
-       {0x0000a0a0, 0x02050301},
-       {0x0000a0a4, 0x02050302},
-       {0x0000a0a8, 0x02050303},
-       {0x0000a0ac, 0x02050400},
-       {0x0000a0b0, 0x02050401},
-       {0x0000a0b4, 0x02050402},
-       {0x0000a0b8, 0x02050403},
-       {0x0000a0bc, 0x02050500},
-       {0x0000a0c0, 0x02050501},
-       {0x0000a0c4, 0x02050502},
-       {0x0000a0c8, 0x02050503},
-       {0x0000a0cc, 0x02050504},
-       {0x0000a0d0, 0x02050600},
-       {0x0000a0d4, 0x02050601},
-       {0x0000a0d8, 0x02050602},
-       {0x0000a0dc, 0x02050603},
-       {0x0000a0e0, 0x02050604},
-       {0x0000a0e4, 0x02050700},
-       {0x0000a0e8, 0x02050701},
-       {0x0000a0ec, 0x02050702},
-       {0x0000a0f0, 0x02050703},
-       {0x0000a0f4, 0x02050704},
-       {0x0000a0f8, 0x02050705},
-       {0x0000a0fc, 0x02050708},
-       {0x0000a100, 0x02050709},
-       {0x0000a104, 0x0205070a},
-       {0x0000a108, 0x0205070b},
-       {0x0000a10c, 0x0205070c},
-       {0x0000a110, 0x0205070d},
-       {0x0000a114, 0x02050710},
-       {0x0000a118, 0x02050711},
-       {0x0000a11c, 0x02050712},
-       {0x0000a120, 0x02050713},
-       {0x0000a124, 0x02050714},
-       {0x0000a128, 0x02050715},
-       {0x0000a12c, 0x02050730},
-       {0x0000a130, 0x02050731},
-       {0x0000a134, 0x02050732},
-       {0x0000a138, 0x02050733},
-       {0x0000a13c, 0x02050734},
-       {0x0000a140, 0x02050735},
-       {0x0000a144, 0x02050750},
-       {0x0000a148, 0x02050751},
-       {0x0000a14c, 0x02050752},
-       {0x0000a150, 0x02050753},
-       {0x0000a154, 0x02050754},
-       {0x0000a158, 0x02050755},
-       {0x0000a15c, 0x02050770},
-       {0x0000a160, 0x02050771},
-       {0x0000a164, 0x02050772},
-       {0x0000a168, 0x02050773},
-       {0x0000a16c, 0x02050774},
-       {0x0000a170, 0x02050775},
-       {0x0000a174, 0x00000776},
-       {0x0000a178, 0x00000776},
-       {0x0000a17c, 0x00000776},
-       {0x0000a180, 0x00000776},
-       {0x0000a184, 0x00000776},
-       {0x0000a188, 0x00000776},
-       {0x0000a18c, 0x00000776},
-       {0x0000a190, 0x00000776},
-       {0x0000a194, 0x00000776},
-       {0x0000a198, 0x00000776},
-       {0x0000a19c, 0x00000776},
-       {0x0000a1a0, 0x00000776},
-       {0x0000a1a4, 0x00000776},
-       {0x0000a1a8, 0x00000776},
-       {0x0000a1ac, 0x00000776},
-       {0x0000a1b0, 0x00000776},
-       {0x0000a1b4, 0x00000776},
-       {0x0000a1b8, 0x00000776},
-       {0x0000a1bc, 0x00000776},
-       {0x0000a1c0, 0x00000776},
-       {0x0000a1c4, 0x00000776},
-       {0x0000a1c8, 0x00000776},
-       {0x0000a1cc, 0x00000776},
-       {0x0000a1d0, 0x00000776},
-       {0x0000a1d4, 0x00000776},
-       {0x0000a1d8, 0x00000776},
-       {0x0000a1dc, 0x00000776},
-       {0x0000a1e0, 0x00000776},
-       {0x0000a1e4, 0x00000776},
-       {0x0000a1e8, 0x00000776},
-       {0x0000a1ec, 0x00000776},
-       {0x0000a1f0, 0x00000776},
-       {0x0000a1f4, 0x00000776},
-       {0x0000a1f8, 0x00000776},
-       {0x0000a1fc, 0x00000776},
-       {0x0000b000, 0x02000101},
-       {0x0000b004, 0x02000102},
-       {0x0000b008, 0x02000103},
-       {0x0000b00c, 0x02000104},
-       {0x0000b010, 0x02000200},
-       {0x0000b014, 0x02000201},
-       {0x0000b018, 0x02000202},
-       {0x0000b01c, 0x02000203},
-       {0x0000b020, 0x02000204},
-       {0x0000b024, 0x02000205},
-       {0x0000b028, 0x02000208},
-       {0x0000b02c, 0x02000302},
-       {0x0000b030, 0x02000303},
-       {0x0000b034, 0x02000304},
-       {0x0000b038, 0x02000400},
-       {0x0000b03c, 0x02010300},
-       {0x0000b040, 0x02010301},
-       {0x0000b044, 0x02010302},
-       {0x0000b048, 0x02000500},
-       {0x0000b04c, 0x02010400},
-       {0x0000b050, 0x02020300},
-       {0x0000b054, 0x02020301},
-       {0x0000b058, 0x02020302},
-       {0x0000b05c, 0x02020303},
-       {0x0000b060, 0x02020400},
-       {0x0000b064, 0x02030300},
-       {0x0000b068, 0x02030301},
-       {0x0000b06c, 0x02030302},
-       {0x0000b070, 0x02030303},
-       {0x0000b074, 0x02030400},
-       {0x0000b078, 0x02040300},
-       {0x0000b07c, 0x02040301},
-       {0x0000b080, 0x02040302},
-       {0x0000b084, 0x02040303},
-       {0x0000b088, 0x02030500},
-       {0x0000b08c, 0x02040400},
-       {0x0000b090, 0x02050203},
-       {0x0000b094, 0x02050204},
-       {0x0000b098, 0x02050205},
-       {0x0000b09c, 0x02040500},
-       {0x0000b0a0, 0x02050301},
-       {0x0000b0a4, 0x02050302},
-       {0x0000b0a8, 0x02050303},
-       {0x0000b0ac, 0x02050400},
-       {0x0000b0b0, 0x02050401},
-       {0x0000b0b4, 0x02050402},
-       {0x0000b0b8, 0x02050403},
-       {0x0000b0bc, 0x02050500},
-       {0x0000b0c0, 0x02050501},
-       {0x0000b0c4, 0x02050502},
-       {0x0000b0c8, 0x02050503},
-       {0x0000b0cc, 0x02050504},
-       {0x0000b0d0, 0x02050600},
-       {0x0000b0d4, 0x02050601},
-       {0x0000b0d8, 0x02050602},
-       {0x0000b0dc, 0x02050603},
-       {0x0000b0e0, 0x02050604},
-       {0x0000b0e4, 0x02050700},
-       {0x0000b0e8, 0x02050701},
-       {0x0000b0ec, 0x02050702},
-       {0x0000b0f0, 0x02050703},
-       {0x0000b0f4, 0x02050704},
-       {0x0000b0f8, 0x02050705},
-       {0x0000b0fc, 0x02050708},
-       {0x0000b100, 0x02050709},
-       {0x0000b104, 0x0205070a},
-       {0x0000b108, 0x0205070b},
-       {0x0000b10c, 0x0205070c},
-       {0x0000b110, 0x0205070d},
-       {0x0000b114, 0x02050710},
-       {0x0000b118, 0x02050711},
-       {0x0000b11c, 0x02050712},
-       {0x0000b120, 0x02050713},
-       {0x0000b124, 0x02050714},
-       {0x0000b128, 0x02050715},
-       {0x0000b12c, 0x02050730},
-       {0x0000b130, 0x02050731},
-       {0x0000b134, 0x02050732},
-       {0x0000b138, 0x02050733},
-       {0x0000b13c, 0x02050734},
-       {0x0000b140, 0x02050735},
-       {0x0000b144, 0x02050750},
-       {0x0000b148, 0x02050751},
-       {0x0000b14c, 0x02050752},
-       {0x0000b150, 0x02050753},
-       {0x0000b154, 0x02050754},
-       {0x0000b158, 0x02050755},
-       {0x0000b15c, 0x02050770},
-       {0x0000b160, 0x02050771},
-       {0x0000b164, 0x02050772},
-       {0x0000b168, 0x02050773},
-       {0x0000b16c, 0x02050774},
-       {0x0000b170, 0x02050775},
-       {0x0000b174, 0x00000776},
-       {0x0000b178, 0x00000776},
-       {0x0000b17c, 0x00000776},
-       {0x0000b180, 0x00000776},
-       {0x0000b184, 0x00000776},
-       {0x0000b188, 0x00000776},
-       {0x0000b18c, 0x00000776},
-       {0x0000b190, 0x00000776},
-       {0x0000b194, 0x00000776},
-       {0x0000b198, 0x00000776},
-       {0x0000b19c, 0x00000776},
-       {0x0000b1a0, 0x00000776},
-       {0x0000b1a4, 0x00000776},
-       {0x0000b1a8, 0x00000776},
-       {0x0000b1ac, 0x00000776},
-       {0x0000b1b0, 0x00000776},
-       {0x0000b1b4, 0x00000776},
-       {0x0000b1b8, 0x00000776},
-       {0x0000b1bc, 0x00000776},
-       {0x0000b1c0, 0x00000776},
-       {0x0000b1c4, 0x00000776},
-       {0x0000b1c8, 0x00000776},
-       {0x0000b1cc, 0x00000776},
-       {0x0000b1d0, 0x00000776},
-       {0x0000b1d4, 0x00000776},
-       {0x0000b1d8, 0x00000776},
-       {0x0000b1dc, 0x00000776},
-       {0x0000b1e0, 0x00000776},
-       {0x0000b1e4, 0x00000776},
-       {0x0000b1e8, 0x00000776},
-       {0x0000b1ec, 0x00000776},
-       {0x0000b1f0, 0x00000776},
-       {0x0000b1f4, 0x00000776},
-       {0x0000b1f8, 0x00000776},
-       {0x0000b1fc, 0x00000776},
-};
-
-static const u32 ar9200_ar9280_2p0_radio_core[][2] = {
-       /* Addr      allmodes  */
-       {0x00007800, 0x00040000},
-       {0x00007804, 0xdb005012},
-       {0x00007808, 0x04924914},
-       {0x0000780c, 0x21084210},
-       {0x00007810, 0x6d801300},
-       {0x00007814, 0x0019beff},
-       {0x00007818, 0x07e41000},
-       {0x0000781c, 0x00392000},
-       {0x00007820, 0x92592480},
-       {0x00007824, 0x00040000},
-       {0x00007828, 0xdb005012},
-       {0x0000782c, 0x04924914},
-       {0x00007830, 0x21084210},
-       {0x00007834, 0x6d801300},
-       {0x00007838, 0x0019beff},
-       {0x0000783c, 0x07e40000},
-       {0x00007840, 0x00392000},
-       {0x00007844, 0x92592480},
-       {0x00007848, 0x00100000},
-       {0x0000784c, 0x773f0567},
-       {0x00007850, 0x54214514},
-       {0x00007854, 0x12035828},
-       {0x00007858, 0x92592692},
-       {0x0000785c, 0x00000000},
-       {0x00007860, 0x56400000},
-       {0x00007864, 0x0a8e370e},
-       {0x00007868, 0xc0102850},
-       {0x0000786c, 0x812d4000},
-       {0x00007870, 0x807ec400},
-       {0x00007874, 0x001b6db0},
-       {0x00007878, 0x00376b63},
-       {0x0000787c, 0x06db6db6},
-       {0x00007880, 0x006d8000},
-       {0x00007884, 0xffeffffe},
-       {0x00007888, 0xffeffffe},
-       {0x0000788c, 0x00010000},
-       {0x00007890, 0x02060aeb},
-       {0x00007894, 0x5a108000},
-};
-
-static const u32 ar9462_2p0_mac_postamble_emulation[][5] = {
-       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-       {0x00008014, 0x10f810f8, 0x10f810f8, 0x10f810f8, 0x10f810f8},
-       {0x0000801c, 0x0e8d8017, 0x0e8d8017, 0x0e8d8017, 0x0e8d8017},
-};
-
-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, 0x50804008, 0x50804008},
-       {0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
-};
-
-static const u32 ar9462_2p0_baseband_postamble_emulation[][5] = {
-       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-       {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x00009e3c, 0xcf946221, 0xcf946221, 0xcf946221, 0xcf946221},
-       {0x00009e44, 0xfc5c0000, 0xfc5c0000, 0xfc5c0000, 0xfc5c0000},
-       {0x0000a258, 0x02020200, 0x02020200, 0x02020200, 0x02020200},
-       {0x0000a25c, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
-       {0x0000a28c, 0x00011111, 0x00011111, 0x00011111, 0x00011111},
-       {0x0000a2c4, 0x00148d18, 0x00148d18, 0x00148d20, 0x00148d20},
-       {0x0000a2d8, 0xf999a800, 0xf999a800, 0xf999a80c, 0xf999a80c},
-       {0x0000a50c, 0x0000c00a, 0x0000c00a, 0x0000c00a, 0x0000c00a},
-       {0x0000a538, 0x00038e8c, 0x00038e8c, 0x00038e8c, 0x00038e8c},
-       {0x0000a53c, 0x0003cecc, 0x0003cecc, 0x0003cecc, 0x0003cecc},
-       {0x0000a540, 0x00040ed4, 0x00040ed4, 0x00040ed4, 0x00040ed4},
-       {0x0000a544, 0x00044edc, 0x00044edc, 0x00044edc, 0x00044edc},
-       {0x0000a548, 0x00048ede, 0x00048ede, 0x00048ede, 0x00048ede},
-       {0x0000a54c, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e},
-       {0x0000a550, 0x00050f5e, 0x00050f5e, 0x00050f5e, 0x00050f5e},
-       {0x0000a554, 0x00054f9e, 0x00054f9e, 0x00054f9e, 0x00054f9e},
-       {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-};
-
 static const u32 ar9462_2p0_radio_postamble_sys2ant[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x000160ac, 0xa4646c08, 0xa4646c08, 0x24645808, 0x24645808},
@@ -1356,24 +1005,6 @@ static const u32 ar9462_2p0_radio_core[][2] = {
        {0x00016548, 0x000080c0},
 };
 
-static const u32 ar9462_2p0_tx_gain_table_baseband_postamble_emulation[][5] = {
-       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-       {0x0000a410, 0x000000d5, 0x000000d5, 0x000000d5, 0x000000d5},
-       {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a504, 0x00004002, 0x00004002, 0x00004002, 0x00004002},
-       {0x0000a508, 0x00008004, 0x00008004, 0x00008004, 0x00008004},
-       {0x0000a510, 0x0001000c, 0x0001000c, 0x0001000c, 0x0001000c},
-       {0x0000a514, 0x0001420b, 0x0001420b, 0x0001420b, 0x0001420b},
-       {0x0000a518, 0x0001824a, 0x0001824a, 0x0001824a, 0x0001824a},
-       {0x0000a51c, 0x0001c44a, 0x0001c44a, 0x0001c44a, 0x0001c44a},
-       {0x0000a520, 0x0002064a, 0x0002064a, 0x0002064a, 0x0002064a},
-       {0x0000a524, 0x0002484a, 0x0002484a, 0x0002484a, 0x0002484a},
-       {0x0000a528, 0x00028a4a, 0x00028a4a, 0x00028a4a, 0x00028a4a},
-       {0x0000a52c, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a},
-       {0x0000a530, 0x00030e4a, 0x00030e4a, 0x00030e4a, 0x00030e4a},
-       {0x0000a534, 0x00034e8a, 0x00034e8a, 0x00034e8a, 0x00034e8a},
-};
-
 static const u32 ar9462_2p0_soc_preamble[][2] = {
        /* Addr      allmodes  */
        {0x00007020, 0x00000000},
@@ -1381,11 +1012,6 @@ static const u32 ar9462_2p0_soc_preamble[][2] = {
        {0x00007038, 0x000004c2},
 };
 
-static const u32 ar9462_2p0_sys2ant[][2] = {
-       /* Addr      allmodes  */
-       {0x00063120, 0x00801980},
-};
-
 static const u32 ar9462_2p0_mac_core[][2] = {
        /* Addr      allmodes  */
        {0x00000008, 0x00000000},
@@ -1822,75 +1448,6 @@ static const u32 ar9462_common_mixed_rx_gain_table_2p0[][2] = {
        {0x0000b1fc, 0x00000196},
 };
 
-static const u32 ar9462_modes_green_ob_db_tx_gain_table_2p0[][5] = {
-       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-       {0x000098bc, 0x00000003, 0x00000003, 0x00000003, 0x00000003},
-       {0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
-       {0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
-       {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
-       {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
-       {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
-       {0x0000a458, 0x80000000, 0x80000000, 0x80000000, 0x80000000},
-       {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
-       {0x0000a504, 0x06002223, 0x06002223, 0x04000002, 0x04000002},
-       {0x0000a508, 0x0a022220, 0x0a022220, 0x08000004, 0x08000004},
-       {0x0000a50c, 0x0f022223, 0x0f022223, 0x0b000200, 0x0b000200},
-       {0x0000a510, 0x14022620, 0x14022620, 0x0f000202, 0x0f000202},
-       {0x0000a514, 0x18022622, 0x18022622, 0x11000400, 0x11000400},
-       {0x0000a518, 0x1b022822, 0x1b022822, 0x15000402, 0x15000402},
-       {0x0000a51c, 0x20022842, 0x20022842, 0x19000404, 0x19000404},
-       {0x0000a520, 0x22022c41, 0x22022c41, 0x1b000603, 0x1b000603},
-       {0x0000a524, 0x28023042, 0x28023042, 0x1f000a02, 0x1f000a02},
-       {0x0000a528, 0x2c023044, 0x2c023044, 0x23000a04, 0x23000a04},
-       {0x0000a52c, 0x2f023644, 0x2f023644, 0x26000a20, 0x26000a20},
-       {0x0000a530, 0x34025643, 0x34025643, 0x2a000e20, 0x2a000e20},
-       {0x0000a534, 0x38025a44, 0x38025a44, 0x2e000e22, 0x2e000e22},
-       {0x0000a538, 0x3b025e45, 0x3b025e45, 0x31000e24, 0x31000e24},
-       {0x0000a53c, 0x41025e4a, 0x41025e4a, 0x34001640, 0x34001640},
-       {0x0000a540, 0x48025e6c, 0x48025e6c, 0x38001660, 0x38001660},
-       {0x0000a544, 0x4e025e8e, 0x4e025e8e, 0x3b001861, 0x3b001861},
-       {0x0000a548, 0x53025eb2, 0x53025eb2, 0x3e001a81, 0x3e001a81},
-       {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},
-       {0x0000a560, 0x70049f56, 0x70049f56, 0x54001ceb, 0x54001ceb},
-       {0x0000a564, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-       {0x0000a568, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-       {0x0000a56c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-       {0x0000a570, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-       {0x0000a574, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-       {0x0000a578, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-       {0x0000a57c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-       {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000},
-       {0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000},
-       {0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501},
-       {0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501},
-       {0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03},
-       {0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04},
-       {0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04},
-       {0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-       {0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-       {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-       {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-       {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-       {0x0000b2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
-       {0x0000b2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
-       {0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
-       {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
-       {0x00016044, 0x056d82e4, 0x056d82e4, 0x056d82e4, 0x056d82e4},
-       {0x00016048, 0x8db49060, 0x8db49060, 0x8db49060, 0x8db49060},
-       {0x00016054, 0x6db60180, 0x6db60180, 0x6db60180, 0x6db60180},
-       {0x00016444, 0x056d82e4, 0x056d82e4, 0x056d82e4, 0x056d82e4},
-       {0x00016448, 0x8db49000, 0x8db49000, 0x8db49000, 0x8db49000},
-       {0x00016454, 0x6db60180, 0x6db60180, 0x6db60180, 0x6db60180},
-};
-
 static const u32 ar9462_2p0_BTCOEX_MAX_TXPWR_table[][2] = {
        /* Addr      allmodes  */
        {0x000018c0, 0x10101010},
@@ -1903,26 +1460,4 @@ static const u32 ar9462_2p0_BTCOEX_MAX_TXPWR_table[][2] = {
        {0x000018dc, 0x10101010},
 };
 
-static const u32 ar9462_2p0_baseband_core_emulation[][2] = {
-       /* Addr      allmodes  */
-       {0x00009800, 0xafa68e30},
-       {0x00009884, 0x00002842},
-       {0x00009c04, 0xff55ff55},
-       {0x00009c08, 0x0320ff55},
-       {0x00009e50, 0x00000000},
-       {0x00009fcc, 0x00000014},
-       {0x0000a344, 0x00000010},
-       {0x0000a398, 0x00000000},
-       {0x0000a39c, 0x71733d01},
-       {0x0000a3a0, 0xd0ad5c12},
-       {0x0000a3c0, 0x22222220},
-       {0x0000a3c4, 0x22222222},
-       {0x0000a404, 0x00418a11},
-       {0x0000a418, 0x050001ce},
-       {0x0000a438, 0x00001800},
-       {0x0000a458, 0x01444452},
-       {0x0000a644, 0x3fad9d74},
-       {0x0000a690, 0x00000038},
-};
-
 #endif /* INITVALS_9462_2P0_H */
index 171ccf7c972ff1cc228dca2019122ff6e79bdc0c..3d8e51cd5d8f1bbd9227fbf394433d3742193753 100644 (file)
@@ -299,7 +299,6 @@ struct ath_tx {
 
 struct ath_rx_edma {
        struct sk_buff_head rx_fifo;
-       struct sk_buff_head rx_buffers;
        u32 rx_fifo_hwsize;
 };
 
@@ -454,9 +453,39 @@ struct ath_btcoex {
        struct ath_mci_profile mci;
 };
 
-int ath_init_btcoex_timer(struct ath_softc *sc);
+#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
+int ath9k_init_btcoex(struct ath_softc *sc);
+void ath9k_deinit_btcoex(struct ath_softc *sc);
+void ath9k_start_btcoex(struct ath_softc *sc);
+void ath9k_stop_btcoex(struct ath_softc *sc);
 void ath9k_btcoex_timer_resume(struct ath_softc *sc);
 void ath9k_btcoex_timer_pause(struct ath_softc *sc);
+void ath9k_btcoex_handle_interrupt(struct ath_softc *sc, u32 status);
+u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen);
+#else
+static inline int ath9k_init_btcoex(struct ath_softc *sc)
+{
+       return 0;
+}
+static inline void ath9k_deinit_btcoex(struct ath_softc *sc)
+{
+}
+static inline void ath9k_start_btcoex(struct ath_softc *sc)
+{
+}
+static inline void ath9k_stop_btcoex(struct ath_softc *sc)
+{
+}
+static inline void ath9k_btcoex_handle_interrupt(struct ath_softc *sc,
+                                                u32 status)
+{
+}
+static inline u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc,
+                                         u32 max_4ms_framelen)
+{
+       return 0;
+}
+#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
 
 /********************/
 /*   LED Control    */
@@ -650,8 +679,11 @@ struct ath_softc {
        struct ath_beacon_config cur_beacon_conf;
        struct delayed_work tx_complete_work;
        struct delayed_work hw_pll_work;
+
+#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
        struct ath_btcoex btcoex;
        struct ath_mci_coex mci_coex;
+#endif
 
        struct ath_descdma txsdma;
 
index b8967e482e6ef952ea97317bac7d4f34322d4e7e..43882f9e25c46d02b9b70180e1258d15f35e5255 100644 (file)
@@ -91,7 +91,7 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
        info.txpower = MAX_RATE_POWER;
        info.keyix = ATH9K_TXKEYIX_INVALID;
        info.keytype = ATH9K_KEY_TYPE_CLEAR;
-       info.flags = ATH9K_TXDESC_NOACK;
+       info.flags = ATH9K_TXDESC_NOACK | ATH9K_TXDESC_INTREQ;
 
        info.buf_addr[0] = bf->bf_buf_addr;
        info.buf_len[0] = roundup(skb->len, 4);
@@ -355,7 +355,6 @@ void ath_beacon_tasklet(unsigned long data)
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath_buf *bf = NULL;
        struct ieee80211_vif *vif;
-       struct ath_tx_status ts;
        bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);
        int slot;
        u32 bfaddr, bc = 0;
@@ -462,11 +461,6 @@ void ath_beacon_tasklet(unsigned long data)
                        ath9k_hw_txstart(ah, sc->beacon.beaconq);
 
                sc->beacon.ast_be_xmit += bc;     /* XXX per-vif? */
-               if (edma) {
-                       spin_lock_bh(&sc->sc_pcu_lock);
-                       ath9k_hw_txprocdesc(ah, bf->bf_desc, (void *)&ts);
-                       spin_unlock_bh(&sc->sc_pcu_lock);
-               }
        }
 }
 
index a6712a95d76a24da330c4d628fc15455afce5536..ec32719934116e9252efeb840ae6925bf0819ac4 100644 (file)
@@ -68,9 +68,6 @@ void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum)
        u32 i, idx;
        bool rxclear_polarity = ath_bt_config.bt_rxclear_polarity;
 
-       if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE)
-               return;
-
        if (AR_SREV_9300_20_OR_LATER(ah))
                rxclear_polarity = !ath_bt_config.bt_rxclear_polarity;
 
@@ -98,12 +95,43 @@ void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum)
 }
 EXPORT_SYMBOL(ath9k_hw_init_btcoex_hw);
 
-void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah)
+void ath9k_hw_btcoex_init_scheme(struct ath_hw *ah)
 {
+       struct ath_common *common = ath9k_hw_common(ah);
        struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
 
-       if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE)
+       /*
+        * Check if BTCOEX is globally disabled.
+        */
+       if (!common->btcoex_enabled) {
+               btcoex_hw->scheme = ATH_BTCOEX_CFG_NONE;
                return;
+       }
+
+       if (AR_SREV_9462(ah)) {
+               btcoex_hw->scheme = ATH_BTCOEX_CFG_MCI;
+       } else if (AR_SREV_9300_20_OR_LATER(ah)) {
+               btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE;
+               btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9300;
+               btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9300;
+               btcoex_hw->btpriority_gpio = ATH_BTPRIORITY_GPIO_9300;
+       } else if (AR_SREV_9280_20_OR_LATER(ah)) {
+               btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9280;
+               btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9280;
+
+               if (AR_SREV_9285(ah)) {
+                       btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE;
+                       btcoex_hw->btpriority_gpio = ATH_BTPRIORITY_GPIO_9285;
+               } else {
+                       btcoex_hw->scheme = ATH_BTCOEX_CFG_2WIRE;
+               }
+       }
+}
+EXPORT_SYMBOL(ath9k_hw_btcoex_init_scheme);
+
+void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah)
+{
+       struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
 
        /* connect bt_active to baseband */
        REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL,
@@ -127,9 +155,6 @@ void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah)
 {
        struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
 
-       if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE)
-               return;
-
        /* btcoex 3-wire */
        REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
                        (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB |
@@ -152,13 +177,34 @@ void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah)
 }
 EXPORT_SYMBOL(ath9k_hw_btcoex_init_3wire);
 
+void ath9k_hw_btcoex_init_mci(struct ath_hw *ah)
+{
+       ah->btcoex_hw.mci.ready = false;
+       ah->btcoex_hw.mci.bt_state = 0;
+       ah->btcoex_hw.mci.bt_ver_major = 3;
+       ah->btcoex_hw.mci.bt_ver_minor = 0;
+       ah->btcoex_hw.mci.bt_version_known = false;
+       ah->btcoex_hw.mci.update_2g5g = true;
+       ah->btcoex_hw.mci.is_2g = true;
+       ah->btcoex_hw.mci.wlan_channels_update = false;
+       ah->btcoex_hw.mci.wlan_channels[0] = 0x00000000;
+       ah->btcoex_hw.mci.wlan_channels[1] = 0xffffffff;
+       ah->btcoex_hw.mci.wlan_channels[2] = 0xffffffff;
+       ah->btcoex_hw.mci.wlan_channels[3] = 0x7fffffff;
+       ah->btcoex_hw.mci.query_bt = true;
+       ah->btcoex_hw.mci.unhalt_bt_gpm = true;
+       ah->btcoex_hw.mci.halted_bt_gpm = false;
+       ah->btcoex_hw.mci.need_flush_btinfo = false;
+       ah->btcoex_hw.mci.wlan_cal_seq = 0;
+       ah->btcoex_hw.mci.wlan_cal_done = 0;
+       ah->btcoex_hw.mci.config = 0x2201;
+}
+EXPORT_SYMBOL(ath9k_hw_btcoex_init_mci);
+
 static void ath9k_hw_btcoex_enable_2wire(struct ath_hw *ah)
 {
        struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
 
-       if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE)
-               return;
-
        /* Configure the desired GPIO port for TX_FRAME output */
        ath9k_hw_cfg_output(ah, btcoex_hw->wlanactive_gpio,
                            AR_GPIO_OUTPUT_MUX_AS_TX_FRAME);
@@ -170,9 +216,6 @@ void ath9k_hw_btcoex_set_weight(struct ath_hw *ah,
 {
        struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
 
-       if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE)
-               return;
-
        btcoex_hw->bt_coex_weights = SM(bt_weight, AR_BTCOEX_BT_WGHT) |
                                     SM(wlan_weight, AR_BTCOEX_WL_WGHT);
 }
@@ -261,9 +304,6 @@ void ath9k_hw_btcoex_disable(struct ath_hw *ah)
        struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
        int i;
 
-       if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE)
-               return;
-
        btcoex_hw->enabled = false;
        if (btcoex_hw->scheme == ATH_BTCOEX_CFG_MCI) {
                ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE);
@@ -312,9 +352,6 @@ static void ar9003_btcoex_bt_stomp(struct ath_hw *ah,
 void ath9k_hw_btcoex_bt_stomp(struct ath_hw *ah,
                              enum ath_stomp_type stomp_type)
 {
-       if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE)
-               return;
-
        if (AR_SREV_9300_20_OR_LATER(ah)) {
                ar9003_btcoex_bt_stomp(ah, stomp_type);
                return;
index 278361c867ca265171e900d5635b62b9bdfbeede..8f93aef4414fabe2a5897c1e4f1e67df4746930b 100644 (file)
@@ -67,7 +67,6 @@ struct ath9k_hw_mci {
        u32 wlan_cal_done;
        u32 config;
        u8 *gpm_buf;
-       u8 *sched_buf;
        bool ready;
        bool update_2g5g;
        bool is_2g;
@@ -98,13 +97,14 @@ struct ath_btcoex_hw {
        u32 wlan_weight[AR9300_NUM_WLAN_WEIGHTS];
 };
 
+void ath9k_hw_btcoex_init_scheme(struct ath_hw *ah);
 void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah);
 void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah);
+void ath9k_hw_btcoex_init_mci(struct ath_hw *ah);
 void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum);
 void ath9k_hw_btcoex_set_weight(struct ath_hw *ah,
                                u32 bt_weight,
                                u32 wlan_weight);
-void ath9k_hw_btcoex_enable(struct ath_hw *ah);
 void ath9k_hw_btcoex_disable(struct ath_hw *ah);
 void ath9k_hw_btcoex_bt_stomp(struct ath_hw *ah,
                              enum ath_stomp_type stomp_type);
index 68d972bf232d20fbc431c291853288c4b20e7fd1..c2edf688da49497159a8962bcbb46a723e4e80c9 100644 (file)
@@ -451,109 +451,6 @@ static const struct file_operations fops_interrupt = {
        .llseek = default_llseek,
 };
 
-static const char *channel_type_str(enum nl80211_channel_type t)
-{
-       switch (t) {
-       case NL80211_CHAN_NO_HT:
-               return "no ht";
-       case NL80211_CHAN_HT20:
-               return "ht20";
-       case NL80211_CHAN_HT40MINUS:
-               return "ht40-";
-       case NL80211_CHAN_HT40PLUS:
-               return "ht40+";
-       default:
-               return "???";
-       }
-}
-
-static ssize_t read_file_wiphy(struct file *file, char __user *user_buf,
-                              size_t count, loff_t *ppos)
-{
-       struct ath_softc *sc = file->private_data;
-       struct ieee80211_channel *chan = sc->hw->conf.channel;
-       struct ieee80211_conf *conf = &(sc->hw->conf);
-       char buf[512];
-       unsigned int len = 0;
-       u8 addr[ETH_ALEN];
-       u32 tmp;
-
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "%s (chan=%d  center-freq: %d MHz  channel-type: %d (%s))\n",
-                       wiphy_name(sc->hw->wiphy),
-                       ieee80211_frequency_to_channel(chan->center_freq),
-                       chan->center_freq,
-                       conf->channel_type,
-                       channel_type_str(conf->channel_type));
-
-       ath9k_ps_wakeup(sc);
-       put_unaligned_le32(REG_READ_D(sc->sc_ah, AR_STA_ID0), addr);
-       put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_STA_ID1) & 0xffff, addr + 4);
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "addr: %pM\n", addr);
-       put_unaligned_le32(REG_READ_D(sc->sc_ah, AR_BSSMSKL), addr);
-       put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_BSSMSKU) & 0xffff, addr + 4);
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "addrmask: %pM\n", addr);
-       tmp = ath9k_hw_getrxfilter(sc->sc_ah);
-       ath9k_ps_restore(sc);
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "rfilt: 0x%x", tmp);
-       if (tmp & ATH9K_RX_FILTER_UCAST)
-               len += snprintf(buf + len, sizeof(buf) - len, " UCAST");
-       if (tmp & ATH9K_RX_FILTER_MCAST)
-               len += snprintf(buf + len, sizeof(buf) - len, " MCAST");
-       if (tmp & ATH9K_RX_FILTER_BCAST)
-               len += snprintf(buf + len, sizeof(buf) - len, " BCAST");
-       if (tmp & ATH9K_RX_FILTER_CONTROL)
-               len += snprintf(buf + len, sizeof(buf) - len, " CONTROL");
-       if (tmp & ATH9K_RX_FILTER_BEACON)
-               len += snprintf(buf + len, sizeof(buf) - len, " BEACON");
-       if (tmp & ATH9K_RX_FILTER_PROM)
-               len += snprintf(buf + len, sizeof(buf) - len, " PROM");
-       if (tmp & ATH9K_RX_FILTER_PROBEREQ)
-               len += snprintf(buf + len, sizeof(buf) - len, " PROBEREQ");
-       if (tmp & ATH9K_RX_FILTER_PHYERR)
-               len += snprintf(buf + len, sizeof(buf) - len, " PHYERR");
-       if (tmp & ATH9K_RX_FILTER_MYBEACON)
-               len += snprintf(buf + len, sizeof(buf) - len, " MYBEACON");
-       if (tmp & ATH9K_RX_FILTER_COMP_BAR)
-               len += snprintf(buf + len, sizeof(buf) - len, " COMP_BAR");
-       if (tmp & ATH9K_RX_FILTER_PSPOLL)
-               len += snprintf(buf + len, sizeof(buf) - len, " PSPOLL");
-       if (tmp & ATH9K_RX_FILTER_PHYRADAR)
-               len += snprintf(buf + len, sizeof(buf) - len, " PHYRADAR");
-       if (tmp & ATH9K_RX_FILTER_MCAST_BCAST_ALL)
-               len += snprintf(buf + len, sizeof(buf) - len, " MCAST_BCAST_ALL");
-
-       len += snprintf(buf + len, sizeof(buf) - len,
-                      "\n\nReset causes:\n"
-                      "  baseband hang: %d\n"
-                      "  baseband watchdog: %d\n"
-                      "  fatal hardware error interrupt: %d\n"
-                      "  tx hardware error: %d\n"
-                      "  tx path hang: %d\n"
-                      "  pll rx hang: %d\n",
-                      sc->debug.stats.reset[RESET_TYPE_BB_HANG],
-                      sc->debug.stats.reset[RESET_TYPE_BB_WATCHDOG],
-                      sc->debug.stats.reset[RESET_TYPE_FATAL_INT],
-                      sc->debug.stats.reset[RESET_TYPE_TX_ERROR],
-                      sc->debug.stats.reset[RESET_TYPE_TX_HANG],
-                      sc->debug.stats.reset[RESET_TYPE_PLL_HANG]);
-
-       if (len > sizeof(buf))
-               len = sizeof(buf);
-
-       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
-}
-
-static const struct file_operations fops_wiphy = {
-       .read = read_file_wiphy,
-       .open = ath9k_debugfs_open,
-       .owner = THIS_MODULE,
-       .llseek = default_llseek,
-};
-
 #define PR_QNUM(_n) sc->tx.txq_map[_n]->axq_qnum
 #define PR(str, elem)                                                  \
        do {                                                            \
@@ -763,87 +660,128 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf,
 {
        struct ath_softc *sc = file->private_data;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-       struct ath_hw *ah = sc->sc_ah;
        struct ieee80211_hw *hw = sc->hw;
-       char *buf;
-       unsigned int len = 0, size = 8000;
+       struct ath9k_vif_iter_data iter_data;
+       char buf[512];
+       unsigned int len = 0;
        ssize_t retval = 0;
        unsigned int reg;
-       struct ath9k_vif_iter_data iter_data;
+       u32 rxfilter;
 
-       ath9k_calculate_iter_data(hw, NULL, &iter_data);
-       
-       buf = kzalloc(size, GFP_KERNEL);
-       if (buf == NULL)
-               return -ENOMEM;
+       len += snprintf(buf + len, sizeof(buf) - len,
+                       "BSSID: %pM\n", common->curbssid);
+       len += snprintf(buf + len, sizeof(buf) - len,
+                       "BSSID-MASK: %pM\n", common->bssidmask);
+       len += snprintf(buf + len, sizeof(buf) - len,
+                       "OPMODE: %s\n", ath_opmode_to_string(sc->sc_ah->opmode));
 
        ath9k_ps_wakeup(sc);
-       len += snprintf(buf + len, size - len,
-                       "curbssid: %pM\n"
-                       "OP-Mode: %s(%i)\n"
-                       "Beacon-Timer-Register: 0x%x\n",
-                       common->curbssid,
-                       ath_opmode_to_string(sc->sc_ah->opmode),
-                       (int)(sc->sc_ah->opmode),
-                       REG_READ(ah, AR_BEACON_PERIOD));
-
-       reg = REG_READ(ah, AR_TIMER_MODE);
+       rxfilter = ath9k_hw_getrxfilter(sc->sc_ah);
        ath9k_ps_restore(sc);
-       len += snprintf(buf + len, size - len, "Timer-Mode-Register: 0x%x (",
-                       reg);
-       if (reg & AR_TBTT_TIMER_EN)
-               len += snprintf(buf + len, size - len, "TBTT ");
-       if (reg & AR_DBA_TIMER_EN)
-               len += snprintf(buf + len, size - len, "DBA ");
-       if (reg & AR_SWBA_TIMER_EN)
-               len += snprintf(buf + len, size - len, "SWBA ");
-       if (reg & AR_HCF_TIMER_EN)
-               len += snprintf(buf + len, size - len, "HCF ");
-       if (reg & AR_TIM_TIMER_EN)
-               len += snprintf(buf + len, size - len, "TIM ");
-       if (reg & AR_DTIM_TIMER_EN)
-               len += snprintf(buf + len, size - len, "DTIM ");
-       len += snprintf(buf + len, size - len, ")\n");
+
+       len += snprintf(buf + len, sizeof(buf) - len,
+                       "RXFILTER: 0x%x", rxfilter);
+
+       if (rxfilter & ATH9K_RX_FILTER_UCAST)
+               len += snprintf(buf + len, sizeof(buf) - len, " UCAST");
+       if (rxfilter & ATH9K_RX_FILTER_MCAST)
+               len += snprintf(buf + len, sizeof(buf) - len, " MCAST");
+       if (rxfilter & ATH9K_RX_FILTER_BCAST)
+               len += snprintf(buf + len, sizeof(buf) - len, " BCAST");
+       if (rxfilter & ATH9K_RX_FILTER_CONTROL)
+               len += snprintf(buf + len, sizeof(buf) - len, " CONTROL");
+       if (rxfilter & ATH9K_RX_FILTER_BEACON)
+               len += snprintf(buf + len, sizeof(buf) - len, " BEACON");
+       if (rxfilter & ATH9K_RX_FILTER_PROM)
+               len += snprintf(buf + len, sizeof(buf) - len, " PROM");
+       if (rxfilter & ATH9K_RX_FILTER_PROBEREQ)
+               len += snprintf(buf + len, sizeof(buf) - len, " PROBEREQ");
+       if (rxfilter & ATH9K_RX_FILTER_PHYERR)
+               len += snprintf(buf + len, sizeof(buf) - len, " PHYERR");
+       if (rxfilter & ATH9K_RX_FILTER_MYBEACON)
+               len += snprintf(buf + len, sizeof(buf) - len, " MYBEACON");
+       if (rxfilter & ATH9K_RX_FILTER_COMP_BAR)
+               len += snprintf(buf + len, sizeof(buf) - len, " COMP_BAR");
+       if (rxfilter & ATH9K_RX_FILTER_PSPOLL)
+               len += snprintf(buf + len, sizeof(buf) - len, " PSPOLL");
+       if (rxfilter & ATH9K_RX_FILTER_PHYRADAR)
+               len += snprintf(buf + len, sizeof(buf) - len, " PHYRADAR");
+       if (rxfilter & ATH9K_RX_FILTER_MCAST_BCAST_ALL)
+               len += snprintf(buf + len, sizeof(buf) - len, " MCAST_BCAST_ALL");
+       if (rxfilter & ATH9K_RX_FILTER_CONTROL_WRAPPER)
+               len += snprintf(buf + len, sizeof(buf) - len, " CONTROL_WRAPPER");
+
+       len += snprintf(buf + len, sizeof(buf) - len, "\n");
 
        reg = sc->sc_ah->imask;
-       len += snprintf(buf + len, size - len, "imask: 0x%x (", reg);
+
+       len += snprintf(buf + len, sizeof(buf) - len, "INTERRUPT-MASK: 0x%x", reg);
+
        if (reg & ATH9K_INT_SWBA)
-               len += snprintf(buf + len, size - len, "SWBA ");
+               len += snprintf(buf + len, sizeof(buf) - len, " SWBA");
        if (reg & ATH9K_INT_BMISS)
-               len += snprintf(buf + len, size - len, "BMISS ");
+               len += snprintf(buf + len, sizeof(buf) - len, " BMISS");
        if (reg & ATH9K_INT_CST)
-               len += snprintf(buf + len, size - len, "CST ");
+               len += snprintf(buf + len, sizeof(buf) - len, " CST");
        if (reg & ATH9K_INT_RX)
-               len += snprintf(buf + len, size - len, "RX ");
+               len += snprintf(buf + len, sizeof(buf) - len, " RX");
        if (reg & ATH9K_INT_RXHP)
-               len += snprintf(buf + len, size - len, "RXHP ");
+               len += snprintf(buf + len, sizeof(buf) - len, " RXHP");
        if (reg & ATH9K_INT_RXLP)
-               len += snprintf(buf + len, size - len, "RXLP ");
+               len += snprintf(buf + len, sizeof(buf) - len, " RXLP");
        if (reg & ATH9K_INT_BB_WATCHDOG)
-               len += snprintf(buf + len, size - len, "BB_WATCHDOG ");
-       /* there are other IRQs if one wanted to add them. */
-       len += snprintf(buf + len, size - len, ")\n");
+               len += snprintf(buf + len, sizeof(buf) - len, " BB_WATCHDOG");
 
-       len += snprintf(buf + len, size - len,
-                       "VIF Counts: AP: %i STA: %i MESH: %i WDS: %i"
-                       " ADHOC: %i OTHER: %i nvifs: %hi beacon-vifs: %hi\n",
+       len += snprintf(buf + len, sizeof(buf) - len, "\n");
+
+       ath9k_calculate_iter_data(hw, NULL, &iter_data);
+
+       len += snprintf(buf + len, sizeof(buf) - len,
+                       "VIF-COUNTS: AP: %i STA: %i MESH: %i WDS: %i"
+                       " ADHOC: %i OTHER: %i TOTAL: %hi BEACON-VIF: %hi\n",
                        iter_data.naps, iter_data.nstations, iter_data.nmeshes,
                        iter_data.nwds, iter_data.nadhocs, iter_data.nothers,
                        sc->nvifs, sc->nbcnvifs);
 
-       len += snprintf(buf + len, size - len,
-                       "Calculated-BSSID-Mask: %pM\n",
-                       iter_data.mask);
-
-       if (len > size)
-               len = size;
+       if (len > sizeof(buf))
+               len = sizeof(buf);
 
        retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
-       kfree(buf);
-
        return retval;
 }
 
+static ssize_t read_file_reset(struct file *file, char __user *user_buf,
+                              size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       char buf[512];
+       unsigned int len = 0;
+
+       len += snprintf(buf + len, sizeof(buf) - len,
+                       "%17s: %2d\n", "Baseband Hang",
+                       sc->debug.stats.reset[RESET_TYPE_BB_HANG]);
+       len += snprintf(buf + len, sizeof(buf) - len,
+                       "%17s: %2d\n", "Baseband Watchdog",
+                       sc->debug.stats.reset[RESET_TYPE_BB_WATCHDOG]);
+       len += snprintf(buf + len, sizeof(buf) - len,
+                       "%17s: %2d\n", "Fatal HW Error",
+                       sc->debug.stats.reset[RESET_TYPE_FATAL_INT]);
+       len += snprintf(buf + len, sizeof(buf) - len,
+                       "%17s: %2d\n", "TX HW error",
+                       sc->debug.stats.reset[RESET_TYPE_TX_ERROR]);
+       len += snprintf(buf + len, sizeof(buf) - len,
+                       "%17s: %2d\n", "TX Path Hang",
+                       sc->debug.stats.reset[RESET_TYPE_TX_HANG]);
+       len += snprintf(buf + len, sizeof(buf) - len,
+                       "%17s: %2d\n", "PLL RX Hang",
+                       sc->debug.stats.reset[RESET_TYPE_PLL_HANG]);
+
+       if (len > sizeof(buf))
+               len = sizeof(buf);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
 void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf,
                       struct ath_tx_status *ts, struct ath_txq *txq,
                       unsigned int flags)
@@ -880,6 +818,7 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf,
        if (ts->ts_flags & ATH9K_TX_DELIM_UNDERRUN)
                TX_STAT_INC(qnum, delim_underrun);
 
+#ifdef CONFIG_ATH9K_MAC_DEBUG
        spin_lock(&sc->debug.samp_lock);
        TX_SAMP_DBG(jiffies) = jiffies;
        TX_SAMP_DBG(rssi_ctl0) = ts->ts_rssi_ctl0;
@@ -906,6 +845,7 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf,
 
        sc->debug.tsidx = (sc->debug.tsidx + 1) % ATH_DBG_MAX_SAMPLES;
        spin_unlock(&sc->debug.samp_lock);
+#endif
 
 #undef TX_SAMP_DBG
 }
@@ -931,16 +871,23 @@ static const struct file_operations fops_misc = {
        .llseek = default_llseek,
 };
 
+static const struct file_operations fops_reset = {
+       .read = read_file_reset,
+       .open = ath9k_debugfs_open,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
 static ssize_t read_file_recv(struct file *file, char __user *user_buf,
                              size_t count, loff_t *ppos)
 {
 #define PHY_ERR(s, p) \
-       len += snprintf(buf + len, size - len, "%18s : %10u\n", s, \
+       len += snprintf(buf + len, size - len, "%22s : %10u\n", s, \
                        sc->debug.stats.rxstats.phy_err_stats[p]);
 
        struct ath_softc *sc = file->private_data;
        char *buf;
-       unsigned int len = 0, size = 1400;
+       unsigned int len = 0, size = 1600;
        ssize_t retval = 0;
 
        buf = kzalloc(size, GFP_KERNEL);
@@ -948,87 +895,59 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf,
                return -ENOMEM;
 
        len += snprintf(buf + len, size - len,
-                       "%18s : %10u\n", "CRC ERR",
+                       "%22s : %10u\n", "CRC ERR",
                        sc->debug.stats.rxstats.crc_err);
        len += snprintf(buf + len, size - len,
-                       "%18s : %10u\n", "DECRYPT CRC ERR",
+                       "%22s : %10u\n", "DECRYPT CRC ERR",
                        sc->debug.stats.rxstats.decrypt_crc_err);
        len += snprintf(buf + len, size - len,
-                       "%18s : %10u\n", "PHY ERR",
+                       "%22s : %10u\n", "PHY ERR",
                        sc->debug.stats.rxstats.phy_err);
        len += snprintf(buf + len, size - len,
-                       "%18s : %10u\n", "MIC ERR",
+                       "%22s : %10u\n", "MIC ERR",
                        sc->debug.stats.rxstats.mic_err);
        len += snprintf(buf + len, size - len,
-                       "%18s : %10u\n", "PRE-DELIM CRC ERR",
+                       "%22s : %10u\n", "PRE-DELIM CRC ERR",
                        sc->debug.stats.rxstats.pre_delim_crc_err);
        len += snprintf(buf + len, size - len,
-                       "%18s : %10u\n", "POST-DELIM CRC ERR",
+                       "%22s : %10u\n", "POST-DELIM CRC ERR",
                        sc->debug.stats.rxstats.post_delim_crc_err);
        len += snprintf(buf + len, size - len,
-                       "%18s : %10u\n", "DECRYPT BUSY ERR",
+                       "%22s : %10u\n", "DECRYPT BUSY ERR",
                        sc->debug.stats.rxstats.decrypt_busy_err);
 
-       len += snprintf(buf + len, size - len,
-                       "%18s : %10d\n", "RSSI-CTL0",
-                       sc->debug.stats.rxstats.rs_rssi_ctl0);
-
-       len += snprintf(buf + len, size - len,
-                       "%18s : %10d\n", "RSSI-CTL1",
-                       sc->debug.stats.rxstats.rs_rssi_ctl1);
-
-       len += snprintf(buf + len, size - len,
-                       "%18s : %10d\n", "RSSI-CTL2",
-                       sc->debug.stats.rxstats.rs_rssi_ctl2);
-
-       len += snprintf(buf + len, size - len,
-                       "%18s : %10d\n", "RSSI-EXT0",
-                       sc->debug.stats.rxstats.rs_rssi_ext0);
+       PHY_ERR("UNDERRUN ERR", ATH9K_PHYERR_UNDERRUN);
+       PHY_ERR("TIMING ERR", ATH9K_PHYERR_TIMING);
+       PHY_ERR("PARITY ERR", ATH9K_PHYERR_PARITY);
+       PHY_ERR("RATE ERR", ATH9K_PHYERR_RATE);
+       PHY_ERR("LENGTH ERR", ATH9K_PHYERR_LENGTH);
+       PHY_ERR("RADAR ERR", ATH9K_PHYERR_RADAR);
+       PHY_ERR("SERVICE ERR", ATH9K_PHYERR_SERVICE);
+       PHY_ERR("TOR ERR", ATH9K_PHYERR_TOR);
+       PHY_ERR("OFDM-TIMING ERR", ATH9K_PHYERR_OFDM_TIMING);
+       PHY_ERR("OFDM-SIGNAL-PARITY ERR", ATH9K_PHYERR_OFDM_SIGNAL_PARITY);
+       PHY_ERR("OFDM-RATE ERR", ATH9K_PHYERR_OFDM_RATE_ILLEGAL);
+       PHY_ERR("OFDM-LENGTH ERR", ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL);
+       PHY_ERR("OFDM-POWER-DROP ERR", ATH9K_PHYERR_OFDM_POWER_DROP);
+       PHY_ERR("OFDM-SERVICE ERR", ATH9K_PHYERR_OFDM_SERVICE);
+       PHY_ERR("OFDM-RESTART ERR", ATH9K_PHYERR_OFDM_RESTART);
+       PHY_ERR("FALSE-RADAR-EXT ERR", ATH9K_PHYERR_FALSE_RADAR_EXT);
+       PHY_ERR("CCK-TIMING ERR", ATH9K_PHYERR_CCK_TIMING);
+       PHY_ERR("CCK-HEADER-CRC ERR", ATH9K_PHYERR_CCK_HEADER_CRC);
+       PHY_ERR("CCK-RATE ERR", ATH9K_PHYERR_CCK_RATE_ILLEGAL);
+       PHY_ERR("CCK-SERVICE ERR", ATH9K_PHYERR_CCK_SERVICE);
+       PHY_ERR("CCK-RESTART ERR", ATH9K_PHYERR_CCK_RESTART);
+       PHY_ERR("CCK-LENGTH ERR", ATH9K_PHYERR_CCK_LENGTH_ILLEGAL);
+       PHY_ERR("CCK-POWER-DROP ERR", ATH9K_PHYERR_CCK_POWER_DROP);
+       PHY_ERR("HT-CRC ERR", ATH9K_PHYERR_HT_CRC_ERROR);
+       PHY_ERR("HT-LENGTH ERR", ATH9K_PHYERR_HT_LENGTH_ILLEGAL);
+       PHY_ERR("HT-RATE ERR", ATH9K_PHYERR_HT_RATE_ILLEGAL);
 
        len += snprintf(buf + len, size - len,
-                       "%18s : %10d\n", "RSSI-EXT1",
-                       sc->debug.stats.rxstats.rs_rssi_ext1);
-
-       len += snprintf(buf + len, size - len,
-                       "%18s : %10d\n", "RSSI-EXT2",
-                       sc->debug.stats.rxstats.rs_rssi_ext2);
-
-       len += snprintf(buf + len, size - len,
-                       "%18s : %10d\n", "Rx Antenna",
-                       sc->debug.stats.rxstats.rs_antenna);
-
-       PHY_ERR("UNDERRUN", ATH9K_PHYERR_UNDERRUN);
-       PHY_ERR("TIMING", ATH9K_PHYERR_TIMING);
-       PHY_ERR("PARITY", ATH9K_PHYERR_PARITY);
-       PHY_ERR("RATE", ATH9K_PHYERR_RATE);
-       PHY_ERR("LENGTH", ATH9K_PHYERR_LENGTH);
-       PHY_ERR("RADAR", ATH9K_PHYERR_RADAR);
-       PHY_ERR("SERVICE", ATH9K_PHYERR_SERVICE);
-       PHY_ERR("TOR", ATH9K_PHYERR_TOR);
-       PHY_ERR("OFDM-TIMING", ATH9K_PHYERR_OFDM_TIMING);
-       PHY_ERR("OFDM-SIGNAL-PARITY", ATH9K_PHYERR_OFDM_SIGNAL_PARITY);
-       PHY_ERR("OFDM-RATE", ATH9K_PHYERR_OFDM_RATE_ILLEGAL);
-       PHY_ERR("OFDM-LENGTH", ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL);
-       PHY_ERR("OFDM-POWER-DROP", ATH9K_PHYERR_OFDM_POWER_DROP);
-       PHY_ERR("OFDM-SERVICE", ATH9K_PHYERR_OFDM_SERVICE);
-       PHY_ERR("OFDM-RESTART", ATH9K_PHYERR_OFDM_RESTART);
-       PHY_ERR("FALSE-RADAR-EXT", ATH9K_PHYERR_FALSE_RADAR_EXT);
-       PHY_ERR("CCK-TIMING", ATH9K_PHYERR_CCK_TIMING);
-       PHY_ERR("CCK-HEADER-CRC", ATH9K_PHYERR_CCK_HEADER_CRC);
-       PHY_ERR("CCK-RATE", ATH9K_PHYERR_CCK_RATE_ILLEGAL);
-       PHY_ERR("CCK-SERVICE", ATH9K_PHYERR_CCK_SERVICE);
-       PHY_ERR("CCK-RESTART", ATH9K_PHYERR_CCK_RESTART);
-       PHY_ERR("CCK-LENGTH", ATH9K_PHYERR_CCK_LENGTH_ILLEGAL);
-       PHY_ERR("CCK-POWER-DROP", ATH9K_PHYERR_CCK_POWER_DROP);
-       PHY_ERR("HT-CRC", ATH9K_PHYERR_HT_CRC_ERROR);
-       PHY_ERR("HT-LENGTH", ATH9K_PHYERR_HT_LENGTH_ILLEGAL);
-       PHY_ERR("HT-RATE", ATH9K_PHYERR_HT_RATE_ILLEGAL);
-
-       len += snprintf(buf + len, size - len,
-                       "%18s : %10u\n", "RX-Pkts-All",
+                       "%22s : %10u\n", "RX-Pkts-All",
                        sc->debug.stats.rxstats.rx_pkts_all);
        len += snprintf(buf + len, size - len,
-                       "%18s : %10u\n", "RX-Bytes-All",
+                       "%22s : %10u\n", "RX-Bytes-All",
                        sc->debug.stats.rxstats.rx_bytes_all);
 
        if (len > size)
@@ -1049,8 +968,6 @@ void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs)
 #define RX_SAMP_DBG(c) (sc->debug.bb_mac_samp[sc->debug.sampidx].rs\
                        [sc->debug.rsidx].c)
 
-       u32 phyerr;
-
        RX_STAT_INC(rx_pkts_all);
        sc->debug.stats.rxstats.rx_bytes_all += rs->rs_datalen;
 
@@ -1069,20 +986,11 @@ void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs)
 
        if (rs->rs_status & ATH9K_RXERR_PHY) {
                RX_STAT_INC(phy_err);
-               phyerr = rs->rs_phyerr & 0x24;
-               RX_PHY_ERR_INC(phyerr);
+               if (rs->rs_phyerr < ATH9K_PHYERR_MAX)
+                       RX_PHY_ERR_INC(rs->rs_phyerr);
        }
 
-       sc->debug.stats.rxstats.rs_rssi_ctl0 = rs->rs_rssi_ctl0;
-       sc->debug.stats.rxstats.rs_rssi_ctl1 = rs->rs_rssi_ctl1;
-       sc->debug.stats.rxstats.rs_rssi_ctl2 = rs->rs_rssi_ctl2;
-
-       sc->debug.stats.rxstats.rs_rssi_ext0 = rs->rs_rssi_ext0;
-       sc->debug.stats.rxstats.rs_rssi_ext1 = rs->rs_rssi_ext1;
-       sc->debug.stats.rxstats.rs_rssi_ext2 = rs->rs_rssi_ext2;
-
-       sc->debug.stats.rxstats.rs_antenna = rs->rs_antenna;
-
+#ifdef CONFIG_ATH9K_MAC_DEBUG
        spin_lock(&sc->debug.samp_lock);
        RX_SAMP_DBG(jiffies) = jiffies;
        RX_SAMP_DBG(rssi_ctl0) = rs->rs_rssi_ctl0;
@@ -1099,6 +1007,8 @@ void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs)
        sc->debug.rsidx = (sc->debug.rsidx + 1) % ATH_DBG_MAX_SAMPLES;
        spin_unlock(&sc->debug.samp_lock);
 
+#endif
+
 #undef RX_STAT_INC
 #undef RX_PHY_ERR_INC
 #undef RX_SAMP_DBG
@@ -1342,6 +1252,8 @@ static const struct file_operations fops_modal_eeprom = {
        .llseek = default_llseek,
 };
 
+#ifdef CONFIG_ATH9K_MAC_DEBUG
+
 void ath9k_debug_samp_bb_mac(struct ath_softc *sc)
 {
 #define ATH_SAMP_DBG(c) (sc->debug.bb_mac_samp[sc->debug.sampidx].c)
@@ -1615,6 +1527,7 @@ static const struct file_operations fops_samps = {
        .llseek = default_llseek,
 };
 
+#endif
 
 int ath9k_init_debug(struct ath_hw *ah)
 {
@@ -1637,14 +1550,14 @@ int ath9k_init_debug(struct ath_hw *ah)
                            &fops_dma);
        debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy, sc,
                            &fops_interrupt);
-       debugfs_create_file("wiphy", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
-                           sc, &fops_wiphy);
        debugfs_create_file("xmit", S_IRUSR, sc->debug.debugfs_phy, sc,
                            &fops_xmit);
        debugfs_create_file("stations", S_IRUSR, sc->debug.debugfs_phy, sc,
                            &fops_stations);
        debugfs_create_file("misc", S_IRUSR, sc->debug.debugfs_phy, sc,
                            &fops_misc);
+       debugfs_create_file("reset", S_IRUSR, sc->debug.debugfs_phy, sc,
+                           &fops_reset);
        debugfs_create_file("recv", S_IRUSR, sc->debug.debugfs_phy, sc,
                            &fops_recv);
        debugfs_create_file("rx_chainmask", S_IRUSR | S_IWUSR,
@@ -1668,8 +1581,10 @@ int ath9k_init_debug(struct ath_hw *ah)
                            &fops_base_eeprom);
        debugfs_create_file("modal_eeprom", S_IRUSR, sc->debug.debugfs_phy, sc,
                            &fops_modal_eeprom);
+#ifdef CONFIG_ATH9K_MAC_DEBUG
        debugfs_create_file("samples", S_IRUSR, sc->debug.debugfs_phy, sc,
                            &fops_samps);
+#endif
 
        debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR,
                           sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask);
@@ -1677,10 +1592,5 @@ int ath9k_init_debug(struct ath_hw *ah)
        debugfs_create_u32("gpio_val", S_IRUSR | S_IWUSR,
                           sc->debug.debugfs_phy, &sc->sc_ah->gpio_val);
 
-       sc->debug.regidx = 0;
-       memset(&sc->debug.bb_mac_samp, 0, sizeof(sc->debug.bb_mac_samp));
-       sc->debug.sampidx = 0;
-       sc->debug.tsidx = 0;
-       sc->debug.rsidx = 0;
        return 0;
 }
index 776a24ada600fc377940851a4abbe7e3fa8a2001..64fcfad467bf44a38e325d2aed6a4bbee4adfc37 100644 (file)
@@ -165,13 +165,6 @@ struct ath_rx_stats {
        u32 post_delim_crc_err;
        u32 decrypt_busy_err;
        u32 phy_err_stats[ATH9K_PHYERR_MAX];
-       int8_t rs_rssi_ctl0;
-       int8_t rs_rssi_ctl1;
-       int8_t rs_rssi_ctl2;
-       int8_t rs_rssi_ext0;
-       int8_t rs_rssi_ext1;
-       int8_t rs_rssi_ext2;
-       u8 rs_antenna;
 };
 
 enum ath_reset_type {
@@ -235,16 +228,17 @@ struct ath9k_debug {
        struct dentry *debugfs_phy;
        u32 regidx;
        struct ath_stats stats;
+#ifdef CONFIG_ATH9K_MAC_DEBUG
        spinlock_t samp_lock;
        struct ath_dbg_bb_mac_samp bb_mac_samp[ATH_DBG_MAX_SAMPLES];
        u8 sampidx;
        u8 tsidx;
        u8 rsidx;
+#endif
 };
 
 int ath9k_init_debug(struct ath_hw *ah);
 
-void ath9k_debug_samp_bb_mac(struct ath_softc *sc);
 void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status);
 void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf,
                       struct ath_tx_status *ts, struct ath_txq *txq,
@@ -258,10 +252,6 @@ static inline int ath9k_init_debug(struct ath_hw *ah)
        return 0;
 }
 
-static inline void ath9k_debug_samp_bb_mac(struct ath_softc *sc)
-{
-}
-
 static inline void ath_debug_stat_interrupt(struct ath_softc *sc,
                                            enum ath9k_int status)
 {
@@ -282,4 +272,17 @@ static inline void ath_debug_stat_rx(struct ath_softc *sc,
 
 #endif /* CONFIG_ATH9K_DEBUGFS */
 
+#ifdef CONFIG_ATH9K_MAC_DEBUG
+
+void ath9k_debug_samp_bb_mac(struct ath_softc *sc);
+
+#else
+
+static inline void ath9k_debug_samp_bb_mac(struct ath_softc *sc)
+{
+}
+
+#endif
+
+
 #endif /* DEBUG_H */
index 597c84e31adb3b30a69ea7beb4f91b9890a2a662..63e4c4b1cb3d7a160c39a0d23224c0d472670d7a 100644 (file)
@@ -110,6 +110,8 @@ void ath_start_rfkill_poll(struct ath_softc *sc)
                wiphy_rfkill_start_polling(sc->hw->wiphy);
 }
 
+#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
+
 /******************/
 /*     BTCOEX     */
 /******************/
@@ -245,13 +247,10 @@ static void ath_btcoex_no_stomp_timer(void *arg)
        ath9k_ps_restore(sc);
 }
 
-int ath_init_btcoex_timer(struct ath_softc *sc)
+static int ath_init_btcoex_timer(struct ath_softc *sc)
 {
        struct ath_btcoex *btcoex = &sc->btcoex;
 
-       if (ath9k_hw_get_btcoex_scheme(sc->sc_ah) == ATH_BTCOEX_CFG_NONE)
-               return 0;
-
        btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000;
        btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) *
                btcoex->btcoex_period / 100;
@@ -284,9 +283,6 @@ void ath9k_btcoex_timer_resume(struct ath_softc *sc)
 
        ath_dbg(ath9k_hw_common(ah), BTCOEX, "Starting btcoex timers\n");
 
-       if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE)
-               return;
-
        /* make sure duty cycle timer is also stopped when resuming */
        if (btcoex->hw_timer_enabled)
                ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer);
@@ -307,9 +303,6 @@ void ath9k_btcoex_timer_pause(struct ath_softc *sc)
        struct ath_btcoex *btcoex = &sc->btcoex;
        struct ath_hw *ah = sc->sc_ah;
 
-       if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE)
-               return;
-
        del_timer_sync(&btcoex->period_timer);
 
        if (btcoex->hw_timer_enabled)
@@ -317,3 +310,113 @@ void ath9k_btcoex_timer_pause(struct ath_softc *sc)
 
        btcoex->hw_timer_enabled = false;
 }
+
+u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen)
+{
+       struct ath_mci_profile *mci = &sc->btcoex.mci;
+       u16 aggr_limit = 0;
+
+       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);
+
+       return aggr_limit;
+}
+
+void ath9k_btcoex_handle_interrupt(struct ath_softc *sc, u32 status)
+{
+       struct ath_hw *ah = sc->sc_ah;
+
+       if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE)
+               if (status & ATH9K_INT_GENTIMER)
+                       ath_gen_timer_isr(sc->sc_ah);
+
+       if (status & ATH9K_INT_MCI)
+               ath_mci_intr(sc);
+}
+
+void ath9k_start_btcoex(struct ath_softc *sc)
+{
+       struct ath_hw *ah = sc->sc_ah;
+
+       if ((ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) &&
+           !ah->btcoex_hw.enabled) {
+               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 (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE)
+                       ath9k_btcoex_timer_resume(sc);
+       }
+}
+
+void ath9k_stop_btcoex(struct ath_softc *sc)
+{
+       struct ath_hw *ah = sc->sc_ah;
+
+       if (ah->btcoex_hw.enabled &&
+           ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) {
+               ath9k_hw_btcoex_disable(ah);
+               if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE)
+                       ath9k_btcoex_timer_pause(sc);
+               ath_mci_flush_profile(&sc->btcoex.mci);
+       }
+}
+
+void ath9k_deinit_btcoex(struct ath_softc *sc)
+{
+        if ((sc->btcoex.no_stomp_timer) &&
+           ath9k_hw_get_btcoex_scheme(sc->sc_ah) == ATH_BTCOEX_CFG_3WIRE)
+               ath_gen_timer_free(sc->sc_ah, sc->btcoex.no_stomp_timer);
+
+       if (ath9k_hw_get_btcoex_scheme(sc->sc_ah) == ATH_BTCOEX_CFG_MCI)
+               ath_mci_cleanup(sc);
+}
+
+int ath9k_init_btcoex(struct ath_softc *sc)
+{
+       struct ath_txq *txq;
+       struct ath_hw *ah = sc->sc_ah;
+       int r;
+
+       ath9k_hw_btcoex_init_scheme(ah);
+
+       switch (ath9k_hw_get_btcoex_scheme(sc->sc_ah)) {
+       case ATH_BTCOEX_CFG_NONE:
+               break;
+       case ATH_BTCOEX_CFG_2WIRE:
+               ath9k_hw_btcoex_init_2wire(sc->sc_ah);
+               break;
+       case ATH_BTCOEX_CFG_3WIRE:
+               ath9k_hw_btcoex_init_3wire(sc->sc_ah);
+               r = ath_init_btcoex_timer(sc);
+               if (r)
+                       return -1;
+               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;
+               break;
+       case ATH_BTCOEX_CFG_MCI:
+               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);
+
+               r = ath_mci_setup(sc);
+               if (r)
+                       return r;
+
+               ath9k_hw_btcoex_init_mci(ah);
+
+               break;
+       default:
+               WARN_ON(1);
+               break;
+       }
+
+       return 0;
+}
+
+#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
index da5596766d8219791948a2f2ca26c719ec9ee7aa..135795257d95ab2a13ef684598a4ca3d57912470 100644 (file)
@@ -400,9 +400,21 @@ struct ath_btcoex {
        u32 btscan_no_stomp;
 };
 
-void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv);
-void ath_htc_resume_btcoex_work(struct ath9k_htc_priv *priv);
-void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv);
+#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
+void ath9k_htc_init_btcoex(struct ath9k_htc_priv *priv, char *product);
+void ath9k_htc_start_btcoex(struct ath9k_htc_priv *priv);
+void ath9k_htc_stop_btcoex(struct ath9k_htc_priv *priv);
+#else
+static inline void ath9k_htc_init_btcoex(struct ath9k_htc_priv *priv, char *product)
+{
+}
+static inline void ath9k_htc_start_btcoex(struct ath9k_htc_priv *priv)
+{
+}
+static inline void ath9k_htc_stop_btcoex(struct ath9k_htc_priv *priv)
+{
+}
+#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
 
 #define OP_INVALID                BIT(0)
 #define OP_SCANNING               BIT(1)
@@ -483,7 +495,10 @@ struct ath9k_htc_priv {
        int cabq;
        int hwq_map[WME_NUM_AC];
 
+#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
        struct ath_btcoex btcoex;
+#endif
+
        struct delayed_work coex_period_work;
        struct delayed_work duty_cycle_work;
 #ifdef CONFIG_ATH9K_HTC_DEBUGFS
index 6506e1fd503649ad42246b84c49c618b5b818ad9..1c10e2e5c237d2a8233b8a09ae056b0a909f7bb2 100644 (file)
 /*     BTCOEX     */
 /******************/
 
+#define ATH_HTC_BTCOEX_PRODUCT_ID "wb193"
+
+#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
+
 /*
  * Detects if there is any priority bt traffic
  */
@@ -111,13 +115,10 @@ static void ath_btcoex_duty_cycle_work(struct work_struct *work)
        ath9k_hw_btcoex_enable(priv->ah);
 }
 
-void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv)
+static void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv)
 {
        struct ath_btcoex *btcoex = &priv->btcoex;
 
-       if (ath9k_hw_get_btcoex_scheme(priv->ah) == ATH_BTCOEX_CFG_NONE)
-               return;
-
        btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD;
        btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) *
                btcoex->btcoex_period / 100;
@@ -131,14 +132,11 @@ void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv)
  * (Re)start btcoex work
  */
 
-void ath_htc_resume_btcoex_work(struct ath9k_htc_priv *priv)
+static void ath_htc_resume_btcoex_work(struct ath9k_htc_priv *priv)
 {
        struct ath_btcoex *btcoex = &priv->btcoex;
        struct ath_hw *ah = priv->ah;
 
-       if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE)
-               return;
-
        ath_dbg(ath9k_hw_common(ah), BTCOEX, "Starting btcoex work\n");
 
        btcoex->bt_priority_cnt = 0;
@@ -151,15 +149,66 @@ void ath_htc_resume_btcoex_work(struct ath9k_htc_priv *priv)
 /*
  * Cancel btcoex and bt duty cycle work.
  */
-void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv)
+static void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv)
 {
-       if (ath9k_hw_get_btcoex_scheme(priv->ah) == ATH_BTCOEX_CFG_NONE)
-               return;
-
        cancel_delayed_work_sync(&priv->coex_period_work);
        cancel_delayed_work_sync(&priv->duty_cycle_work);
 }
 
+void ath9k_htc_start_btcoex(struct ath9k_htc_priv *priv)
+{
+       struct ath_hw *ah = priv->ah;
+
+       if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE) {
+               ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
+                                          AR_STOMP_LOW_WLAN_WGHT);
+               ath9k_hw_btcoex_enable(ah);
+               ath_htc_resume_btcoex_work(priv);
+       }
+}
+
+void ath9k_htc_stop_btcoex(struct ath9k_htc_priv *priv)
+{
+       struct ath_hw *ah = priv->ah;
+
+       if (ah->btcoex_hw.enabled &&
+           ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) {
+               ath9k_hw_btcoex_disable(ah);
+               if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
+                       ath_htc_cancel_btcoex_work(priv);
+       }
+}
+
+void ath9k_htc_init_btcoex(struct ath9k_htc_priv *priv, char *product)
+{
+       struct ath_hw *ah = priv->ah;
+       int qnum;
+
+       if (product && strncmp(product, ATH_HTC_BTCOEX_PRODUCT_ID, 5) == 0) {
+               ah->btcoex_hw.scheme = ATH_BTCOEX_CFG_3WIRE;
+       }
+
+       switch (ath9k_hw_get_btcoex_scheme(priv->ah)) {
+       case ATH_BTCOEX_CFG_NONE:
+               break;
+       case ATH_BTCOEX_CFG_3WIRE:
+               priv->ah->btcoex_hw.btactive_gpio = 7;
+               priv->ah->btcoex_hw.btpriority_gpio = 6;
+               priv->ah->btcoex_hw.wlanactive_gpio = 8;
+               priv->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
+               ath9k_hw_btcoex_init_3wire(priv->ah);
+               ath_htc_init_btcoex_work(priv);
+               qnum = priv->hwq_map[WME_AC_BE];
+               ath9k_hw_init_btcoex_hw(priv->ah, qnum);
+               break;
+       default:
+               WARN_ON(1);
+               break;
+       }
+}
+
+#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
+
 /*******/
 /* LED */
 /*******/
index fc7519c933904ac5c800b755fcd867d3b34133de..de5ee15ee639f7964509c679580cadb2b3d95417 100644 (file)
@@ -41,8 +41,6 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption");
        .max_power = 20, \
 }
 
-#define ATH_HTC_BTCOEX_PRODUCT_ID "wb193"
-
 static struct ieee80211_channel ath9k_2ghz_channels[] = {
        CHAN2G(2412, 0), /* Channel 1 */
        CHAN2G(2417, 1), /* Channel 2 */
@@ -603,29 +601,6 @@ static void ath9k_init_misc(struct ath9k_htc_priv *priv)
        priv->ah->opmode = NL80211_IFTYPE_STATION;
 }
 
-static void ath9k_init_btcoex(struct ath9k_htc_priv *priv)
-{
-       int qnum;
-
-       switch (ath9k_hw_get_btcoex_scheme(priv->ah)) {
-       case ATH_BTCOEX_CFG_NONE:
-               break;
-       case ATH_BTCOEX_CFG_3WIRE:
-               priv->ah->btcoex_hw.btactive_gpio = 7;
-               priv->ah->btcoex_hw.btpriority_gpio = 6;
-               priv->ah->btcoex_hw.wlanactive_gpio = 8;
-               priv->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
-               ath9k_hw_btcoex_init_3wire(priv->ah);
-               ath_htc_init_btcoex_work(priv);
-               qnum = priv->hwq_map[WME_AC_BE];
-               ath9k_hw_init_btcoex_hw(priv->ah, qnum);
-               break;
-       default:
-               WARN_ON(1);
-               break;
-       }
-}
-
 static int ath9k_init_priv(struct ath9k_htc_priv *priv,
                           u16 devid, char *product,
                           u32 drv_info)
@@ -698,12 +673,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
        ath9k_cmn_init_crypto(ah);
        ath9k_init_channels_rates(priv);
        ath9k_init_misc(priv);
-
-       if (product && strncmp(product, ATH_HTC_BTCOEX_PRODUCT_ID, 5) == 0) {
-               ah->btcoex_hw.scheme = ATH_BTCOEX_CFG_3WIRE;
-               if (ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE)
-                       ath9k_init_btcoex(priv);
-       }
+       ath9k_htc_init_btcoex(priv, product);
 
        return 0;
 
index 06101b6bdeac97777813820e87e53c4e350737ce..2a29a7cdef18f34630098025a916314b7600d9af 100644 (file)
@@ -957,12 +957,8 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)
        mod_timer(&priv->tx.cleanup_timer,
                  jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL));
 
-       if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE) {
-               ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
-                                          AR_STOMP_LOW_WLAN_WGHT);
-               ath9k_hw_btcoex_enable(ah);
-               ath_htc_resume_btcoex_work(priv);
-       }
+       ath9k_htc_start_btcoex(priv);
+
        mutex_unlock(&priv->mutex);
 
        return ret;
@@ -1009,12 +1005,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
 
        mutex_lock(&priv->mutex);
 
-       if (ah->btcoex_hw.enabled &&
-           ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) {
-               ath9k_hw_btcoex_disable(ah);
-               if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
-                       ath_htc_cancel_btcoex_work(priv);
-       }
+       ath9k_htc_stop_btcoex(priv);
 
        /* Remove a monitor interface if it's present. */
        if (priv->ah->is_monitoring)
index d0d13d7cf3728ca4e342092099c6adf6cd31e282..2eb0ef315e315386d499ba702555be6bbdd32e55 100644 (file)
@@ -23,6 +23,7 @@
 #include "hw-ops.h"
 #include "rc.h"
 #include "ar9003_mac.h"
+#include "ar9003_mci.h"
 
 static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type);
 
@@ -1385,10 +1386,16 @@ static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type)
 static bool ath9k_hw_chip_reset(struct ath_hw *ah,
                                struct ath9k_channel *chan)
 {
-       if (AR_SREV_9280(ah) && ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)) {
-               if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON))
-                       return false;
-       } else if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM))
+       int reset_type = ATH9K_RESET_WARM;
+
+       if (AR_SREV_9280(ah)) {
+               if (ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL))
+                       reset_type = ATH9K_RESET_POWER_ON;
+               else
+                       reset_type = ATH9K_RESET_COLD;
+       }
+
+       if (!ath9k_hw_set_reset_reg(ah, reset_type))
                return false;
 
        if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
@@ -1518,61 +1525,22 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
                   struct ath9k_hw_cal_data *caldata, bool bChannelChange)
 {
        struct ath_common *common = ath9k_hw_common(ah);
-       struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
        u32 saveLedState;
        struct ath9k_channel *curchan = ah->curchan;
        u32 saveDefAntenna;
        u32 macStaId1;
        u64 tsf = 0;
        int i, r;
-       bool allow_fbs = false;
+       bool allow_fbs = false, start_mci_reset = false;
        bool mci = !!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI);
        bool save_fullsleep = ah->chip_fullsleep;
 
        if (mci) {
-
-               ar9003_mci_2g5g_changed(ah, IS_CHAN_2GHZ(chan));
-
-               if (mci_hw->bt_state == MCI_BT_CAL_START) {
-                       u32 payload[4] = {0, 0, 0, 0};
-
-                       ath_dbg(common, MCI, "MCI stop rx for BT CAL\n");
-
-                       mci_hw->bt_state = MCI_BT_CAL;
-
-                       /*
-                        * MCI FIX: disable mci interrupt here. This is to avoid
-                        * SW_MSG_DONE or RX_MSG bits to trigger MCI_INT and
-                        * lead to mci_intr reentry.
-                        */
-
-                       ar9003_mci_disable_interrupt(ah);
-
-                       ath_dbg(common, MCI, "send WLAN_CAL_GRANT\n");
-                       MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_GRANT);
-                       ar9003_mci_send_message(ah, MCI_GPM, 0, payload,
-                                               16, true, false);
-
-                       ath_dbg(common, MCI, "\nMCI BT is calibrating\n");
-
-                       /* Wait BT calibration to be completed for 25ms */
-
-                       if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_DONE,
-                                                                 0, 25000))
-                               ath_dbg(common, MCI,
-                                       "MCI got BT_CAL_DONE\n");
-                       else
-                               ath_dbg(common, MCI,
-                                       "MCI ### BT cal takes to long, force bt_state to be bt_awake\n");
-                       mci_hw->bt_state = MCI_BT_AWAKE;
-                       /* MCI FIX: enable mci interrupt here */
-                       ar9003_mci_enable_interrupt(ah);
-
-                       return true;
-               }
+               start_mci_reset = ar9003_mci_start_reset(ah, chan);
+               if (start_mci_reset)
+                       return 0;
        }
 
-
        if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
                return -EIO;
 
@@ -1609,7 +1577,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
                if (ath9k_hw_channel_change(ah, chan)) {
                        ath9k_hw_loadnf(ah, ah->curchan);
                        ath9k_hw_start_nfcal(ah, true);
-                       if (mci && mci_hw->ready)
+                       if (mci && ar9003_mci_is_ready(ah))
                                ar9003_mci_2g5g_switch(ah, true);
 
                        if (AR_SREV_9271(ah))
@@ -1618,19 +1586,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
                }
        }
 
-       if (mci) {
-               ar9003_mci_disable_interrupt(ah);
-
-               if (mci_hw->ready && !save_fullsleep) {
-                       ar9003_mci_mute_bt(ah);
-                       udelay(20);
-                       REG_WRITE(ah, AR_BTCOEX_CTRL, 0);
-               }
-
-               mci_hw->bt_state = MCI_BT_SLEEP;
-               mci_hw->ready = false;
-       }
-
+       if (mci)
+               ar9003_mci_stop_bt(ah, save_fullsleep);
 
        saveDefAntenna = REG_READ(ah, AR_DEF_ANTENNA);
        if (saveDefAntenna == 0)
@@ -1807,53 +1764,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        ath9k_hw_loadnf(ah, chan);
        ath9k_hw_start_nfcal(ah, true);
 
-       if (mci && mci_hw->ready) {
-
-               if (IS_CHAN_2GHZ(chan) &&
-                   (mci_hw->bt_state == MCI_BT_SLEEP)) {
-
-                       if (ar9003_mci_check_int(ah,
-                           AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET) ||
-                           ar9003_mci_check_int(ah,
-                           AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)) {
-
-                               /*
-                                * BT is sleeping. Check if BT wakes up during
-                                * WLAN calibration. If BT wakes up during
-                                * WLAN calibration, need to go through all
-                                * message exchanges again and recal.
-                                */
-
-                               ath_dbg(common, MCI,
-                                       "MCI BT wakes up during WLAN calibration\n");
-
-                               REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
-                                         AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET |
-                                         AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE);
-                               ath_dbg(common, MCI, "MCI send REMOTE_RESET\n");
-                               ar9003_mci_remote_reset(ah, true);
-                               ar9003_mci_send_sys_waking(ah, true);
-                               udelay(1);
-                               if (IS_CHAN_2GHZ(chan))
-                                       ar9003_mci_send_lna_transfer(ah, true);
-
-                               mci_hw->bt_state = MCI_BT_AWAKE;
-
-                               ath_dbg(common, MCI, "MCI re-cal\n");
-
-                               if (caldata) {
-                                       caldata->done_txiqcal_once = false;
-                                       caldata->done_txclcal_once = false;
-                                       caldata->rtt_hist.num_readings = 0;
-                               }
-
-                               if (!ath9k_hw_init_cal(ah, chan))
-                                       return -EIO;
-
-                       }
-               }
-               ar9003_mci_enable_interrupt(ah);
-       }
+       if (mci && ar9003_mci_end_reset(ah, chan, caldata))
+               return -EIO;
 
        ENABLE_REGWRITE_BUFFER(ah);
 
@@ -1894,24 +1806,11 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 #endif
        }
 
-       if (ah->btcoex_hw.enabled &&
-           ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE)
+       if (ath9k_hw_btcoex_is_enabled(ah))
                ath9k_hw_btcoex_enable(ah);
 
-       if (mci && mci_hw->ready) {
-               /*
-                * check BT state again to make
-                * sure it's not changed.
-                */
-
-               ar9003_mci_sync_bt_state(ah);
-               ar9003_mci_2g5g_switch(ah, true);
-
-               if ((mci_hw->bt_state == MCI_BT_AWAKE) &&
-                               (mci_hw->query_bt == true)) {
-                       mci_hw->need_flush_btinfo = true;
-               }
-       }
+       if (mci)
+               ar9003_mci_check_bt(ah);
 
        if (AR_SREV_9300_20_OR_LATER(ah)) {
                ar9003_hw_bb_watchdog_config(ah);
@@ -1962,8 +1861,7 @@ static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip)
                        REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF);
 
                /* Shutdown chip. Active low */
-               if (!AR_SREV_5416(ah) &&
-                               !AR_SREV_9271(ah) && !AR_SREV_9462_10(ah)) {
+               if (!AR_SREV_5416(ah) && !AR_SREV_9271(ah)) {
                        REG_CLR_BIT(ah, AR_RTC_RESET, AR_RTC_RESET_EN);
                        udelay(2);
                }
@@ -2076,7 +1974,6 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
 bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
 {
        struct ath_common *common = ath9k_hw_common(ah);
-       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
        int status = true, setChip = true;
        static const char *modes[] = {
                "AWAKE",
@@ -2100,20 +1997,8 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
 
                break;
        case ATH9K_PM_FULL_SLEEP:
-
-               if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI) {
-                       if (ar9003_mci_state(ah, MCI_STATE_ENABLE, NULL) &&
-                               (mci->bt_state != MCI_BT_SLEEP) &&
-                               !mci->halted_bt_gpm) {
-                               ath_dbg(common, MCI,
-                                       "MCI halt BT GPM (full_sleep)\n");
-                               ar9003_mci_send_coex_halt_bt_gpm(ah,
-                                                                true, true);
-                       }
-
-                       mci->ready = false;
-                       REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
-               }
+               if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
+                       ar9003_mci_set_full_sleep(ah);
 
                ath9k_set_power_sleep(ah, setChip);
                ah->chip_fullsleep = true;
@@ -2303,7 +2188,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
        struct ath9k_hw_capabilities *pCap = &ah->caps;
        struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
        struct ath_common *common = ath9k_hw_common(ah);
-       struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
        unsigned int chip_chainmask;
 
        u16 eeval;
@@ -2422,30 +2306,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
        else
                pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS;
 
-       if (common->btcoex_enabled) {
-               if (AR_SREV_9462(ah))
-                       btcoex_hw->scheme = ATH_BTCOEX_CFG_MCI;
-               else if (AR_SREV_9300_20_OR_LATER(ah)) {
-                       btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE;
-                       btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9300;
-                       btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9300;
-                       btcoex_hw->btpriority_gpio = ATH_BTPRIORITY_GPIO_9300;
-               } else if (AR_SREV_9280_20_OR_LATER(ah)) {
-                       btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9280;
-                       btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9280;
-
-                       if (AR_SREV_9285(ah)) {
-                               btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE;
-                               btcoex_hw->btpriority_gpio =
-                                               ATH_BTPRIORITY_GPIO_9285;
-                       } else {
-                               btcoex_hw->scheme = ATH_BTCOEX_CFG_2WIRE;
-                       }
-               }
-       } else {
-               btcoex_hw->scheme = ATH_BTCOEX_CFG_NONE;
-       }
-
        if (AR_SREV_9300_20_OR_LATER(ah)) {
                pCap->hw_caps |= ATH9K_HW_CAP_EDMA | ATH9K_HW_CAP_FASTCLOCK;
                if (!AR_SREV_9330(ah) && !AR_SREV_9485(ah))
index c8261d4fc780aa3b4db12586e2738a1065376604..1707137e0a30a20fd117ad2826daf3636c39c62b 100644 (file)
@@ -209,11 +209,7 @@ enum ath9k_hw_caps {
        ATH9K_HW_CAP_5GHZ                       = BIT(12),
        ATH9K_HW_CAP_APM                        = BIT(13),
        ATH9K_HW_CAP_RTT                        = BIT(14),
-#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
        ATH9K_HW_CAP_MCI                        = BIT(15),
-#else
-       ATH9K_HW_CAP_MCI                        = 0,
-#endif
        ATH9K_HW_CAP_DFS                        = BIT(16),
 };
 
@@ -432,161 +428,6 @@ enum ath9k_rx_qtype {
        ATH9K_RX_QUEUE_MAX,
 };
 
-enum mci_message_header {              /* length of payload */
-       MCI_LNA_CTRL     = 0x10,        /* len = 0 */
-       MCI_CONT_NACK    = 0x20,        /* len = 0 */
-       MCI_CONT_INFO    = 0x30,        /* len = 4 */
-       MCI_CONT_RST     = 0x40,        /* len = 0 */
-       MCI_SCHD_INFO    = 0x50,        /* len = 16 */
-       MCI_CPU_INT      = 0x60,        /* len = 4 */
-       MCI_SYS_WAKING   = 0x70,        /* len = 0 */
-       MCI_GPM          = 0x80,        /* len = 16 */
-       MCI_LNA_INFO     = 0x90,        /* len = 1 */
-       MCI_LNA_STATE    = 0x94,
-       MCI_LNA_TAKE     = 0x98,
-       MCI_LNA_TRANS    = 0x9c,
-       MCI_SYS_SLEEPING = 0xa0,        /* len = 0 */
-       MCI_REQ_WAKE     = 0xc0,        /* len = 0 */
-       MCI_DEBUG_16     = 0xfe,        /* len = 2 */
-       MCI_REMOTE_RESET = 0xff         /* len = 16 */
-};
-
-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
-};
-
-/* MCI GPM/Coex opcode/type definitions */
-enum {
-       MCI_GPM_COEX_W_GPM_PAYLOAD      = 1,
-       MCI_GPM_COEX_B_GPM_TYPE         = 4,
-       MCI_GPM_COEX_B_GPM_OPCODE       = 5,
-       /* MCI_GPM_WLAN_CAL_REQ, MCI_GPM_WLAN_CAL_DONE */
-       MCI_GPM_WLAN_CAL_W_SEQUENCE     = 2,
-
-       /* MCI_GPM_COEX_VERSION_QUERY */
-       /* MCI_GPM_COEX_VERSION_RESPONSE */
-       MCI_GPM_COEX_B_MAJOR_VERSION    = 6,
-       MCI_GPM_COEX_B_MINOR_VERSION    = 7,
-       /* MCI_GPM_COEX_STATUS_QUERY */
-       MCI_GPM_COEX_B_BT_BITMAP        = 6,
-       MCI_GPM_COEX_B_WLAN_BITMAP      = 7,
-       /* MCI_GPM_COEX_HALT_BT_GPM */
-       MCI_GPM_COEX_B_HALT_STATE       = 6,
-       /* MCI_GPM_COEX_WLAN_CHANNELS */
-       MCI_GPM_COEX_B_CHANNEL_MAP      = 6,
-       /* MCI_GPM_COEX_BT_PROFILE_INFO */
-       MCI_GPM_COEX_B_PROFILE_TYPE     = 6,
-       MCI_GPM_COEX_B_PROFILE_LINKID   = 7,
-       MCI_GPM_COEX_B_PROFILE_STATE    = 8,
-       MCI_GPM_COEX_B_PROFILE_ROLE     = 9,
-       MCI_GPM_COEX_B_PROFILE_RATE     = 10,
-       MCI_GPM_COEX_B_PROFILE_VOTYPE   = 11,
-       MCI_GPM_COEX_H_PROFILE_T        = 12,
-       MCI_GPM_COEX_B_PROFILE_W        = 14,
-       MCI_GPM_COEX_B_PROFILE_A        = 15,
-       /* MCI_GPM_COEX_BT_STATUS_UPDATE */
-       MCI_GPM_COEX_B_STATUS_TYPE      = 6,
-       MCI_GPM_COEX_B_STATUS_LINKID    = 7,
-       MCI_GPM_COEX_B_STATUS_STATE     = 8,
-       /* MCI_GPM_COEX_BT_UPDATE_FLAGS */
-       MCI_GPM_COEX_W_BT_FLAGS         = 6,
-       MCI_GPM_COEX_B_BT_FLAGS_OP      = 10
-};
-
-enum mci_gpm_subtype {
-       MCI_GPM_BT_CAL_REQ      = 0,
-       MCI_GPM_BT_CAL_GRANT    = 1,
-       MCI_GPM_BT_CAL_DONE     = 2,
-       MCI_GPM_WLAN_CAL_REQ    = 3,
-       MCI_GPM_WLAN_CAL_GRANT  = 4,
-       MCI_GPM_WLAN_CAL_DONE   = 5,
-       MCI_GPM_COEX_AGENT      = 0x0c,
-       MCI_GPM_RSVD_PATTERN    = 0xfe,
-       MCI_GPM_RSVD_PATTERN32  = 0xfefefefe,
-       MCI_GPM_BT_DEBUG        = 0xff
-};
-
-enum mci_bt_state {
-       MCI_BT_SLEEP,
-       MCI_BT_AWAKE,
-       MCI_BT_CAL_START,
-       MCI_BT_CAL
-};
-
-/* Type of state query */
-enum mci_state_type {
-       MCI_STATE_ENABLE,
-       MCI_STATE_INIT_GPM_OFFSET,
-       MCI_STATE_NEXT_GPM_OFFSET,
-       MCI_STATE_LAST_GPM_OFFSET,
-       MCI_STATE_BT,
-       MCI_STATE_SET_BT_SLEEP,
-       MCI_STATE_SET_BT_AWAKE,
-       MCI_STATE_SET_BT_CAL_START,
-       MCI_STATE_SET_BT_CAL,
-       MCI_STATE_LAST_SCHD_MSG_OFFSET,
-       MCI_STATE_REMOTE_SLEEP,
-       MCI_STATE_CONT_RSSI_POWER,
-       MCI_STATE_CONT_PRIORITY,
-       MCI_STATE_CONT_TXRX,
-       MCI_STATE_RESET_REQ_WAKE,
-       MCI_STATE_SEND_WLAN_COEX_VERSION,
-       MCI_STATE_SET_BT_COEX_VERSION,
-       MCI_STATE_SEND_WLAN_CHANNELS,
-       MCI_STATE_SEND_VERSION_QUERY,
-       MCI_STATE_SEND_STATUS_QUERY,
-       MCI_STATE_NEED_FLUSH_BT_INFO,
-       MCI_STATE_SET_CONCUR_TX_PRI,
-       MCI_STATE_RECOVER_RX,
-       MCI_STATE_NEED_FTP_STOMP,
-       MCI_STATE_NEED_TUNING,
-       MCI_STATE_DEBUG,
-       MCI_STATE_MAX
-};
-
-enum mci_gpm_coex_opcode {
-       MCI_GPM_COEX_VERSION_QUERY,
-       MCI_GPM_COEX_VERSION_RESPONSE,
-       MCI_GPM_COEX_STATUS_QUERY,
-       MCI_GPM_COEX_HALT_BT_GPM,
-       MCI_GPM_COEX_WLAN_CHANNELS,
-       MCI_GPM_COEX_BT_PROFILE_INFO,
-       MCI_GPM_COEX_BT_STATUS_UPDATE,
-       MCI_GPM_COEX_BT_UPDATE_FLAGS
-};
-
-#define MCI_GPM_NOMORE  0
-#define MCI_GPM_MORE    1
-#define MCI_GPM_INVALID 0xffffffff
-
-#define MCI_GPM_RECYCLE(_p_gpm)        do {                      \
-       *(((u32 *)_p_gpm) + MCI_GPM_COEX_W_GPM_PAYLOAD) = \
-                               MCI_GPM_RSVD_PATTERN32;   \
-} while (0)
-
-#define MCI_GPM_TYPE(_p_gpm)   \
-       (*(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_TYPE) & 0xff)
-
-#define MCI_GPM_OPCODE(_p_gpm) \
-       (*(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_OPCODE) & 0xff)
-
-#define MCI_GPM_SET_CAL_TYPE(_p_gpm, _cal_type)        do {                       \
-       *(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_TYPE) = (_cal_type) & 0xff;\
-} while (0)
-
-#define MCI_GPM_SET_TYPE_OPCODE(_p_gpm, _type, _opcode) do {              \
-       *(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_TYPE) = (_type) & 0xff;    \
-       *(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_OPCODE) = (_opcode) & 0xff;\
-} while (0)
-
-#define MCI_GPM_IS_CAL_TYPE(_type) ((_type) <= MCI_GPM_WLAN_CAL_DONE)
-
 struct ath9k_beacon_state {
        u32 bs_nexttbtt;
        u32 bs_nextdtim;
@@ -956,8 +797,9 @@ struct ath_hw {
        int firpwr[5];
        enum ath9k_ani_cmd ani_function;
 
-       /* Bluetooth coexistance */
+#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
        struct ath_btcoex_hw btcoex_hw;
+#endif
 
        u32 intr_txqs;
        u8 txchainmask;
@@ -1205,41 +1047,31 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning);
 void ath9k_hw_proc_mib_event(struct ath_hw *ah);
 void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan);
 
-bool ar9003_mci_send_message(struct ath_hw *ah, u8 header, u32 flag,
-                            u32 *payload, u8 len, bool wait_done,
-                            bool check_bt);
-void ar9003_mci_mute_bt(struct ath_hw *ah);
-u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data);
-void ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf,
-                     u16 len, u32 sched_addr);
-void ar9003_mci_cleanup(struct ath_hw *ah);
-void ar9003_mci_send_coex_halt_bt_gpm(struct ath_hw *ah, bool halt,
-                                     bool wait_done);
-u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type,
-                           u8 gpm_opcode, int time_out);
-void ar9003_mci_2g5g_changed(struct ath_hw *ah, bool is_2g);
-void ar9003_mci_disable_interrupt(struct ath_hw *ah);
-void ar9003_mci_enable_interrupt(struct ath_hw *ah);
-void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done);
-void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
-                     bool is_full_sleep);
-bool ar9003_mci_check_int(struct ath_hw *ah, u32 ints);
-void ar9003_mci_remote_reset(struct ath_hw *ah, bool wait_done);
-void ar9003_mci_send_sys_waking(struct ath_hw *ah, bool wait_done);
-void ar9003_mci_send_lna_transfer(struct ath_hw *ah, bool wait_done);
-void ar9003_mci_sync_bt_state(struct ath_hw *ah);
-void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr,
-                             u32 *rx_msg_intr);
-
 #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
+static inline bool ath9k_hw_btcoex_is_enabled(struct ath_hw *ah)
+{
+       return ah->btcoex_hw.enabled;
+}
+void ath9k_hw_btcoex_enable(struct ath_hw *ah);
 static inline enum ath_btcoex_scheme
 ath9k_hw_get_btcoex_scheme(struct ath_hw *ah)
 {
        return ah->btcoex_hw.scheme;
 }
 #else
-#define ath9k_hw_get_btcoex_scheme(...) ATH_BTCOEX_CFG_NONE
-#endif
+static inline bool ath9k_hw_btcoex_is_enabled(struct ath_hw *ah)
+{
+       return false;
+}
+static inline void ath9k_hw_btcoex_enable(struct ath_hw *ah)
+{
+}
+static inline enum ath_btcoex_scheme
+ath9k_hw_get_btcoex_scheme(struct ath_hw *ah)
+{
+       return ATH_BTCOEX_CFG_NONE;
+}
+#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
 
 #define ATH9K_CLOCK_RATE_CCK           22
 #define ATH9K_CLOCK_RATE_5GHZ_OFDM     40
index 53a005d288aa53949da6e1317c57e294a092a907..944e9b518f1935ba61111d1ca1d6c6aa8eb89b24 100644 (file)
@@ -419,66 +419,6 @@ fail:
        return error;
 }
 
-static int ath9k_init_btcoex(struct ath_softc *sc)
-{
-       struct ath_txq *txq;
-       struct ath_hw *ah = sc->sc_ah;
-       int r;
-
-       switch (ath9k_hw_get_btcoex_scheme(sc->sc_ah)) {
-       case ATH_BTCOEX_CFG_NONE:
-               break;
-       case ATH_BTCOEX_CFG_2WIRE:
-               ath9k_hw_btcoex_init_2wire(sc->sc_ah);
-               break;
-       case ATH_BTCOEX_CFG_3WIRE:
-               ath9k_hw_btcoex_init_3wire(sc->sc_ah);
-               r = ath_init_btcoex_timer(sc);
-               if (r)
-                       return -1;
-               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;
-               break;
-       case ATH_BTCOEX_CFG_MCI:
-               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);
-
-               r = ath_mci_setup(sc);
-               if (r)
-                       return r;
-
-               if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI) {
-                       ah->btcoex_hw.mci.ready = false;
-                       ah->btcoex_hw.mci.bt_state = 0;
-                       ah->btcoex_hw.mci.bt_ver_major = 3;
-                       ah->btcoex_hw.mci.bt_ver_minor = 0;
-                       ah->btcoex_hw.mci.bt_version_known = false;
-                       ah->btcoex_hw.mci.update_2g5g = true;
-                       ah->btcoex_hw.mci.is_2g = true;
-                       ah->btcoex_hw.mci.wlan_channels_update = false;
-                       ah->btcoex_hw.mci.wlan_channels[0] = 0x00000000;
-                       ah->btcoex_hw.mci.wlan_channels[1] = 0xffffffff;
-                       ah->btcoex_hw.mci.wlan_channels[2] = 0xffffffff;
-                       ah->btcoex_hw.mci.wlan_channels[3] = 0x7fffffff;
-                       ah->btcoex_hw.mci.query_bt = true;
-                       ah->btcoex_hw.mci.unhalt_bt_gpm = true;
-                       ah->btcoex_hw.mci.halted_bt_gpm = false;
-                       ah->btcoex_hw.mci.need_flush_btinfo = false;
-                       ah->btcoex_hw.mci.wlan_cal_seq = 0;
-                       ah->btcoex_hw.mci.wlan_cal_done = 0;
-                       ah->btcoex_hw.mci.config = 0x2201;
-               }
-               break;
-       default:
-               WARN_ON(1);
-               break;
-       }
-
-       return 0;
-}
-
 static int ath9k_init_queues(struct ath_softc *sc)
 {
        int i = 0;
@@ -615,8 +555,10 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
        mutex_init(&sc->mutex);
 #ifdef CONFIG_ATH9K_DEBUGFS
        spin_lock_init(&sc->nodes_lock);
-       spin_lock_init(&sc->debug.samp_lock);
        INIT_LIST_HEAD(&sc->nodes);
+#endif
+#ifdef CONFIG_ATH9K_MAC_DEBUG
+       spin_lock_init(&sc->debug.samp_lock);
 #endif
        tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
        tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet,
@@ -880,12 +822,7 @@ static void ath9k_deinit_softc(struct ath_softc *sc)
        if (sc->sbands[IEEE80211_BAND_5GHZ].channels)
                kfree(sc->sbands[IEEE80211_BAND_5GHZ].channels);
 
-        if ((sc->btcoex.no_stomp_timer) &&
-           ath9k_hw_get_btcoex_scheme(sc->sc_ah) == ATH_BTCOEX_CFG_3WIRE)
-               ath_gen_timer_free(sc->sc_ah, sc->btcoex.no_stomp_timer);
-
-       if (ath9k_hw_get_btcoex_scheme(sc->sc_ah) == ATH_BTCOEX_CFG_MCI)
-               ath_mci_cleanup(sc);
+       ath9k_deinit_btcoex(sc);
 
        for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
                if (ATH_TXQ_SETUP(sc, i))
index e196aba77acf568387d7a4b2b5852e316d801e4f..5f4ae6c9a93c69f4605bf7af447bc29e1c8cb583 100644 (file)
@@ -745,7 +745,11 @@ int ath9k_hw_beaconq_setup(struct ath_hw *ah)
        qi.tqi_aifs = 1;
        qi.tqi_cwmin = 0;
        qi.tqi_cwmax = 0;
-       /* NB: don't enable any interrupts */
+
+       if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
+               qi.tqi_qflags = TXQ_FLAG_TXOKINT_ENABLE |
+                               TXQ_FLAG_TXERRINT_ENABLE;
+
        return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi);
 }
 EXPORT_SYMBOL(ath9k_hw_beaconq_setup);
index ec82e926badc50ea65cd265d80f7b8317f53339b..cc2535c38beddd6a9adb2db9be3a2fe8683ec51c 100644 (file)
@@ -371,12 +371,8 @@ static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
        if (sc->sc_flags & SC_OP_INVALID)
                return -EIO;
 
-       ath9k_ps_wakeup(sc);
-
        r = ath_reset_internal(sc, hchan, false);
 
-       ath9k_ps_restore(sc);
-
        return r;
 }
 
@@ -739,12 +735,7 @@ void ath9k_tasklet(unsigned long data)
                        ath_tx_tasklet(sc);
        }
 
-       if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE)
-               if (status & ATH9K_INT_GENTIMER)
-                       ath_gen_timer_isr(sc->sc_ah);
-
-       if ((status & ATH9K_INT_MCI) && ATH9K_HW_CAP_MCI)
-               ath_mci_intr(sc);
+       ath9k_btcoex_handle_interrupt(sc, status);
 
 out:
        /* re-enable hardware interrupt */
@@ -1079,16 +1070,7 @@ static int ath9k_start(struct ieee80211_hw *hw)
 
        spin_unlock_bh(&sc->sc_pcu_lock);
 
-       if ((ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) &&
-           !ah->btcoex_hw.enabled) {
-               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 (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE)
-                       ath9k_btcoex_timer_resume(sc);
-       }
+       ath9k_start_btcoex(sc);
 
        if (ah->caps.pcie_lcr_extsync_en && common->bus_ops->extn_synch_en)
                common->bus_ops->extn_synch_en(common);
@@ -1189,13 +1171,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
        /* Ensure HW is awake when we try to shut it down. */
        ath9k_ps_wakeup(sc);
 
-       if (ah->btcoex_hw.enabled &&
-           ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) {
-               ath9k_hw_btcoex_disable(ah);
-               if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE)
-                       ath9k_btcoex_timer_pause(sc);
-               ath_mci_flush_profile(&sc->btcoex.mci);
-       }
+       ath9k_stop_btcoex(sc);
 
        spin_lock_bh(&sc->sc_pcu_lock);
 
@@ -1587,12 +1563,6 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
        ath9k_ps_wakeup(sc);
        mutex_lock(&sc->mutex);
 
-       /*
-        * Leave this as the first check because we need to turn on the
-        * radio if it was disabled before prior to processing the rest
-        * of the changes. Likewise we must only disable the radio towards
-        * the end.
-        */
        if (changed & IEEE80211_CONF_CHANGE_IDLE) {
                sc->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE);
                if (sc->ps_idle)
@@ -2330,6 +2300,7 @@ static int ath9k_tx_last_beacon(struct ieee80211_hw *hw)
        struct ath_vif *avp;
        struct ath_buf *bf;
        struct ath_tx_status ts;
+       bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);
        int status;
 
        vif = sc->beacon.bslot[0];
@@ -2340,7 +2311,7 @@ static int ath9k_tx_last_beacon(struct ieee80211_hw *hw)
        if (!avp->is_bslot_active)
                return 0;
 
-       if (!sc->beacon.tx_processed) {
+       if (!sc->beacon.tx_processed && !edma) {
                tasklet_disable(&sc->bcon_tasklet);
 
                bf = avp->av_bcbuf;
index 05c23ea4c63362a36072b699719ecd4ce2810173..29fe52d6997350777afb8660f41910738fffedb4 100644 (file)
@@ -42,24 +42,18 @@ static bool ath_mci_add_profile(struct ath_common *common,
        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, MCI,
-                       "Too many SCO profile, failed to add new profile\n");
+           (info->type == MCI_GPM_COEX_PROFILE_VOICE))
                return false;
-       }
 
        if (((NUM_PROF(mci) - mci->num_sco) == ATH_MCI_MAX_ACL_PROFILE) &&
-           (info->type != MCI_GPM_COEX_PROFILE_VOICE)) {
-               ath_dbg(common, MCI,
-                       "Too many ACL profile, failed to add new profile\n");
+           (info->type != MCI_GPM_COEX_PROFILE_VOICE))
                return false;
-       }
 
        entry = ath_mci_find_profile(mci, info);
 
-       if (entry)
+       if (entry) {
                memcpy(entry, info, 10);
-       else {
+       else {
                entry = kzalloc(sizeof(*entry), GFP_KERNEL);
                if (!entry)
                        return false;
@@ -68,6 +62,7 @@ static bool ath_mci_add_profile(struct ath_common *common,
                INC_PROF(mci, info);
                list_add_tail(&info->list, &mci->info);
        }
+
        return true;
 }
 
@@ -79,10 +74,9 @@ static void ath_mci_del_profile(struct ath_common *common,
 
        entry = ath_mci_find_profile(mci, info);
 
-       if (!entry) {
-               ath_dbg(common, MCI, "Profile to be deleted not found\n");
+       if (!entry)
                return;
-       }
+
        DEC_PROF(mci, entry);
        list_del(&entry->list);
        kfree(entry);
@@ -177,13 +171,12 @@ static void ath_mci_update_scheme(struct ath_softc *sc)
 
        btcoex->btcoex_period *= 1000;
        btcoex->btcoex_no_stomp =  btcoex->btcoex_period *
-                                       (100 - btcoex->duty_cycle) / 100;
+               (100 - btcoex->duty_cycle) / 100;
 
        ath9k_hw_btcoex_enable(sc->sc_ah);
        ath9k_btcoex_timer_resume(sc);
 }
 
-
 static void ath_mci_cal_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload)
 {
        struct ath_hw *ah = sc->sc_ah;
@@ -192,42 +185,24 @@ static void ath_mci_cal_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload)
 
        switch (opcode) {
        case MCI_GPM_BT_CAL_REQ:
-
-               ath_dbg(common, MCI, "MCI received BT_CAL_REQ\n");
-
                if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_AWAKE) {
                        ar9003_mci_state(ah, MCI_STATE_SET_BT_CAL_START, NULL);
                        ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
-               } else
-                       ath_dbg(common, MCI, "MCI State mismatches: %d\n",
+               } else {
+                       ath_dbg(common, MCI, "MCI State mismatch: %d\n",
                                ar9003_mci_state(ah, MCI_STATE_BT, NULL));
-
+               }
                break;
-
        case MCI_GPM_BT_CAL_DONE:
-
-               ath_dbg(common, MCI, "MCI received BT_CAL_DONE\n");
-
-               if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_CAL)
-                       ath_dbg(common, MCI, "MCI error illegal!\n");
-               else
-                       ath_dbg(common, MCI, "MCI BT not in CAL state\n");
-
+               ar9003_mci_state(ah, MCI_STATE_BT, NULL);
                break;
-
        case MCI_GPM_BT_CAL_GRANT:
-
-               ath_dbg(common, MCI, "MCI received BT_CAL_GRANT\n");
-
-               /* Send WLAN_CAL_DONE for now */
-               ath_dbg(common, MCI, "MCI send WLAN_CAL_DONE\n");
                MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_DONE);
                ar9003_mci_send_message(sc->sc_ah, MCI_GPM, 0, payload,
                                        16, false, true);
                break;
-
        default:
-               ath_dbg(common, MCI, "MCI Unknown GPM CAL message\n");
+               ath_dbg(common, MCI, "Unknown GPM CAL message\n");
                break;
        }
 }
@@ -247,6 +222,7 @@ static void ath_mci_process_profile(struct ath_softc *sc,
 
        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)];
@@ -262,31 +238,24 @@ static void ath_mci_process_profile(struct ath_softc *sc,
 static 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, MCI, "Skip link type status update\n");
+       if (status->is_link)
                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, MCI,
-                       "Skip non link state update for existing profile %d\n",
-                       status->conn_handle);
+       if (ath_mci_find_profile(mci, &info))
                return;
-       }
-       if (status->conn_handle >= ATH_MCI_MAX_PROFILE) {
-               ath_dbg(common, MCI, "Ignore too many non-link update\n");
+
+       if (status->conn_handle >= ATH_MCI_MAX_PROFILE)
                return;
-       }
+
        if (status->is_critical)
                __set_bit(status->conn_handle, mci->status);
        else
@@ -314,43 +283,28 @@ static void ath_mci_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload)
        u32 seq_num;
 
        switch (opcode) {
-
        case MCI_GPM_COEX_VERSION_QUERY:
-               ath_dbg(common, MCI, "MCI Recv GPM COEX Version Query\n");
-               version = ar9003_mci_state(ah,
-                               MCI_STATE_SEND_WLAN_COEX_VERSION, NULL);
+               version = ar9003_mci_state(ah, MCI_STATE_SEND_WLAN_COEX_VERSION,
+                                          NULL);
                break;
-
        case MCI_GPM_COEX_VERSION_RESPONSE:
-               ath_dbg(common, MCI, "MCI Recv GPM COEX Version Response\n");
                major = *(rx_payload + MCI_GPM_COEX_B_MAJOR_VERSION);
                minor = *(rx_payload + MCI_GPM_COEX_B_MINOR_VERSION);
-               ath_dbg(common, MCI, "MCI BT Coex version: %d.%d\n",
-                       major, minor);
                version = (major << 8) + minor;
-               version = ar9003_mci_state(ah,
-                         MCI_STATE_SET_BT_COEX_VERSION, &version);
+               version = ar9003_mci_state(ah, MCI_STATE_SET_BT_COEX_VERSION,
+                                          &version);
                break;
-
        case MCI_GPM_COEX_STATUS_QUERY:
-               ath_dbg(common, MCI,
-                       "MCI Recv GPM COEX Status Query = 0x%02x\n",
-                       *(rx_payload + MCI_GPM_COEX_B_WLAN_BITMAP));
-               ar9003_mci_state(ah,
-               MCI_STATE_SEND_WLAN_CHANNELS, NULL);
+               ar9003_mci_state(ah, MCI_STATE_SEND_WLAN_CHANNELS, NULL);
                break;
-
        case MCI_GPM_COEX_BT_PROFILE_INFO:
-               ath_dbg(common, MCI, "MCI Recv GPM Coex BT profile info\n");
                memcpy(&profile_info,
                       (rx_payload + MCI_GPM_COEX_B_PROFILE_TYPE), 10);
 
-               if ((profile_info.type == MCI_GPM_COEX_PROFILE_UNKNOWN)
-                   || (profile_info.type >=
-                                           MCI_GPM_COEX_PROFILE_MAX)) {
-
+               if ((profile_info.type == MCI_GPM_COEX_PROFILE_UNKNOWN) ||
+                   (profile_info.type >= MCI_GPM_COEX_PROFILE_MAX)) {
                        ath_dbg(common, MCI,
-                               "illegal profile type = %d, state = %d\n",
+                               "Illegal profile type = %d, state = %d\n",
                                profile_info.type,
                                profile_info.start);
                        break;
@@ -358,7 +312,6 @@ static void ath_mci_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload)
 
                ath_mci_process_profile(sc, &profile_info);
                break;
-
        case MCI_GPM_COEX_BT_STATUS_UPDATE:
                profile_status.is_link = *(rx_payload +
                                           MCI_GPM_COEX_B_STATUS_TYPE);
@@ -369,98 +322,66 @@ static void ath_mci_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload)
 
                seq_num = *((u32 *)(rx_payload + 12));
                ath_dbg(common, MCI,
-                       "MCI Recv GPM COEX BT_Status_Update: is_link=%d, linkId=%d, state=%d, SEQ=%d\n",
+                       "BT_Status_Update: is_link=%d, linkId=%d, state=%d, SEQ=%d\n",
                        profile_status.is_link, profile_status.conn_handle,
                        profile_status.is_critical, seq_num);
 
                ath_mci_process_status(sc, &profile_status);
                break;
-
        default:
-               ath_dbg(common, MCI, "MCI Unknown GPM COEX message = 0x%02x\n",
-                       opcode);
+               ath_dbg(common, MCI, "Unknown GPM COEX message = 0x%02x\n", opcode);
                break;
        }
 }
 
-static int ath_mci_buf_alloc(struct ath_softc *sc, struct ath_mci_buf *buf)
-{
-       int error = 0;
-
-       buf->bf_addr = dma_alloc_coherent(sc->dev, buf->bf_len,
-                                         &buf->bf_paddr, GFP_KERNEL);
-
-       if (buf->bf_addr == NULL) {
-               error = -ENOMEM;
-               goto fail;
-       }
-
-       return 0;
-
-fail:
-       memset(buf, 0, sizeof(*buf));
-       return error;
-}
-
-static void ath_mci_buf_free(struct ath_softc *sc, struct ath_mci_buf *buf)
-{
-       if (buf->bf_addr) {
-               dma_free_coherent(sc->dev, buf->bf_len, buf->bf_addr,
-                                                       buf->bf_paddr);
-               memset(buf, 0, sizeof(*buf));
-       }
-}
-
 int ath_mci_setup(struct ath_softc *sc)
 {
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_mci_coex *mci = &sc->mci_coex;
-       int error = 0;
-
-       if (!ATH9K_HW_CAP_MCI)
-               return 0;
+       struct ath_mci_buf *buf = &mci->sched_buf;
 
-       mci->sched_buf.bf_len = ATH_MCI_SCHED_BUF_SIZE + ATH_MCI_GPM_BUF_SIZE;
+       buf->bf_addr = dma_alloc_coherent(sc->dev,
+                                 ATH_MCI_SCHED_BUF_SIZE + ATH_MCI_GPM_BUF_SIZE,
+                                 &buf->bf_paddr, GFP_KERNEL);
 
-       if (ath_mci_buf_alloc(sc, &mci->sched_buf)) {
+       if (buf->bf_addr == NULL) {
                ath_dbg(common, FATAL, "MCI buffer alloc failed\n");
-               error = -ENOMEM;
-               goto fail;
+               return -ENOMEM;
        }
 
-       mci->sched_buf.bf_len = ATH_MCI_SCHED_BUF_SIZE;
+       memset(buf->bf_addr, MCI_GPM_RSVD_PATTERN,
+              ATH_MCI_SCHED_BUF_SIZE + ATH_MCI_GPM_BUF_SIZE);
 
-       memset(mci->sched_buf.bf_addr, MCI_GPM_RSVD_PATTERN,
-                                               mci->sched_buf.bf_len);
+       mci->sched_buf.bf_len = ATH_MCI_SCHED_BUF_SIZE;
 
        mci->gpm_buf.bf_len = ATH_MCI_GPM_BUF_SIZE;
-       mci->gpm_buf.bf_addr = (u8 *)mci->sched_buf.bf_addr +
-                                                       mci->sched_buf.bf_len;
+       mci->gpm_buf.bf_addr = (u8 *)mci->sched_buf.bf_addr + mci->sched_buf.bf_len;
        mci->gpm_buf.bf_paddr = mci->sched_buf.bf_paddr + mci->sched_buf.bf_len;
 
-       /* initialize the buffer */
-       memset(mci->gpm_buf.bf_addr, MCI_GPM_RSVD_PATTERN, mci->gpm_buf.bf_len);
-
        ar9003_mci_setup(sc->sc_ah, mci->gpm_buf.bf_paddr,
                         mci->gpm_buf.bf_addr, (mci->gpm_buf.bf_len >> 4),
                         mci->sched_buf.bf_paddr);
-fail:
-       return error;
+
+       ath_dbg(common, MCI, "MCI Initialized\n");
+
+       return 0;
 }
 
 void ath_mci_cleanup(struct ath_softc *sc)
 {
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_hw *ah = sc->sc_ah;
        struct ath_mci_coex *mci = &sc->mci_coex;
+       struct ath_mci_buf *buf = &mci->sched_buf;
 
-       if (!ATH9K_HW_CAP_MCI)
-               return;
+       if (buf->bf_addr)
+               dma_free_coherent(sc->dev,
+                                 ATH_MCI_SCHED_BUF_SIZE + ATH_MCI_GPM_BUF_SIZE,
+                                 buf->bf_addr, buf->bf_paddr);
 
-       /*
-        * both schedule and gpm buffers will be released
-        */
-       ath_mci_buf_free(sc, &mci->sched_buf);
        ar9003_mci_cleanup(ah);
+
+       ath_dbg(common, MCI, "MCI De-Initialized\n");
 }
 
 void ath_mci_intr(struct ath_softc *sc)
@@ -474,19 +395,10 @@ void ath_mci_intr(struct ath_softc *sc)
        u32 more_data = MCI_GPM_MORE;
        bool skip_gpm = false;
 
-       if (!ATH9K_HW_CAP_MCI)
-               return;
-
        ar9003_mci_get_interrupt(sc->sc_ah, &mci_int, &mci_int_rxmsg);
 
        if (ar9003_mci_state(ah, MCI_STATE_ENABLE, NULL) == 0) {
-
-               ar9003_mci_state(sc->sc_ah, MCI_STATE_INIT_GPM_OFFSET, NULL);
-               ath_dbg(common, MCI, "MCI interrupt but MCI disabled\n");
-
-               ath_dbg(common, MCI,
-                       "MCI interrupt: intr = 0x%x, intr_rxmsg = 0x%x\n",
-                       mci_int, mci_int_rxmsg);
+               ar9003_mci_state(ah, MCI_STATE_INIT_GPM_OFFSET, NULL);
                return;
        }
 
@@ -499,11 +411,8 @@ void ath_mci_intr(struct ath_softc *sc)
                 * only when BT wake up. Now they are always sent, as a
                 * recovery method to reset BT MCI's RX alignment.
                 */
-               ath_dbg(common, MCI, "MCI interrupt send REMOTE_RESET\n");
-
                ar9003_mci_send_message(ah, MCI_REMOTE_RESET, 0,
                                        payload, 16, true, false);
-               ath_dbg(common, MCI, "MCI interrupt send SYS_WAKING\n");
                ar9003_mci_send_message(ah, MCI_SYS_WAKING, 0,
                                        NULL, 0, true, false);
 
@@ -513,74 +422,51 @@ void ath_mci_intr(struct ath_softc *sc)
                /*
                 * always do this for recovery and 2G/5G toggling and LNA_TRANS
                 */
-               ath_dbg(common, MCI, "MCI Set BT state to AWAKE\n");
                ar9003_mci_state(ah, MCI_STATE_SET_BT_AWAKE, NULL);
        }
 
-       /* Processing SYS_WAKING/SYS_SLEEPING */
        if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING) {
                mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING;
 
                if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_SLEEP) {
-
-                       if (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL)
-                                       == MCI_BT_SLEEP)
-                               ath_dbg(common, MCI,
-                                       "MCI BT stays in sleep mode\n");
-                       else {
-                               ath_dbg(common, MCI,
-                                       "MCI Set BT state to AWAKE\n");
-                               ar9003_mci_state(ah,
-                                                MCI_STATE_SET_BT_AWAKE, NULL);
-                       }
-               } else
-                       ath_dbg(common, MCI, "MCI BT stays in AWAKE mode\n");
+                       if (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL) !=
+                           MCI_BT_SLEEP)
+                               ar9003_mci_state(ah, MCI_STATE_SET_BT_AWAKE,
+                                                NULL);
+               }
        }
 
        if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING) {
-
                mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING;
 
                if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_AWAKE) {
-
-                       if (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL)
-                                       == MCI_BT_AWAKE)
-                               ath_dbg(common, MCI,
-                                       "MCI BT stays in AWAKE mode\n");
-                       else {
-                               ath_dbg(common, MCI,
-                                       "MCI SetBT state to SLEEP\n");
+                       if (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL) !=
+                           MCI_BT_AWAKE)
                                ar9003_mci_state(ah, MCI_STATE_SET_BT_SLEEP,
                                                 NULL);
-                       }
-               } else
-                       ath_dbg(common, MCI, "MCI BT stays in SLEEP mode\n");
+               }
        }
 
        if ((mci_int & AR_MCI_INTERRUPT_RX_INVALID_HDR) ||
            (mci_int & AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT)) {
-
-               ath_dbg(common, MCI, "MCI RX broken, skip GPM msgs\n");
                ar9003_mci_state(ah, MCI_STATE_RECOVER_RX, NULL);
                skip_gpm = true;
        }
 
        if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO) {
-
                mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO;
                offset = ar9003_mci_state(ah, MCI_STATE_LAST_SCHD_MSG_OFFSET,
                                          NULL);
        }
 
        if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_GPM) {
-
                mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_GPM;
 
                while (more_data == MCI_GPM_MORE) {
 
                        pgpm = mci->gpm_buf.bf_addr;
-                       offset = ar9003_mci_state(ah,
-                                       MCI_STATE_NEXT_GPM_OFFSET, &more_data);
+                       offset = ar9003_mci_state(ah, MCI_STATE_NEXT_GPM_OFFSET,
+                                                 &more_data);
 
                        if (offset == MCI_GPM_INVALID)
                                break;
@@ -591,44 +477,38 @@ void ath_mci_intr(struct ath_softc *sc)
                         * The first dword is timer.
                         * The real data starts from 2nd dword.
                         */
-
                        subtype = MCI_GPM_TYPE(pgpm);
                        opcode = MCI_GPM_OPCODE(pgpm);
 
-                       if (!skip_gpm) {
-
-                               if (MCI_GPM_IS_CAL_TYPE(subtype))
-                                       ath_mci_cal_msg(sc, subtype,
-                                                       (u8 *) pgpm);
-                               else {
-                                       switch (subtype) {
-                                       case MCI_GPM_COEX_AGENT:
-                                               ath_mci_msg(sc, opcode,
-                                                           (u8 *) pgpm);
-                                               break;
-                                       default:
-                                               break;
-                                       }
+                       if (skip_gpm)
+                               goto recycle;
+
+                       if (MCI_GPM_IS_CAL_TYPE(subtype)) {
+                               ath_mci_cal_msg(sc, subtype, (u8 *)pgpm);
+                       } else {
+                               switch (subtype) {
+                               case MCI_GPM_COEX_AGENT:
+                                       ath_mci_msg(sc, opcode, (u8 *)pgpm);
+                                       break;
+                               default:
+                                       break;
                                }
                        }
+               recycle:
                        MCI_GPM_RECYCLE(pgpm);
                }
        }
 
        if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_HW_MSG_MASK) {
-
                if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL)
                        mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL;
 
-               if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_LNA_INFO) {
+               if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_LNA_INFO)
                        mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_LNA_INFO;
-                       ath_dbg(common, MCI, "MCI LNA_INFO\n");
-               }
 
                if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_INFO) {
-
                        int value_dbm = ar9003_mci_state(ah,
-                                       MCI_STATE_CONT_RSSI_POWER, NULL);
+                                                MCI_STATE_CONT_RSSI_POWER, NULL);
 
                        mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_CONT_INFO;
 
@@ -636,33 +516,25 @@ void ath_mci_intr(struct ath_softc *sc)
                                ath_dbg(common, MCI,
                                        "MCI CONT_INFO: (tx) pri = %d, pwr = %d dBm\n",
                                        ar9003_mci_state(ah,
-                                               MCI_STATE_CONT_PRIORITY, NULL),
+                                                MCI_STATE_CONT_PRIORITY, NULL),
                                        value_dbm);
                        else
                                ath_dbg(common, MCI,
                                        "MCI CONT_INFO: (rx) pri = %d,pwr = %d dBm\n",
                                        ar9003_mci_state(ah,
-                                               MCI_STATE_CONT_PRIORITY, NULL),
+                                                MCI_STATE_CONT_PRIORITY, NULL),
                                        value_dbm);
                }
 
-               if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_NACK) {
+               if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_NACK)
                        mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_CONT_NACK;
-                       ath_dbg(common, MCI, "MCI CONT_NACK\n");
-               }
 
-               if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_RST) {
+               if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_RST)
                        mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_CONT_RST;
-                       ath_dbg(common, MCI, "MCI CONT_RST\n");
-               }
        }
 
        if ((mci_int & AR_MCI_INTERRUPT_RX_INVALID_HDR) ||
            (mci_int & AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT))
                mci_int &= ~(AR_MCI_INTERRUPT_RX_INVALID_HDR |
                             AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT);
-
-       if (mci_int_rxmsg & 0xfffffffe)
-               ath_dbg(common, MCI, "MCI not processed mci_int_rxmsg = 0x%x\n",
-                       mci_int_rxmsg);
 }
index 29e3e51d078f52e661f0693f267d6e2f031f4479..c841444f53c2c91d2a02140c11f5cadf97f421c3 100644 (file)
@@ -17,6 +17,8 @@
 #ifndef MCI_H
 #define MCI_H
 
+#include "ar9003_mci.h"
+
 #define ATH_MCI_SCHED_BUF_SIZE         (16 * 16) /* 16 entries, 4 dword each */
 #define ATH_MCI_GPM_MAX_ENTRY          16
 #define ATH_MCI_GPM_BUF_SIZE           (ATH_MCI_GPM_MAX_ENTRY * 16)
@@ -113,7 +115,6 @@ struct ath_mci_profile {
        u8 num_bdr;
 };
 
-
 struct ath_mci_buf {
        void *bf_addr;          /* virtual addr of desc */
        dma_addr_t bf_paddr;    /* physical addr of buffer */
@@ -121,10 +122,8 @@ struct ath_mci_buf {
 };
 
 struct ath_mci_coex {
-       atomic_t mci_cal_flag;
        struct ath_mci_buf sched_buf;
        struct ath_mci_buf gpm_buf;
-       u32 bt_cal_start;
 };
 
 void ath_mci_flush_profile(struct ath_mci_profile *mci);
index a427a16bb739be2b97cbeb2c430fec41bd689774..6407af22f7b90b216752198703574670f48726c9 100644 (file)
@@ -567,10 +567,8 @@ static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv,
 
 static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv,
                                  const struct ath_rate_table *rate_table,
-                                 u8 *mcs_set, u32 capflag)
+                                 struct ath_rateset *rateset, u32 capflag)
 {
-       struct ath_rateset *rateset = (struct ath_rateset *)mcs_set;
-
        u8 i, j, hi = 0;
 
        /* Use intersection of working rates and valid rates */
@@ -1212,7 +1210,7 @@ static void ath_rc_init(struct ath_softc *sc,
 {
        struct ath_rateset *rateset = &ath_rc_priv->neg_rates;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-       u8 *ht_mcs = (u8 *)&ath_rc_priv->neg_ht_rates;
+       struct ath_rateset *ht_mcs = &ath_rc_priv->neg_ht_rates;
        u8 i, j, k, hi = 0, hthi = 0;
 
        /* Initial rate table size. Will change depending
@@ -1228,7 +1226,7 @@ static void ath_rc_init(struct ath_softc *sc,
        ath_rc_init_valid_rate_idx(ath_rc_priv);
 
        for (i = 0; i < WLAN_RC_PHY_MAX; i++) {
-               for (j = 0; j < MAX_TX_RATE_PHY; j++)
+               for (j = 0; j < RATE_TABLE_SIZE; j++)
                        ath_rc_priv->valid_phy_rateidx[i][j] = 0;
                ath_rc_priv->valid_phy_ratecnt[i] = 0;
        }
index b7a4bcd3eec70f02c62f11e0a23ea7ff843813f2..75f8e9b06b2859d2866f16653c3a22913ee6baf5 100644 (file)
@@ -25,8 +25,6 @@ struct ath_softc;
 
 #define ATH_RATE_MAX     30
 #define RATE_TABLE_SIZE  72
-#define MAX_TX_RATE_PHY  48
-
 
 #define RC_INVALID     0x0000
 #define RC_LEGACY      0x0001
index 7e1a91af149751b13a53ee9d6dab5c16fcd2f01f..1b1b279c304aa5e3794c8e13f8ac2fec4b3b2e37 100644 (file)
@@ -169,22 +169,17 @@ static void ath_rx_addbuffer_edma(struct ath_softc *sc,
                                  enum ath9k_rx_qtype qtype, int size)
 {
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-       u32 nbuf = 0;
+       struct ath_buf *bf, *tbf;
 
        if (list_empty(&sc->rx.rxbuf)) {
                ath_dbg(common, QUEUE, "No free rx buf available\n");
                return;
        }
 
-       while (!list_empty(&sc->rx.rxbuf)) {
-               nbuf++;
-
+       list_for_each_entry_safe(bf, tbf, &sc->rx.rxbuf, list)
                if (!ath_rx_edma_buf_link(sc, qtype))
                        break;
 
-               if (nbuf >= size)
-                       break;
-       }
 }
 
 static void ath_rx_remove_buffer(struct ath_softc *sc,
@@ -232,7 +227,6 @@ static void ath_rx_edma_cleanup(struct ath_softc *sc)
 static void ath_rx_edma_init_queue(struct ath_rx_edma *rx_edma, int size)
 {
        skb_queue_head_init(&rx_edma->rx_fifo);
-       skb_queue_head_init(&rx_edma->rx_buffers);
        rx_edma->rx_fifo_hwsize = size;
 }
 
@@ -658,7 +652,9 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb, bool mybeacon)
 }
 
 static bool ath_edma_get_buffers(struct ath_softc *sc,
-                                enum ath9k_rx_qtype qtype)
+                                enum ath9k_rx_qtype qtype,
+                                struct ath_rx_status *rs,
+                                struct ath_buf **dest)
 {
        struct ath_rx_edma *rx_edma = &sc->rx.rx_edma[qtype];
        struct ath_hw *ah = sc->sc_ah;
@@ -677,7 +673,7 @@ static bool ath_edma_get_buffers(struct ath_softc *sc,
        dma_sync_single_for_cpu(sc->dev, bf->bf_buf_addr,
                                common->rx_bufsize, DMA_FROM_DEVICE);
 
-       ret = ath9k_hw_process_rxdesc_edma(ah, NULL, skb->data);
+       ret = ath9k_hw_process_rxdesc_edma(ah, rs, skb->data);
        if (ret == -EINPROGRESS) {
                /*let device gain the buffer again*/
                dma_sync_single_for_device(sc->dev, bf->bf_buf_addr,
@@ -690,20 +686,21 @@ static bool ath_edma_get_buffers(struct ath_softc *sc,
                /* corrupt descriptor, skip this one and the following one */
                list_add_tail(&bf->list, &sc->rx.rxbuf);
                ath_rx_edma_buf_link(sc, qtype);
-               skb = skb_peek(&rx_edma->rx_fifo);
-               if (!skb)
-                       return true;
 
-               bf = SKB_CB_ATHBUF(skb);
-               BUG_ON(!bf);
+               skb = skb_peek(&rx_edma->rx_fifo);
+               if (skb) {
+                       bf = SKB_CB_ATHBUF(skb);
+                       BUG_ON(!bf);
 
-               __skb_unlink(skb, &rx_edma->rx_fifo);
-               list_add_tail(&bf->list, &sc->rx.rxbuf);
-               ath_rx_edma_buf_link(sc, qtype);
-               return true;
+                       __skb_unlink(skb, &rx_edma->rx_fifo);
+                       list_add_tail(&bf->list, &sc->rx.rxbuf);
+                       ath_rx_edma_buf_link(sc, qtype);
+               } else {
+                       bf = NULL;
+               }
        }
-       skb_queue_tail(&rx_edma->rx_buffers, skb);
 
+       *dest = bf;
        return true;
 }
 
@@ -711,18 +708,15 @@ static struct ath_buf *ath_edma_get_next_rx_buf(struct ath_softc *sc,
                                                struct ath_rx_status *rs,
                                                enum ath9k_rx_qtype qtype)
 {
-       struct ath_rx_edma *rx_edma = &sc->rx.rx_edma[qtype];
-       struct sk_buff *skb;
-       struct ath_buf *bf;
+       struct ath_buf *bf = NULL;
 
-       while (ath_edma_get_buffers(sc, qtype));
-       skb = __skb_dequeue(&rx_edma->rx_buffers);
-       if (!skb)
-               return NULL;
+       while (ath_edma_get_buffers(sc, qtype, rs, &bf)) {
+               if (!bf)
+                       continue;
 
-       bf = SKB_CB_ATHBUF(skb);
-       ath9k_hw_process_rxdesc_edma(sc->sc_ah, rs, skb->data);
-       return bf;
+               return bf;
+       }
+       return NULL;
 }
 
 static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc,
@@ -954,6 +948,7 @@ static void ath9k_process_rssi(struct ath_common *common,
        struct ath_softc *sc = hw->priv;
        struct ath_hw *ah = common->ah;
        int last_rssi;
+       int rssi = rx_stats->rs_rssi;
 
        if (!rx_stats->is_mybeacon ||
            ((ah->opmode != NL80211_IFTYPE_STATION) &&
@@ -965,13 +960,12 @@ static void ath9k_process_rssi(struct ath_common *common,
 
        last_rssi = sc->last_rssi;
        if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
-               rx_stats->rs_rssi = ATH_EP_RND(last_rssi,
-                                             ATH_RSSI_EP_MULTIPLIER);
-       if (rx_stats->rs_rssi < 0)
-               rx_stats->rs_rssi = 0;
+               rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER);
+       if (rssi < 0)
+               rssi = 0;
 
        /* Update Beacon RSSI, this is used by ANI. */
-       ah->stats.avgbrssi = rx_stats->rs_rssi;
+       ah->stats.avgbrssi = rssi;
 }
 
 /*
@@ -1011,6 +1005,8 @@ static int ath9k_rx_skb_preprocess(struct ath_common *common,
        rx_status->signal = ah->noise + rx_stats->rs_rssi;
        rx_status->antenna = rx_stats->rs_antenna;
        rx_status->flag |= RX_FLAG_MACTIME_MPDU;
+       if (rx_stats->rs_moreaggr)
+               rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;
 
        return 0;
 }
index 6e2f18861f5d991d62b84b854f633443ba961d4a..80b1856f817deff8522ef0c32aee21d9b57c1de8 100644 (file)
 #define AR_SREV_VERSION_9580           0x1C0
 #define AR_SREV_REVISION_9580_10       4 /* AR9580 1.0 */
 #define AR_SREV_VERSION_9462           0x280
-#define AR_SREV_REVISION_9462_10       0
 #define AR_SREV_REVISION_9462_20       2
 
 #define AR_SREV_5416(_ah) \
 #define AR_SREV_9462(_ah) \
        (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462))
 
-#define AR_SREV_9462_10(_ah) \
-       (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \
-       ((_ah)->hw_version.macRev == AR_SREV_REVISION_9462_10))
-
 #define AR_SREV_9462_20(_ah) \
        (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \
        ((_ah)->hw_version.macRev == AR_SREV_REVISION_9462_20))
index 3182408ffe35abcc08c075d8f950cf433d1ca9cf..9f785015a7dcef6acbe75eb74e044a7dcfb463ad 100644 (file)
@@ -647,9 +647,8 @@ 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;
+       u16 aggr_limit, bt_aggr_limit, legacy = 0;
        int i;
 
        skb = bf->bf_mpdu;
@@ -694,14 +693,14 @@ 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_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
-               aggr_limit = min(max_4ms_framelen,
-                                (u32)ATH_AMPDU_LIMIT_MAX);
+       aggr_limit = min(max_4ms_framelen, (u32)ATH_AMPDU_LIMIT_MAX);
+
+       /*
+        * Override the default aggregation limit for BTCOEX.
+        */
+       bt_aggr_limit = ath9k_btcoex_aggr_limit(sc, max_4ms_framelen);
+       if (bt_aggr_limit)
+               aggr_limit = bt_aggr_limit;
 
        /*
         * h/w can accept aggregates up to 16 bit lengths (65535).
@@ -2297,9 +2296,12 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
                        break;
                }
 
-               /* Skip beacon completions */
-               if (ts.qid == sc->beacon.beaconq)
+               /* Process beacon completions separately */
+               if (ts.qid == sc->beacon.beaconq) {
+                       sc->beacon.tx_processed = true;
+                       sc->beacon.tx_last = !(ts.ts_status & ATH9K_TXERR_MASK);
                        continue;
+               }
 
                txq = &sc->tx.txq[ts.qid];
 
index 771e1a9294c54e1d70e1183e2cdbe00fa2595dc7..aed305177af6a92ba784a8014c66bee117f5bea4 100644 (file)
@@ -1236,6 +1236,7 @@ static bool carl9170_tx_ps_drop(struct ar9170 *ar, struct sk_buff *skb)
 {
        struct ieee80211_sta *sta;
        struct carl9170_sta_info *sta_info;
+       struct ieee80211_tx_info *tx_info;
 
        rcu_read_lock();
        sta = __carl9170_get_tx_sta(ar, skb);
@@ -1243,16 +1244,18 @@ static bool carl9170_tx_ps_drop(struct ar9170 *ar, struct sk_buff *skb)
                goto out_rcu;
 
        sta_info = (void *) sta->drv_priv;
-       if (unlikely(sta_info->sleeping)) {
-               struct ieee80211_tx_info *tx_info;
+       tx_info = IEEE80211_SKB_CB(skb);
 
+       if (unlikely(sta_info->sleeping) &&
+           !(tx_info->flags & (IEEE80211_TX_CTL_NO_PS_BUFFER |
+                               IEEE80211_TX_CTL_CLEAR_PS_FILT))) {
                rcu_read_unlock();
 
-               tx_info = IEEE80211_SKB_CB(skb);
                if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
                        atomic_dec(&ar->tx_ampdu_upload);
 
                tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
+               carl9170_release_dev_space(ar, skb);
                carl9170_tx_status(ar, skb, false);
                return true;
        }
index 5189cf38123a8a30af8ec50d9157e5f51869f44d..1d633f3b3274f15583f033ba2faea7ae3d203d5f 100644 (file)
@@ -2706,6 +2706,8 @@ static int b43_gpio_init(struct b43_wldev *dev)
                mask |= 0x0060;
                set |= 0x0060;
        }
+       if (dev->dev->chip_id == 0x5354)
+               set &= 0xff02;
        if (0 /* FIXME: conditional unknown */ ) {
                b43_write16(dev, B43_MMIO_GPIO_MASK,
                            b43_read16(dev, B43_MMIO_GPIO_MASK)
index 96faaef3661b075fc2a3b52f8c08a7d91b708d20..950334197f403e12daaaf274b31bb78c9a792cee 100644 (file)
@@ -1860,7 +1860,7 @@ void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev)
         * which accounts for the factor of 4 */
 #define REG_MAX_PWR 20
        max_pwr = min(REG_MAX_PWR * 4
-                     - dev->dev->bus->sprom.antenna_gain.ghz24.a0
+                     - dev->dev->bus->sprom.antenna_gain.a0
                      - 0x6, max_pwr);
 
        /* find the desired power in Q5.2 - power_level is in dBm
index cd6375de2a606a2662ba2c5a63e5906c88b4656c..c5104533e24e7a7986e6445d8108f91e0cc73e40 100644 (file)
@@ -26,16 +26,25 @@ config BRCMFMAC
          it'll be called brcmfmac.ko.
 
 config BRCMFMAC_SDIO
-       bool "SDIO bus interface support for FullMAC"
+       bool "SDIO bus interface support for FullMAC driver"
        depends on MMC
        depends on BRCMFMAC
        select FW_LOADER
        default y
        ---help---
          This option enables the SDIO bus interface support for Broadcom
-         FullMAC WLAN driver.
-         Say Y if you want to use brcmfmac for a compatible SDIO interface
-         wireless card.
+         IEEE802.11n embedded FullMAC WLAN driver. Say Y if you want to
+         use the driver for a SDIO wireless card.
+
+config BRCMFMAC_USB
+       bool "USB bus interface support for FullMAC driver"
+       depends on USB
+       depends on BRCMFMAC
+       select FW_LOADER
+       ---help---
+         This option enables the USB bus interface support for Broadcom
+         IEEE802.11n embedded FullMAC WLAN driver. Say Y if you want to
+         use the driver for an USB wireless card.
 
 config BRCMDBG
        bool "Broadcom driver debug functions"
index 9ca9ea1135ea3c311938bf9d86d6b98a557deeba..abb48032753b1d1b1a11ec1b1a67feb2a92c53f5 100644 (file)
@@ -19,6 +19,8 @@ ccflags-y += \
        -Idrivers/net/wireless/brcm80211/brcmfmac       \
        -Idrivers/net/wireless/brcm80211/include
 
+ccflags-y += -D__CHECK_ENDIAN__
+
 obj-$(CONFIG_BRCMFMAC) += brcmfmac.o
 brcmfmac-objs += \
                wl_cfg80211.o \
@@ -30,5 +32,5 @@ brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \
                bcmsdh.o \
                bcmsdh_sdmmc.o \
                sdio_chip.o
-
-ccflags-y += -D__CHECK_ENDIAN__
+brcmfmac-$(CONFIG_BRCMFMAC_USB) += \
+               usb.o
index ac71adeece51aa0f4bcb343de17e2abfbd130bde..4688904908ec464b3b9895504e8566eb61d6c5e7 100644 (file)
@@ -294,13 +294,14 @@ int brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev,
                               struct sk_buff *pkt)
 {
        int status;
-       uint pkt_len = pkt->len;
+       uint pkt_len;
        bool fifo = (fix_inc == SDIOH_DATA_FIX);
 
        brcmf_dbg(TRACE, "Enter\n");
 
        if (pkt == NULL)
                return -EINVAL;
+       pkt_len = pkt->len;
 
        brcmf_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait);
        if (brcmf_pm_resume_error(sdiodev))
@@ -488,7 +489,7 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
                sdiodev->func[0] = func->card->sdio_func[0];
                sdiodev->func[1] = func;
                sdiodev->bus_if = bus_if;
-               bus_if->bus_priv = sdiodev;
+               bus_if->bus_priv.sdio = sdiodev;
                bus_if->type = SDIO_BUS;
                bus_if->align = BRCMF_SDALIGN;
                dev_set_drvdata(&func->card->dev, sdiodev);
@@ -529,7 +530,7 @@ static void brcmf_ops_sdio_remove(struct sdio_func *func)
 
        if (func->num == 2) {
                bus_if = dev_get_drvdata(&func->dev);
-               sdiodev = bus_if->bus_priv;
+               sdiodev = bus_if->bus_priv.sdio;
                brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_remove...\n");
                brcmf_sdio_remove(sdiodev);
                dev_set_drvdata(&func->card->dev, NULL);
@@ -596,14 +597,14 @@ static struct sdio_driver brcmf_sdmmc_driver = {
 #endif /* CONFIG_PM_SLEEP */
 };
 
-static void __exit brcmf_sdio_exit(void)
+void brcmf_sdio_exit(void)
 {
        brcmf_dbg(TRACE, "Enter\n");
 
        sdio_unregister_driver(&brcmf_sdmmc_driver);
 }
 
-static int __init brcmf_sdio_init(void)
+void brcmf_sdio_init(void)
 {
        int ret;
 
@@ -613,9 +614,4 @@ static int __init brcmf_sdio_init(void)
 
        if (ret)
                brcmf_dbg(ERROR, "sdio_register_driver failed: %d\n", ret);
-
-       return ret;
 }
-
-module_init(brcmf_sdio_init);
-module_exit(brcmf_sdio_exit);
index ad9be2410b59337158879fe301673433d68d6320..366916494be402a90ffdc5654cc286f075bdc795 100644 (file)
@@ -39,8 +39,11 @@ struct dngl_stats {
 /* interface structure between common and bus layer */
 struct brcmf_bus {
        u8 type;                /* bus type */
-       void *bus_priv;         /* pointer to bus private structure */
-       void *drvr;             /* pointer to driver pub structure brcmf_pub */
+       union {
+               struct brcmf_sdio_dev *sdio;
+               struct brcmf_usbdev *usb;
+       } bus_priv;
+       struct brcmf_pub *drvr; /* pointer to driver pub structure brcmf_pub */
        enum brcmf_bus_state state;
        uint maxctl;            /* Max size rxctl request from proto to bus */
        bool drvr_up;           /* Status flag of driver up/down */
@@ -102,4 +105,14 @@ extern int brcmf_bus_start(struct device *dev);
 
 extern int brcmf_add_if(struct device *dev, int ifidx,
                        char *name, u8 *mac_addr);
+
+#ifdef CONFIG_BRCMFMAC_SDIO
+extern void brcmf_sdio_exit(void);
+extern void brcmf_sdio_init(void);
+#endif
+#ifdef CONFIG_BRCMFMAC_USB
+extern void brcmf_usb_exit(void);
+extern void brcmf_usb_init(void);
+#endif
+
 #endif                         /* _BRCMF_BUS_H_ */
index db2df1f1e6b27589befa5c810acd8d0b223fe75b..2a1e5ae0c4024ff560b40dade098c4599894feb5 100644 (file)
@@ -796,18 +796,19 @@ static int brcmf_netdev_open(struct net_device *ndev)
 {
        struct brcmf_if *ifp = netdev_priv(ndev);
        struct brcmf_pub *drvr = ifp->drvr;
+       struct brcmf_bus *bus_if = drvr->bus_if;
        u32 toe_ol;
        s32 ret = 0;
 
        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->dev);
-               if (ret != 0) {
-                       brcmf_dbg(ERROR, "failed with code %d\n", ret);
-                       return -1;
+               /* If bus is not ready, can't continue */
+               if (bus_if->state != BRCMF_BUS_DATA) {
+                       brcmf_dbg(ERROR, "failed bus is not ready\n");
+                       return -EAGAIN;
                }
+
                atomic_set(&drvr->pend_8021x_cnt, 0);
 
                memcpy(ndev->dev_addr, drvr->mac, ETH_ALEN);
@@ -979,12 +980,6 @@ int brcmf_bus_start(struct device *dev)
                return ret;
        }
 
-       /* If bus is not ready, can't come up */
-       if (bus_if->state != BRCMF_BUS_DATA) {
-               brcmf_dbg(ERROR, "failed bus is not ready\n");
-               return -ENODEV;
-       }
-
        brcmf_c_mkiovar("event_msgs", drvr->eventmask, BRCMF_EVENTING_MASK_LEN,
                      iovbuf, sizeof(iovbuf));
        brcmf_proto_cdc_query_dcmd(drvr, 0, BRCMF_C_GET_VAR, iovbuf,
@@ -1021,6 +1016,8 @@ int brcmf_bus_start(struct device *dev)
        if (ret < 0)
                return ret;
 
+       /* signal bus ready */
+       bus_if->state = BRCMF_BUS_DATA;
        return 0;
 }
 
@@ -1109,13 +1106,13 @@ void brcmf_detach(struct device *dev)
                if (drvr->iflist[i])
                        brcmf_del_if(drvr, i);
 
-       cancel_work_sync(&drvr->setmacaddr_work);
-       cancel_work_sync(&drvr->multicast_work);
-
        brcmf_bus_detach(drvr);
 
-       if (drvr->prot)
+       if (drvr->prot) {
+               cancel_work_sync(&drvr->setmacaddr_work);
+               cancel_work_sync(&drvr->multicast_work);
                brcmf_proto_detach(drvr);
+       }
 
        bus_if->drvr = NULL;
        kfree(drvr);
@@ -1183,3 +1180,37 @@ exit:
        return ret;
 }
 #endif                         /* DEBUG */
+
+static void brcmf_driver_init(struct work_struct *work)
+{
+#ifdef CONFIG_BRCMFMAC_SDIO
+       brcmf_sdio_init();
+#endif
+#ifdef CONFIG_BRCMFMAC_USB
+       brcmf_usb_init();
+#endif
+}
+static DECLARE_WORK(brcmf_driver_work, brcmf_driver_init);
+
+static int __init brcmfmac_module_init(void)
+{
+       if (!schedule_work(&brcmf_driver_work))
+               return -EBUSY;
+
+       return 0;
+}
+
+static void __exit brcmfmac_module_exit(void)
+{
+       cancel_work_sync(&brcmf_driver_work);
+
+#ifdef CONFIG_BRCMFMAC_SDIO
+       brcmf_sdio_exit();
+#endif
+#ifdef CONFIG_BRCMFMAC_USB
+       brcmf_usb_exit();
+#endif
+}
+
+module_init(brcmfmac_module_init);
+module_exit(brcmfmac_module_exit);
index bd2d1dd5a4955d2e0a36720bb26856a999551dfb..2bf5dda292919868a90a9dad3722f0a4991f7024 100644 (file)
@@ -309,10 +309,10 @@ struct rte_console {
 /* Flags for SDH calls */
 #define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
 
-#define BRCMFMAC_FW_NAME       "brcm/brcmfmac.bin"
-#define BRCMFMAC_NV_NAME       "brcm/brcmfmac.txt"
-MODULE_FIRMWARE(BRCMFMAC_FW_NAME);
-MODULE_FIRMWARE(BRCMFMAC_NV_NAME);
+#define BRCMF_SDIO_FW_NAME     "brcm/brcmfmac-sdio.bin"
+#define BRCMF_SDIO_NV_NAME     "brcm/brcmfmac-sdio.txt"
+MODULE_FIRMWARE(BRCMF_SDIO_FW_NAME);
+MODULE_FIRMWARE(BRCMF_SDIO_NV_NAME);
 
 #define BRCMF_IDLE_IMMEDIATE   (-1)    /* Enter idle immediately */
 #define BRCMF_IDLE_ACTIVE      0       /* Do not request any SD clock change
@@ -2276,7 +2276,7 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev)
        uint retries;
        int err;
        struct brcmf_bus *bus_if = dev_get_drvdata(dev);
-       struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv;
+       struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
        struct brcmf_sdio *bus = sdiodev->bus;
 
        brcmf_dbg(TRACE, "Enter\n");
@@ -2626,7 +2626,7 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)
        int ret = -EBADE;
        uint datalen, prec;
        struct brcmf_bus *bus_if = dev_get_drvdata(dev);
-       struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv;
+       struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
        struct brcmf_sdio *bus = sdiodev->bus;
 
        brcmf_dbg(TRACE, "Enter\n");
@@ -2867,7 +2867,7 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
        u8 doff = 0;
        int ret = -1;
        struct brcmf_bus *bus_if = dev_get_drvdata(dev);
-       struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv;
+       struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
        struct brcmf_sdio *bus = sdiodev->bus;
 
        brcmf_dbg(TRACE, "Enter\n");
@@ -2976,7 +2976,7 @@ brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)
        uint rxlen = 0;
        bool pending;
        struct brcmf_bus *bus_if = dev_get_drvdata(dev);
-       struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv;
+       struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
        struct brcmf_sdio *bus = sdiodev->bus;
 
        brcmf_dbg(TRACE, "Enter\n");
@@ -3200,7 +3200,7 @@ static int brcmf_sdbrcm_download_code_file(struct brcmf_sdio *bus)
 
        brcmf_dbg(INFO, "Enter\n");
 
-       ret = request_firmware(&bus->firmware, BRCMFMAC_FW_NAME,
+       ret = request_firmware(&bus->firmware, BRCMF_SDIO_FW_NAME,
                               &bus->sdiodev->func[2]->dev);
        if (ret) {
                brcmf_dbg(ERROR, "Fail to request firmware %d\n", ret);
@@ -3297,7 +3297,7 @@ static int brcmf_sdbrcm_download_nvram(struct brcmf_sdio *bus)
        char *bufp;
        int ret;
 
-       ret = request_firmware(&bus->firmware, BRCMFMAC_NV_NAME,
+       ret = request_firmware(&bus->firmware, BRCMF_SDIO_NV_NAME,
                               &bus->sdiodev->func[2]->dev);
        if (ret) {
                brcmf_dbg(ERROR, "Fail to request nvram %d\n", ret);
@@ -3387,7 +3387,7 @@ brcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus)
 static int brcmf_sdbrcm_bus_init(struct device *dev)
 {
        struct brcmf_bus *bus_if = dev_get_drvdata(dev);
-       struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv;
+       struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
        struct brcmf_sdio *bus = sdiodev->bus;
        unsigned long timeout;
        uint retries = 0;
@@ -3462,16 +3462,12 @@ static int brcmf_sdbrcm_bus_init(struct device *dev)
 
                brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
                                       SBSDIO_WATERMARK, 8, &err);
-
-               /* Set bus state according to enable result */
-               bus_if->state = BRCMF_BUS_DATA;
-       }
-
-       else {
+       } else {
                /* Disable F2 again */
                enable = SDIO_FUNC_ENABLE_1;
                brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0,
                                       SDIO_CCCR_IOEx, enable, NULL);
+               ret = -ENODEV;
        }
 
        /* Restore previous clock setting */
@@ -3479,7 +3475,7 @@ static int brcmf_sdbrcm_bus_init(struct device *dev)
                               SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
 
        /* If we didn't come up, turn off backplane clock */
-       if (bus_if->state != BRCMF_BUS_DATA)
+       if (!ret)
                brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
 
 exit:
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
new file mode 100644 (file)
index 0000000..8236422
--- /dev/null
@@ -0,0 +1,1621 @@
+/*
+ * Copyright (c) 2011 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/spinlock.h>
+#include <linux/ethtool.h>
+#include <linux/fcntl.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/firmware.h>
+#include <linux/usb.h>
+#include <net/cfg80211.h>
+
+#include <defs.h>
+#include <brcmu_utils.h>
+#include <brcmu_wifi.h>
+#include <dhd_bus.h>
+#include <dhd_dbg.h>
+
+#include "usb_rdl.h"
+#include "usb.h"
+
+#define IOCTL_RESP_TIMEOUT  2000
+
+#define BRCMF_USB_SYNC_TIMEOUT         300     /* ms */
+#define BRCMF_USB_DLIMAGE_SPINWAIT     100     /* in unit of ms */
+#define BRCMF_USB_DLIMAGE_LIMIT                500     /* spinwait limit (ms) */
+
+#define BRCMF_POSTBOOT_ID              0xA123  /* ID to detect if dongle
+                                                  has boot up */
+#define BRCMF_USB_RESETCFG_SPINWAIT    1       /* wait after resetcfg (ms) */
+
+#define BRCMF_USB_NRXQ 50
+#define BRCMF_USB_NTXQ 50
+
+#define CONFIGDESC(usb)         (&((usb)->actconfig)->desc)
+#define IFPTR(usb, idx)         ((usb)->actconfig->interface[(idx)])
+#define IFALTS(usb, idx)        (IFPTR((usb), (idx))->altsetting[0])
+#define IFDESC(usb, idx)        IFALTS((usb), (idx)).desc
+#define IFEPDESC(usb, idx, ep)  (IFALTS((usb), (idx)).endpoint[(ep)]).desc
+
+#define CONTROL_IF              0
+#define BULK_IF                 0
+
+#define BRCMF_USB_CBCTL_WRITE  0
+#define BRCMF_USB_CBCTL_READ   1
+#define BRCMF_USB_MAX_PKT_SIZE 1600
+
+#define BRCMF_USB_43236_FW_NAME        "brcm/brcmfmac43236b.bin"
+
+enum usbdev_suspend_state {
+       USBOS_SUSPEND_STATE_DEVICE_ACTIVE = 0, /* Device is busy, won't allow
+                                                 suspend */
+       USBOS_SUSPEND_STATE_SUSPEND_PENDING,    /* Device is idle, can be
+                                                * suspended. Wating PM to
+                                                * suspend the device
+                                                */
+       USBOS_SUSPEND_STATE_SUSPENDED   /* Device suspended */
+};
+
+struct brcmf_usb_probe_info {
+       void *usbdev_info;
+       struct usb_device *usb; /* USB device pointer from OS */
+       uint rx_pipe, tx_pipe, intr_pipe, rx_pipe2;
+       int intr_size; /* Size of interrupt message */
+       int interval;  /* Interrupt polling interval */
+       int vid;
+       int pid;
+       enum usb_device_speed device_speed;
+       enum usbdev_suspend_state suspend_state;
+       struct usb_interface *intf;
+};
+static struct brcmf_usb_probe_info usbdev_probe_info;
+
+struct brcmf_usb_image {
+       void *data;
+       u32 len;
+};
+static struct brcmf_usb_image g_image = { NULL, 0 };
+
+struct intr_transfer_buf {
+       u32 notification;
+       u32 reserved;
+};
+
+struct brcmf_usbdev_info {
+       struct brcmf_usbdev bus_pub; /* MUST BE FIRST */
+       spinlock_t qlock;
+       struct list_head rx_freeq;
+       struct list_head rx_postq;
+       struct list_head tx_freeq;
+       struct list_head tx_postq;
+       enum usbdev_suspend_state suspend_state;
+       uint rx_pipe, tx_pipe, intr_pipe, rx_pipe2;
+
+       bool activity;
+       int rx_low_watermark;
+       int tx_low_watermark;
+       int tx_high_watermark;
+       bool txoff;
+       bool rxoff;
+       bool txoverride;
+
+       struct brcmf_usbreq *tx_reqs;
+       struct brcmf_usbreq *rx_reqs;
+
+       u8 *image;      /* buffer for combine fw and nvram */
+       int image_len;
+
+       wait_queue_head_t wait;
+       bool waitdone;
+       int sync_urb_status;
+
+       struct usb_device *usbdev;
+       struct device *dev;
+       enum usb_device_speed  device_speed;
+
+       int ctl_in_pipe, ctl_out_pipe;
+       struct urb *ctl_urb; /* URB for control endpoint */
+       struct usb_ctrlrequest ctl_write;
+       struct usb_ctrlrequest ctl_read;
+       u32 ctl_urb_actual_length;
+       int ctl_urb_status;
+       int ctl_completed;
+       wait_queue_head_t ioctl_resp_wait;
+       wait_queue_head_t ctrl_wait;
+       ulong ctl_op;
+
+       bool rxctl_deferrespok;
+
+       struct urb *bulk_urb; /* used for FW download */
+       struct urb *intr_urb; /* URB for interrupt endpoint */
+       int intr_size;          /* Size of interrupt message */
+       int interval;           /* Interrupt polling interval */
+       struct intr_transfer_buf intr; /* Data buffer for interrupt endpoint */
+
+       struct brcmf_usb_probe_info probe_info;
+
+};
+
+static void brcmf_usb_rx_refill(struct brcmf_usbdev_info *devinfo,
+                               struct brcmf_usbreq  *req);
+
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN fullmac usb driver.");
+MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN fullmac usb cards");
+MODULE_LICENSE("Dual BSD/GPL");
+
+static struct brcmf_usbdev *brcmf_usb_get_buspub(struct device *dev)
+{
+       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+       return bus_if->bus_priv.usb;
+}
+
+static struct brcmf_usbdev_info *brcmf_usb_get_businfo(struct device *dev)
+{
+       return brcmf_usb_get_buspub(dev)->devinfo;
+}
+
+#if 0
+static void
+brcmf_usb_txflowcontrol(struct brcmf_usbdev_info *devinfo, bool onoff)
+{
+       dhd_txflowcontrol(devinfo->bus_pub.netdev, 0, onoff);
+}
+#endif
+
+static int brcmf_usb_ioctl_resp_wait(struct brcmf_usbdev_info *devinfo,
+        uint *condition, bool *pending)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       int timeout = IOCTL_RESP_TIMEOUT;
+
+       /* Convert timeout in millsecond to jiffies */
+       timeout = msecs_to_jiffies(timeout);
+       /* Wait until control frame is available */
+       add_wait_queue(&devinfo->ioctl_resp_wait, &wait);
+       set_current_state(TASK_INTERRUPTIBLE);
+
+       smp_mb();
+       while (!(*condition) && (!signal_pending(current) && timeout)) {
+               timeout = schedule_timeout(timeout);
+               /* Wait until control frame is available */
+               smp_mb();
+       }
+
+       if (signal_pending(current))
+               *pending = true;
+
+       set_current_state(TASK_RUNNING);
+       remove_wait_queue(&devinfo->ioctl_resp_wait, &wait);
+
+       return timeout;
+}
+
+static int brcmf_usb_ioctl_resp_wake(struct brcmf_usbdev_info *devinfo)
+{
+       if (waitqueue_active(&devinfo->ioctl_resp_wait))
+               wake_up_interruptible(&devinfo->ioctl_resp_wait);
+
+       return 0;
+}
+
+static void
+brcmf_usb_ctl_complete(struct brcmf_usbdev_info *devinfo, int type, int status)
+{
+
+       if (unlikely(devinfo == NULL))
+               return;
+
+       if (type == BRCMF_USB_CBCTL_READ) {
+               if (status == 0)
+                       devinfo->bus_pub.stats.rx_ctlpkts++;
+               else
+                       devinfo->bus_pub.stats.rx_ctlerrs++;
+       } else if (type == BRCMF_USB_CBCTL_WRITE) {
+               if (status == 0)
+                       devinfo->bus_pub.stats.tx_ctlpkts++;
+               else
+                       devinfo->bus_pub.stats.tx_ctlerrs++;
+       }
+
+       devinfo->ctl_urb_status = status;
+       devinfo->ctl_completed = true;
+       brcmf_usb_ioctl_resp_wake(devinfo);
+}
+
+static void
+brcmf_usb_ctlread_complete(struct urb *urb)
+{
+       struct brcmf_usbdev_info *devinfo =
+               (struct brcmf_usbdev_info *)urb->context;
+
+       devinfo->ctl_urb_actual_length = urb->actual_length;
+       brcmf_usb_ctl_complete(devinfo, BRCMF_USB_CBCTL_READ,
+               urb->status);
+}
+
+static void
+brcmf_usb_ctlwrite_complete(struct urb *urb)
+{
+       struct brcmf_usbdev_info *devinfo =
+               (struct brcmf_usbdev_info *)urb->context;
+
+       brcmf_usb_ctl_complete(devinfo, BRCMF_USB_CBCTL_WRITE,
+               urb->status);
+}
+
+static int brcmf_usb_pnp(struct brcmf_usbdev_info *devinfo, uint state)
+{
+       return 0;
+}
+
+static int
+brcmf_usb_send_ctl(struct brcmf_usbdev_info *devinfo, u8 *buf, int len)
+{
+       int ret;
+       u16 size;
+
+       if (devinfo == NULL || buf == NULL ||
+           len == 0 || devinfo->ctl_urb == NULL)
+               return -EINVAL;
+
+       /* If the USB/HSIC bus in sleep state, wake it up */
+       if (devinfo->suspend_state == USBOS_SUSPEND_STATE_SUSPENDED)
+               if (brcmf_usb_pnp(devinfo, BCMFMAC_USB_PNP_RESUME) != 0) {
+                       brcmf_dbg(ERROR, "Could not Resume the bus!\n");
+                       return -EIO;
+               }
+
+       devinfo->activity = true;
+       size = len;
+       devinfo->ctl_write.wLength = cpu_to_le16p(&size);
+       devinfo->ctl_urb->transfer_buffer_length = size;
+       devinfo->ctl_urb_status = 0;
+       devinfo->ctl_urb_actual_length = 0;
+
+       usb_fill_control_urb(devinfo->ctl_urb,
+               devinfo->usbdev,
+               devinfo->ctl_out_pipe,
+               (unsigned char *) &devinfo->ctl_write,
+               buf, size,
+               (usb_complete_t)brcmf_usb_ctlwrite_complete,
+               devinfo);
+
+       ret = usb_submit_urb(devinfo->ctl_urb, GFP_ATOMIC);
+       if (ret < 0)
+               brcmf_dbg(ERROR, "usb_submit_urb failed %d\n", ret);
+
+       return ret;
+}
+
+static int
+brcmf_usb_recv_ctl(struct brcmf_usbdev_info *devinfo, u8 *buf, int len)
+{
+       int ret;
+       u16 size;
+
+       if ((devinfo == NULL) || (buf == NULL) || (len == 0)
+               || (devinfo->ctl_urb == NULL))
+               return -EINVAL;
+
+       size = len;
+       devinfo->ctl_read.wLength = cpu_to_le16p(&size);
+       devinfo->ctl_urb->transfer_buffer_length = size;
+
+       if (devinfo->rxctl_deferrespok) {
+               /* BMAC model */
+               devinfo->ctl_read.bRequestType = USB_DIR_IN
+                       | USB_TYPE_VENDOR | USB_RECIP_INTERFACE;
+               devinfo->ctl_read.bRequest = DL_DEFER_RESP_OK;
+       } else {
+               /* full dongle model */
+               devinfo->ctl_read.bRequestType = USB_DIR_IN
+                       | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+               devinfo->ctl_read.bRequest = 1;
+       }
+
+       usb_fill_control_urb(devinfo->ctl_urb,
+               devinfo->usbdev,
+               devinfo->ctl_in_pipe,
+               (unsigned char *) &devinfo->ctl_read,
+               buf, size,
+               (usb_complete_t)brcmf_usb_ctlread_complete,
+               devinfo);
+
+       ret = usb_submit_urb(devinfo->ctl_urb, GFP_ATOMIC);
+       if (ret < 0)
+               brcmf_dbg(ERROR, "usb_submit_urb failed %d\n", ret);
+
+       return ret;
+}
+
+static int brcmf_usb_tx_ctlpkt(struct device *dev, u8 *buf, u32 len)
+{
+       int err = 0;
+       int timeout = 0;
+       bool pending;
+       struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
+
+       if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) {
+               /* TODO: handle suspend/resume */
+               return -EIO;
+       }
+
+       if (test_and_set_bit(0, &devinfo->ctl_op))
+               return -EIO;
+
+       err = brcmf_usb_send_ctl(devinfo, buf, len);
+       if (err) {
+               brcmf_dbg(ERROR, "fail %d bytes: %d\n", err, len);
+               return err;
+       }
+
+       devinfo->ctl_completed = false;
+       timeout = brcmf_usb_ioctl_resp_wait(devinfo, &devinfo->ctl_completed,
+                                           &pending);
+       clear_bit(0, &devinfo->ctl_op);
+       if (!timeout) {
+               brcmf_dbg(ERROR, "Txctl wait timed out\n");
+               err = -EIO;
+       }
+       return err;
+}
+
+static int brcmf_usb_rx_ctlpkt(struct device *dev, u8 *buf, u32 len)
+{
+       int err = 0;
+       int timeout = 0;
+       bool pending;
+       struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
+
+       if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) {
+               /* TODO: handle suspend/resume */
+               return -EIO;
+       }
+       if (test_and_set_bit(0, &devinfo->ctl_op))
+               return -EIO;
+
+       err = brcmf_usb_recv_ctl(devinfo, buf, len);
+       if (err) {
+               brcmf_dbg(ERROR, "fail %d bytes: %d\n", err, len);
+               return err;
+       }
+       devinfo->ctl_completed = false;
+       timeout = brcmf_usb_ioctl_resp_wait(devinfo, &devinfo->ctl_completed,
+                                           &pending);
+       err = devinfo->ctl_urb_status;
+       clear_bit(0, &devinfo->ctl_op);
+       if (!timeout) {
+               brcmf_dbg(ERROR, "rxctl wait timed out\n");
+               err = -EIO;
+       }
+       if (!err)
+               return devinfo->ctl_urb_actual_length;
+       else
+               return err;
+}
+
+static struct brcmf_usbreq *brcmf_usb_deq(struct brcmf_usbdev_info *devinfo,
+                                         struct list_head *q)
+{
+       unsigned long flags;
+       struct brcmf_usbreq  *req;
+       spin_lock_irqsave(&devinfo->qlock, flags);
+       if (list_empty(q)) {
+               spin_unlock_irqrestore(&devinfo->qlock, flags);
+               return NULL;
+       }
+       req = list_entry(q->next, struct brcmf_usbreq, list);
+       list_del_init(q->next);
+       spin_unlock_irqrestore(&devinfo->qlock, flags);
+       return req;
+
+}
+
+static void brcmf_usb_enq(struct brcmf_usbdev_info *devinfo,
+                         struct list_head *q, struct brcmf_usbreq *req)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&devinfo->qlock, flags);
+       list_add_tail(&req->list, q);
+       spin_unlock_irqrestore(&devinfo->qlock, flags);
+}
+
+static struct brcmf_usbreq *
+brcmf_usbdev_qinit(struct list_head *q, int qsize)
+{
+       int i;
+       struct brcmf_usbreq *req, *reqs;
+
+       reqs = kzalloc(sizeof(struct brcmf_usbreq) * qsize, GFP_ATOMIC);
+       if (reqs == NULL) {
+               brcmf_dbg(ERROR, "fail to allocate memory!\n");
+               return NULL;
+       }
+       req = reqs;
+
+       for (i = 0; i < qsize; i++) {
+               req->urb = usb_alloc_urb(0, GFP_ATOMIC);
+               if (!req->urb)
+                       goto fail;
+
+               INIT_LIST_HEAD(&req->list);
+               list_add_tail(&req->list, q);
+               req++;
+       }
+       return reqs;
+fail:
+       brcmf_dbg(ERROR, "fail!\n");
+       while (!list_empty(q)) {
+               req = list_entry(q->next, struct brcmf_usbreq, list);
+               if (req && req->urb)
+                       usb_free_urb(req->urb);
+               list_del(q->next);
+       }
+       return NULL;
+
+}
+
+static void brcmf_usb_free_q(struct list_head *q, bool pending)
+{
+       struct brcmf_usbreq *req, *next;
+       int i = 0;
+       list_for_each_entry_safe(req, next, q, list) {
+               if (!req->urb) {
+                       brcmf_dbg(ERROR, "bad req\n");
+                       break;
+               }
+               i++;
+               if (pending) {
+                       usb_kill_urb(req->urb);
+               } else {
+                       usb_free_urb(req->urb);
+                       list_del_init(&req->list);
+               }
+       }
+}
+
+static void brcmf_usb_del_fromq(struct brcmf_usbdev_info *devinfo,
+                               struct brcmf_usbreq *req)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&devinfo->qlock, flags);
+       list_del_init(&req->list);
+       spin_unlock_irqrestore(&devinfo->qlock, flags);
+}
+
+
+static void brcmf_usb_tx_complete(struct urb *urb)
+{
+       struct brcmf_usbreq *req = (struct brcmf_usbreq *)urb->context;
+       struct brcmf_usbdev_info *devinfo = req->devinfo;
+
+       brcmf_usb_del_fromq(devinfo, req);
+       if (urb->status == 0)
+               devinfo->bus_pub.bus->dstats.tx_packets++;
+       else
+               devinfo->bus_pub.bus->dstats.tx_errors++;
+
+       dev_kfree_skb(req->skb);
+       req->skb = NULL;
+       brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req);
+
+}
+
+static void brcmf_usb_rx_complete(struct urb *urb)
+{
+       struct brcmf_usbreq  *req = (struct brcmf_usbreq *)urb->context;
+       struct brcmf_usbdev_info *devinfo = req->devinfo;
+       struct sk_buff *skb;
+       int ifidx = 0;
+
+       brcmf_usb_del_fromq(devinfo, req);
+       skb = req->skb;
+       req->skb = NULL;
+
+       if (urb->status == 0) {
+               devinfo->bus_pub.bus->dstats.rx_packets++;
+       } else {
+               devinfo->bus_pub.bus->dstats.rx_errors++;
+               dev_kfree_skb(skb);
+               brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req);
+               return;
+       }
+
+       if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_UP) {
+               skb_put(skb, urb->actual_length);
+               if (brcmf_proto_hdrpull(devinfo->dev, &ifidx, skb) != 0) {
+                       brcmf_dbg(ERROR, "rx protocol error\n");
+                       brcmu_pkt_buf_free_skb(skb);
+                       devinfo->bus_pub.bus->dstats.rx_errors++;
+               } else {
+                       brcmf_rx_packet(devinfo->dev, ifidx, skb);
+                       brcmf_usb_rx_refill(devinfo, req);
+               }
+       } else {
+               dev_kfree_skb(skb);
+       }
+       return;
+
+}
+
+static void brcmf_usb_rx_refill(struct brcmf_usbdev_info *devinfo,
+                               struct brcmf_usbreq  *req)
+{
+       struct sk_buff *skb;
+       int ret;
+
+       if (!req || !devinfo)
+               return;
+
+       skb = dev_alloc_skb(devinfo->bus_pub.bus_mtu);
+       if (!skb) {
+               brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req);
+               return;
+       }
+       req->skb = skb;
+
+       usb_fill_bulk_urb(req->urb, devinfo->usbdev, devinfo->rx_pipe,
+                         skb->data, skb_tailroom(skb), brcmf_usb_rx_complete,
+                         req);
+       req->urb->transfer_flags |= URB_ZERO_PACKET;
+       req->devinfo = devinfo;
+
+       ret = usb_submit_urb(req->urb, GFP_ATOMIC);
+       if (ret == 0) {
+               brcmf_usb_enq(devinfo, &devinfo->rx_postq, req);
+       } else {
+               dev_kfree_skb(req->skb);
+               req->skb = NULL;
+               brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req);
+       }
+       return;
+}
+
+static void brcmf_usb_rx_fill_all(struct brcmf_usbdev_info *devinfo)
+{
+       struct brcmf_usbreq *req;
+
+       if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) {
+               brcmf_dbg(ERROR, "bus is not up\n");
+               return;
+       }
+       while ((req = brcmf_usb_deq(devinfo, &devinfo->rx_freeq)) != NULL)
+               brcmf_usb_rx_refill(devinfo, req);
+}
+
+static void
+brcmf_usb_state_change(struct brcmf_usbdev_info *devinfo, int state)
+{
+       struct brcmf_bus *bcmf_bus = devinfo->bus_pub.bus;
+       int old_state;
+
+
+       if (devinfo->bus_pub.state == state)
+               return;
+
+       old_state = devinfo->bus_pub.state;
+       brcmf_dbg(TRACE, "dbus state change from %d to to %d\n",
+                 old_state, state);
+
+       /* Don't update state if it's PnP firmware re-download */
+       if (state != BCMFMAC_USB_STATE_PNP_FWDL) /* TODO */
+               devinfo->bus_pub.state = state;
+
+       if ((old_state  == BCMFMAC_USB_STATE_SLEEP)
+               && (state == BCMFMAC_USB_STATE_UP)) {
+               brcmf_usb_rx_fill_all(devinfo);
+       }
+
+       /* update state of upper layer */
+       if (state == BCMFMAC_USB_STATE_DOWN) {
+               brcmf_dbg(INFO, "DBUS is down\n");
+               bcmf_bus->state = BRCMF_BUS_DOWN;
+       } else {
+               brcmf_dbg(INFO, "DBUS current state=%d\n", state);
+       }
+}
+
+static void
+brcmf_usb_intr_complete(struct urb *urb)
+{
+       struct brcmf_usbdev_info *devinfo =
+                       (struct brcmf_usbdev_info *)urb->context;
+       bool killed;
+
+       if (devinfo == NULL)
+               return;
+
+       if (unlikely(urb->status)) {
+               if (devinfo->suspend_state ==
+                       USBOS_SUSPEND_STATE_SUSPEND_PENDING)
+                       killed = true;
+
+               if ((urb->status == -ENOENT && (!killed))
+                       || urb->status == -ESHUTDOWN ||
+                       urb->status == -ENODEV) {
+                       brcmf_usb_state_change(devinfo, BCMFMAC_USB_STATE_DOWN);
+               }
+       }
+
+       if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_DOWN) {
+               brcmf_dbg(ERROR, "intr cb when DBUS down, ignoring\n");
+               return;
+       }
+
+       if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_UP)
+               usb_submit_urb(devinfo->intr_urb, GFP_ATOMIC);
+}
+
+static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb)
+{
+       struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
+       struct brcmf_usbreq  *req;
+       int ret;
+
+       if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) {
+               /* TODO: handle suspend/resume */
+               return -EIO;
+       }
+
+       req = brcmf_usb_deq(devinfo, &devinfo->tx_freeq);
+       if (!req) {
+               brcmf_dbg(ERROR, "no req to send\n");
+               return -ENOMEM;
+       }
+       if (!req->urb) {
+               brcmf_dbg(ERROR, "no urb for req %p\n", req);
+               return -ENOBUFS;
+       }
+
+       req->skb = skb;
+       req->devinfo = devinfo;
+       usb_fill_bulk_urb(req->urb, devinfo->usbdev, devinfo->tx_pipe,
+                         skb->data, skb->len, brcmf_usb_tx_complete, req);
+       req->urb->transfer_flags |= URB_ZERO_PACKET;
+       ret = usb_submit_urb(req->urb, GFP_ATOMIC);
+       if (!ret) {
+               brcmf_usb_enq(devinfo, &devinfo->tx_postq, req);
+       } else {
+               req->skb = NULL;
+               brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req);
+       }
+
+       return ret;
+}
+
+
+static int brcmf_usb_up(struct device *dev)
+{
+       struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
+       u16 ifnum;
+
+       if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_UP)
+               return 0;
+
+       /* If the USB/HSIC bus in sleep state, wake it up */
+       if (devinfo->suspend_state == USBOS_SUSPEND_STATE_SUSPENDED) {
+               if (brcmf_usb_pnp(devinfo, BCMFMAC_USB_PNP_RESUME) != 0) {
+                       brcmf_dbg(ERROR, "Could not Resume the bus!\n");
+                       return -EIO;
+               }
+       }
+       devinfo->activity = true;
+
+       /* Success, indicate devinfo is fully up */
+       brcmf_usb_state_change(devinfo, BCMFMAC_USB_STATE_UP);
+
+       if (devinfo->intr_urb) {
+               int ret;
+
+               usb_fill_int_urb(devinfo->intr_urb, devinfo->usbdev,
+                       devinfo->intr_pipe,
+                       &devinfo->intr,
+                       devinfo->intr_size,
+                       (usb_complete_t)brcmf_usb_intr_complete,
+                       devinfo,
+                       devinfo->interval);
+
+               ret = usb_submit_urb(devinfo->intr_urb, GFP_ATOMIC);
+               if (ret) {
+                       brcmf_dbg(ERROR, "USB_SUBMIT_URB failed with status %d\n",
+                                 ret);
+                       return -EINVAL;
+               }
+       }
+
+       if (devinfo->ctl_urb) {
+               devinfo->ctl_in_pipe = usb_rcvctrlpipe(devinfo->usbdev, 0);
+               devinfo->ctl_out_pipe = usb_sndctrlpipe(devinfo->usbdev, 0);
+
+               ifnum = IFDESC(devinfo->usbdev, CONTROL_IF).bInterfaceNumber;
+
+               /* CTL Write */
+               devinfo->ctl_write.bRequestType =
+                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+               devinfo->ctl_write.bRequest = 0;
+               devinfo->ctl_write.wValue = cpu_to_le16(0);
+               devinfo->ctl_write.wIndex = cpu_to_le16p(&ifnum);
+
+               /* CTL Read */
+               devinfo->ctl_read.bRequestType =
+                       USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+               devinfo->ctl_read.bRequest = 1;
+               devinfo->ctl_read.wValue = cpu_to_le16(0);
+               devinfo->ctl_read.wIndex = cpu_to_le16p(&ifnum);
+       }
+       brcmf_usb_rx_fill_all(devinfo);
+       return 0;
+}
+
+static void brcmf_usb_down(struct device *dev)
+{
+       struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
+
+       if (devinfo == NULL)
+               return;
+
+       brcmf_dbg(TRACE, "enter\n");
+       if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_DOWN)
+               return;
+
+       brcmf_usb_state_change(devinfo, BCMFMAC_USB_STATE_DOWN);
+       if (devinfo->intr_urb)
+               usb_kill_urb(devinfo->intr_urb);
+
+       if (devinfo->ctl_urb)
+               usb_kill_urb(devinfo->ctl_urb);
+
+       if (devinfo->bulk_urb)
+               usb_kill_urb(devinfo->bulk_urb);
+       brcmf_usb_free_q(&devinfo->tx_postq, true);
+
+       brcmf_usb_free_q(&devinfo->rx_postq, true);
+}
+
+static int
+brcmf_usb_sync_wait(struct brcmf_usbdev_info *devinfo, u16 time)
+{
+       int ret;
+       int err = 0;
+       int ms = time;
+
+       ret = wait_event_interruptible_timeout(devinfo->wait,
+               devinfo->waitdone == true, (ms * HZ / 1000));
+
+       if ((devinfo->waitdone == false) || (devinfo->sync_urb_status)) {
+               brcmf_dbg(ERROR, "timeout(%d) or urb err=%d\n",
+                         ret, devinfo->sync_urb_status);
+               err = -EINVAL;
+       }
+       devinfo->waitdone = false;
+       return err;
+}
+
+static void
+brcmf_usb_sync_complete(struct urb *urb)
+{
+       struct brcmf_usbdev_info *devinfo =
+                       (struct brcmf_usbdev_info *)urb->context;
+
+       devinfo->waitdone = true;
+       wake_up_interruptible(&devinfo->wait);
+       devinfo->sync_urb_status = urb->status;
+}
+
+static bool brcmf_usb_dl_cmd(struct brcmf_usbdev_info *devinfo, u8 cmd,
+                            void *buffer, int buflen)
+{
+       int ret = 0;
+       char *tmpbuf;
+       u16 size;
+
+       if ((!devinfo) || (devinfo->ctl_urb == NULL))
+               return false;
+
+       tmpbuf = kmalloc(buflen, GFP_ATOMIC);
+       if (!tmpbuf)
+               return false;
+
+       size = buflen;
+       devinfo->ctl_urb->transfer_buffer_length = size;
+
+       devinfo->ctl_read.wLength = cpu_to_le16p(&size);
+       devinfo->ctl_read.bRequestType = USB_DIR_IN | USB_TYPE_VENDOR |
+               USB_RECIP_INTERFACE;
+       devinfo->ctl_read.bRequest = cmd;
+
+       usb_fill_control_urb(devinfo->ctl_urb,
+               devinfo->usbdev,
+               usb_rcvctrlpipe(devinfo->usbdev, 0),
+               (unsigned char *) &devinfo->ctl_read,
+               (void *) tmpbuf, size,
+               (usb_complete_t)brcmf_usb_sync_complete, devinfo);
+
+       ret = usb_submit_urb(devinfo->ctl_urb, GFP_ATOMIC);
+       if (ret < 0) {
+               brcmf_dbg(ERROR, "usb_submit_urb failed %d\n", ret);
+               kfree(tmpbuf);
+               return false;
+       }
+
+       ret = brcmf_usb_sync_wait(devinfo, BRCMF_USB_SYNC_TIMEOUT);
+       memcpy(buffer, tmpbuf, buflen);
+       kfree(tmpbuf);
+
+       return (ret == 0);
+}
+
+static bool
+brcmf_usb_dlneeded(struct brcmf_usbdev_info *devinfo)
+{
+       struct bootrom_id_le id;
+       u32 chipid, chiprev;
+
+       brcmf_dbg(TRACE, "enter\n");
+
+       if (devinfo == NULL)
+               return false;
+
+       /* Check if firmware downloaded already by querying runtime ID */
+       id.chip = cpu_to_le32(0xDEAD);
+       brcmf_usb_dl_cmd(devinfo, DL_GETVER, &id,
+               sizeof(struct bootrom_id_le));
+
+       chipid = le32_to_cpu(id.chip);
+       chiprev = le32_to_cpu(id.chiprev);
+
+       if ((chipid & 0x4300) == 0x4300)
+               brcmf_dbg(INFO, "chip %x rev 0x%x\n", chipid, chiprev);
+       else
+               brcmf_dbg(INFO, "chip %d rev 0x%x\n", chipid, chiprev);
+       if (chipid == BRCMF_POSTBOOT_ID) {
+               brcmf_dbg(INFO, "firmware already downloaded\n");
+               brcmf_usb_dl_cmd(devinfo, DL_RESETCFG, &id,
+                       sizeof(struct bootrom_id_le));
+               return false;
+       } else {
+               devinfo->bus_pub.devid = chipid;
+               devinfo->bus_pub.chiprev = chiprev;
+       }
+       return true;
+}
+
+static int
+brcmf_usb_resetcfg(struct brcmf_usbdev_info *devinfo)
+{
+       struct bootrom_id_le id;
+       u16 wait = 0, wait_time;
+
+       brcmf_dbg(TRACE, "enter\n");
+
+       if (devinfo == NULL)
+               return -EINVAL;
+
+       /* Give dongle chance to boot */
+       wait_time = BRCMF_USB_DLIMAGE_SPINWAIT;
+       while (wait < BRCMF_USB_DLIMAGE_LIMIT) {
+               mdelay(wait_time);
+               wait += wait_time;
+               id.chip = cpu_to_le32(0xDEAD);       /* Get the ID */
+               brcmf_usb_dl_cmd(devinfo, DL_GETVER, &id,
+                       sizeof(struct bootrom_id_le));
+               if (id.chip == cpu_to_le32(BRCMF_POSTBOOT_ID))
+                       break;
+       }
+
+       if (id.chip == cpu_to_le32(BRCMF_POSTBOOT_ID)) {
+               brcmf_dbg(INFO, "download done %d ms postboot chip 0x%x/rev 0x%x\n",
+                         wait, le32_to_cpu(id.chip), le32_to_cpu(id.chiprev));
+
+               brcmf_usb_dl_cmd(devinfo, DL_RESETCFG, &id,
+                       sizeof(struct bootrom_id_le));
+
+               /* XXX this wait may not be necessary */
+               mdelay(BRCMF_USB_RESETCFG_SPINWAIT);
+               return 0;
+       } else {
+               brcmf_dbg(ERROR, "Cannot talk to Dongle. Firmware is not UP, %d ms\n",
+                         wait);
+               return -EINVAL;
+       }
+}
+
+
+static int
+brcmf_usb_dl_send_bulk(struct brcmf_usbdev_info *devinfo, void *buffer, int len)
+{
+       int ret;
+
+       if ((devinfo == NULL) || (devinfo->bulk_urb == NULL))
+               return -EINVAL;
+
+       /* Prepare the URB */
+       usb_fill_bulk_urb(devinfo->bulk_urb, devinfo->usbdev,
+                         devinfo->tx_pipe, buffer, len,
+                         (usb_complete_t)brcmf_usb_sync_complete, devinfo);
+
+       devinfo->bulk_urb->transfer_flags |= URB_ZERO_PACKET;
+
+       ret = usb_submit_urb(devinfo->bulk_urb, GFP_ATOMIC);
+       if (ret) {
+               brcmf_dbg(ERROR, "usb_submit_urb failed %d\n", ret);
+               return ret;
+       }
+       ret = brcmf_usb_sync_wait(devinfo, BRCMF_USB_SYNC_TIMEOUT);
+       return ret;
+}
+
+static int
+brcmf_usb_dl_writeimage(struct brcmf_usbdev_info *devinfo, u8 *fw, int fwlen)
+{
+       unsigned int sendlen, sent, dllen;
+       char *bulkchunk = NULL, *dlpos;
+       struct rdl_state_le state;
+       u32 rdlstate, rdlbytes;
+       int err = 0;
+       brcmf_dbg(TRACE, "fw %p, len %d\n", fw, fwlen);
+
+       bulkchunk = kmalloc(RDL_CHUNK, GFP_ATOMIC);
+       if (bulkchunk == NULL) {
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       /* 1) Prepare USB boot loader for runtime image */
+       brcmf_usb_dl_cmd(devinfo, DL_START, &state,
+                        sizeof(struct rdl_state_le));
+
+       rdlstate = le32_to_cpu(state.state);
+       rdlbytes = le32_to_cpu(state.bytes);
+
+       /* 2) Check we are in the Waiting state */
+       if (rdlstate != DL_WAITING) {
+               brcmf_dbg(ERROR, "Failed to DL_START\n");
+               err = -EINVAL;
+               goto fail;
+       }
+       sent = 0;
+       dlpos = fw;
+       dllen = fwlen;
+
+       /* Get chip id and rev */
+       while (rdlbytes != dllen) {
+               /* Wait until the usb device reports it received all
+                * the bytes we sent */
+               if ((rdlbytes == sent) && (rdlbytes != dllen)) {
+                       if ((dllen-sent) < RDL_CHUNK)
+                               sendlen = dllen-sent;
+                       else
+                               sendlen = RDL_CHUNK;
+
+                       /* simply avoid having to send a ZLP by ensuring we
+                        * never have an even
+                        * multiple of 64
+                        */
+                       if (!(sendlen % 64))
+                               sendlen -= 4;
+
+                       /* send data */
+                       memcpy(bulkchunk, dlpos, sendlen);
+                       if (brcmf_usb_dl_send_bulk(devinfo, bulkchunk,
+                                                  sendlen)) {
+                               brcmf_dbg(ERROR, "send_bulk failed\n");
+                               err = -EINVAL;
+                               goto fail;
+                       }
+
+                       dlpos += sendlen;
+                       sent += sendlen;
+               }
+               if (!brcmf_usb_dl_cmd(devinfo, DL_GETSTATE, &state,
+                                     sizeof(struct rdl_state_le))) {
+                       brcmf_dbg(ERROR, "DL_GETSTATE Failed xxxx\n");
+                       err = -EINVAL;
+                       goto fail;
+               }
+
+               rdlstate = le32_to_cpu(state.state);
+               rdlbytes = le32_to_cpu(state.bytes);
+
+               /* restart if an error is reported */
+               if (rdlstate == DL_BAD_HDR || rdlstate == DL_BAD_CRC) {
+                       brcmf_dbg(ERROR, "Bad Hdr or Bad CRC state %d\n",
+                                 rdlstate);
+                       err = -EINVAL;
+                       goto fail;
+               }
+       }
+
+fail:
+       kfree(bulkchunk);
+       brcmf_dbg(TRACE, "err=%d\n", err);
+       return err;
+}
+
+static int brcmf_usb_dlstart(struct brcmf_usbdev_info *devinfo, u8 *fw, int len)
+{
+       int err;
+
+       brcmf_dbg(TRACE, "enter\n");
+
+       if (devinfo == NULL)
+               return -EINVAL;
+
+       if (devinfo->bus_pub.devid == 0xDEAD)
+               return -EINVAL;
+
+       err = brcmf_usb_dl_writeimage(devinfo, fw, len);
+       if (err == 0)
+               devinfo->bus_pub.state = BCMFMAC_USB_STATE_DL_DONE;
+       else
+               devinfo->bus_pub.state = BCMFMAC_USB_STATE_DL_PENDING;
+       brcmf_dbg(TRACE, "exit: err=%d\n", err);
+
+       return err;
+}
+
+static int brcmf_usb_dlrun(struct brcmf_usbdev_info *devinfo)
+{
+       struct rdl_state_le state;
+
+       brcmf_dbg(TRACE, "enter\n");
+       if (!devinfo)
+               return -EINVAL;
+
+       if (devinfo->bus_pub.devid == 0xDEAD)
+               return -EINVAL;
+
+       /* Check we are runnable */
+       brcmf_usb_dl_cmd(devinfo, DL_GETSTATE, &state,
+               sizeof(struct rdl_state_le));
+
+       /* Start the image */
+       if (state.state == cpu_to_le32(DL_RUNNABLE)) {
+               if (!brcmf_usb_dl_cmd(devinfo, DL_GO, &state,
+                       sizeof(struct rdl_state_le)))
+                       return -ENODEV;
+               if (brcmf_usb_resetcfg(devinfo))
+                       return -ENODEV;
+               /* The Dongle may go for re-enumeration. */
+       } else {
+               brcmf_dbg(ERROR, "Dongle not runnable\n");
+               return -EINVAL;
+       }
+       brcmf_dbg(TRACE, "exit\n");
+       return 0;
+}
+
+static bool brcmf_usb_chip_support(int chipid, int chiprev)
+{
+       switch(chipid) {
+       case 43235:
+       case 43236:
+       case 43238:
+               return (chiprev == 3);
+       default:
+               break;
+       }
+       return false;
+}
+
+static int
+brcmf_usb_fw_download(struct brcmf_usbdev_info *devinfo)
+{
+       int devid, chiprev;
+       int err;
+
+       brcmf_dbg(TRACE, "enter\n");
+       if (devinfo == NULL)
+               return -ENODEV;
+
+       devid = devinfo->bus_pub.devid;
+       chiprev = devinfo->bus_pub.chiprev;
+
+       if (!brcmf_usb_chip_support(devid, chiprev)) {
+               brcmf_dbg(ERROR, "unsupported chip %d rev %d\n",
+                         devid, chiprev);
+               return -EINVAL;
+       }
+
+       if (!devinfo->image) {
+               brcmf_dbg(ERROR, "No firmware!\n");
+               return -ENOENT;
+       }
+
+       err = brcmf_usb_dlstart(devinfo,
+               devinfo->image, devinfo->image_len);
+       if (err == 0)
+               err = brcmf_usb_dlrun(devinfo);
+       return err;
+}
+
+
+static void brcmf_usb_detach(const struct brcmf_usbdev *bus_pub)
+{
+       struct brcmf_usbdev_info *devinfo =
+               (struct brcmf_usbdev_info *)bus_pub;
+
+       brcmf_dbg(TRACE, "devinfo %p\n", devinfo);
+
+       /* store the image globally */
+       g_image.data = devinfo->image;
+       g_image.len = devinfo->image_len;
+
+       /* free the URBS */
+       brcmf_usb_free_q(&devinfo->rx_freeq, false);
+       brcmf_usb_free_q(&devinfo->tx_freeq, false);
+
+       usb_free_urb(devinfo->intr_urb);
+       usb_free_urb(devinfo->ctl_urb);
+       usb_free_urb(devinfo->bulk_urb);
+
+       kfree(devinfo->tx_reqs);
+       kfree(devinfo->rx_reqs);
+       kfree(devinfo);
+}
+
+#define TRX_MAGIC       0x30524448      /* "HDR0" */
+#define TRX_VERSION     1               /* Version 1 */
+#define TRX_MAX_LEN     0x3B0000        /* Max length */
+#define TRX_NO_HEADER   1               /* Do not write TRX header */
+#define TRX_MAX_OFFSET  3               /* Max number of individual files */
+#define TRX_UNCOMP_IMAGE        0x20    /* Trx contains uncompressed image */
+
+struct trx_header_le {
+       __le32 magic;           /* "HDR0" */
+       __le32 len;             /* Length of file including header */
+       __le32 crc32;           /* CRC from flag_version to end of file */
+       __le32 flag_version;    /* 0:15 flags, 16:31 version */
+       __le32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of
+                                        * header */
+};
+
+static int check_file(const u8 *headers)
+{
+       struct trx_header_le *trx;
+       int actual_len = -1;
+
+       /* Extract trx header */
+       trx = (struct trx_header_le *) headers;
+       if (trx->magic != cpu_to_le32(TRX_MAGIC))
+               return -1;
+
+       headers += sizeof(struct trx_header_le);
+
+       if (le32_to_cpu(trx->flag_version) & TRX_UNCOMP_IMAGE) {
+               actual_len = le32_to_cpu(trx->offsets[TRX_OFFSETS_DLFWLEN_IDX]);
+               return actual_len + sizeof(struct trx_header_le);
+       }
+       return -1;
+}
+
+static int brcmf_usb_get_fw(struct brcmf_usbdev_info *devinfo)
+{
+       s8 *fwname;
+       const struct firmware *fw;
+       int err;
+
+       devinfo->image = g_image.data;
+       devinfo->image_len = g_image.len;
+
+       /*
+        * if we have an image we can leave here.
+        */
+       if (devinfo->image)
+               return 0;
+
+       fwname = BRCMF_USB_43236_FW_NAME;
+
+       err = request_firmware(&fw, fwname, devinfo->dev);
+       if (!fw) {
+               brcmf_dbg(ERROR, "fail to request firmware %s\n", fwname);
+               return err;
+       }
+       if (check_file(fw->data) < 0) {
+               brcmf_dbg(ERROR, "invalid firmware %s\n", fwname);
+               return -EINVAL;
+       }
+
+       devinfo->image = kmalloc(fw->size, GFP_ATOMIC); /* plus nvram */
+       if (!devinfo->image)
+               return -ENOMEM;
+
+       memcpy(devinfo->image, fw->data, fw->size);
+       devinfo->image_len = fw->size;
+
+       release_firmware(fw);
+       return 0;
+}
+
+
+static
+struct brcmf_usbdev *brcmf_usb_attach(int nrxq, int ntxq, struct device *dev)
+{
+       struct brcmf_usbdev_info *devinfo;
+
+       devinfo = kzalloc(sizeof(struct brcmf_usbdev_info), GFP_ATOMIC);
+       if (devinfo == NULL)
+               return NULL;
+
+       devinfo->bus_pub.nrxq = nrxq;
+       devinfo->rx_low_watermark = nrxq / 2;
+       devinfo->bus_pub.devinfo = devinfo;
+       devinfo->bus_pub.ntxq = ntxq;
+
+       /* flow control when too many tx urbs posted */
+       devinfo->tx_low_watermark = ntxq / 4;
+       devinfo->tx_high_watermark = devinfo->tx_low_watermark * 3;
+       devinfo->dev = dev;
+       devinfo->usbdev = usbdev_probe_info.usb;
+       devinfo->tx_pipe = usbdev_probe_info.tx_pipe;
+       devinfo->rx_pipe = usbdev_probe_info.rx_pipe;
+       devinfo->rx_pipe2 = usbdev_probe_info.rx_pipe2;
+       devinfo->intr_pipe = usbdev_probe_info.intr_pipe;
+
+       devinfo->interval = usbdev_probe_info.interval;
+       devinfo->intr_size = usbdev_probe_info.intr_size;
+
+       memcpy(&devinfo->probe_info, &usbdev_probe_info,
+               sizeof(struct brcmf_usb_probe_info));
+       devinfo->bus_pub.bus_mtu = BRCMF_USB_MAX_PKT_SIZE;
+
+       /* Initialize other structure content */
+       init_waitqueue_head(&devinfo->ioctl_resp_wait);
+
+       /* Initialize the spinlocks */
+       spin_lock_init(&devinfo->qlock);
+
+       INIT_LIST_HEAD(&devinfo->rx_freeq);
+       INIT_LIST_HEAD(&devinfo->rx_postq);
+
+       INIT_LIST_HEAD(&devinfo->tx_freeq);
+       INIT_LIST_HEAD(&devinfo->tx_postq);
+
+       devinfo->rx_reqs = brcmf_usbdev_qinit(&devinfo->rx_freeq, nrxq);
+       if (!devinfo->rx_reqs)
+               goto error;
+
+       devinfo->tx_reqs = brcmf_usbdev_qinit(&devinfo->tx_freeq, ntxq);
+       if (!devinfo->tx_reqs)
+               goto error;
+
+       devinfo->intr_urb = usb_alloc_urb(0, GFP_ATOMIC);
+       if (!devinfo->intr_urb) {
+               brcmf_dbg(ERROR, "usb_alloc_urb (intr) failed\n");
+               goto error;
+       }
+       devinfo->ctl_urb = usb_alloc_urb(0, GFP_ATOMIC);
+       if (!devinfo->ctl_urb) {
+               brcmf_dbg(ERROR, "usb_alloc_urb (ctl) failed\n");
+               goto error;
+       }
+       devinfo->rxctl_deferrespok = 0;
+
+       devinfo->bulk_urb = usb_alloc_urb(0, GFP_ATOMIC);
+       if (!devinfo->bulk_urb) {
+               brcmf_dbg(ERROR, "usb_alloc_urb (bulk) failed\n");
+               goto error;
+       }
+
+       init_waitqueue_head(&devinfo->wait);
+       if (!brcmf_usb_dlneeded(devinfo))
+               return &devinfo->bus_pub;
+
+       brcmf_dbg(TRACE, "start fw downloading\n");
+       if (brcmf_usb_get_fw(devinfo))
+               goto error;
+
+       if (brcmf_usb_fw_download(devinfo))
+               goto error;
+
+       return &devinfo->bus_pub;
+
+error:
+       brcmf_dbg(ERROR, "failed!\n");
+       brcmf_usb_detach(&devinfo->bus_pub);
+       return NULL;
+}
+
+static int brcmf_usb_probe_cb(struct device *dev, const char *desc,
+                               u32 bustype, u32 hdrlen)
+{
+       struct brcmf_bus *bus = NULL;
+       struct brcmf_usbdev *bus_pub = NULL;
+       int ret;
+
+
+       bus_pub = brcmf_usb_attach(BRCMF_USB_NRXQ, BRCMF_USB_NTXQ, dev);
+       if (!bus_pub) {
+               ret = -ENODEV;
+               goto fail;
+       }
+
+       bus = kzalloc(sizeof(struct brcmf_bus), GFP_ATOMIC);
+       if (!bus) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       bus_pub->bus = bus;
+       bus->brcmf_bus_txdata = brcmf_usb_tx;
+       bus->brcmf_bus_init = brcmf_usb_up;
+       bus->brcmf_bus_stop = brcmf_usb_down;
+       bus->brcmf_bus_txctl = brcmf_usb_tx_ctlpkt;
+       bus->brcmf_bus_rxctl = brcmf_usb_rx_ctlpkt;
+       bus->type = bustype;
+       bus->bus_priv.usb = bus_pub;
+       dev_set_drvdata(dev, bus);
+
+       /* Attach to the common driver interface */
+       ret = brcmf_attach(hdrlen, dev);
+       if (ret) {
+               brcmf_dbg(ERROR, "dhd_attach failed\n");
+               goto fail;
+       }
+
+       ret = brcmf_bus_start(dev);
+       if (ret == -ENOLINK) {
+               brcmf_dbg(ERROR, "dongle is not responding\n");
+               brcmf_detach(dev);
+               goto fail;
+       }
+
+       /* add interface and open for business */
+       ret = brcmf_add_if(dev, 0, "wlan%d", NULL);
+       if (ret) {
+               brcmf_dbg(ERROR, "Add primary net device interface failed!!\n");
+               brcmf_detach(dev);
+               goto fail;
+       }
+
+       return 0;
+fail:
+       /* Release resources in reverse order */
+       if (bus_pub)
+               brcmf_usb_detach(bus_pub);
+       kfree(bus);
+       return ret;
+}
+
+static void
+brcmf_usb_disconnect_cb(struct brcmf_usbdev *bus_pub)
+{
+       if (!bus_pub)
+               return;
+       brcmf_dbg(TRACE, "enter: bus_pub %p\n", bus_pub);
+
+       brcmf_detach(bus_pub->devinfo->dev);
+       kfree(bus_pub->bus);
+       brcmf_usb_detach(bus_pub);
+
+}
+
+static int
+brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+       int ep;
+       struct usb_endpoint_descriptor *endpoint;
+       int ret = 0;
+       struct usb_device *usb = interface_to_usbdev(intf);
+       int num_of_eps;
+       u8 endpoint_num;
+
+       brcmf_dbg(TRACE, "enter\n");
+
+       usbdev_probe_info.usb = usb;
+       usbdev_probe_info.intf = intf;
+
+       if (id != NULL) {
+               usbdev_probe_info.vid = id->idVendor;
+               usbdev_probe_info.pid = id->idProduct;
+       }
+
+       usb_set_intfdata(intf, &usbdev_probe_info);
+
+       /* Check that the device supports only one configuration */
+       if (usb->descriptor.bNumConfigurations != 1) {
+               ret = -1;
+               goto fail;
+       }
+
+       if (usb->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) {
+               ret = -1;
+               goto fail;
+       }
+
+       /*
+        * Only the BDC interface configuration is supported:
+        *      Device class: USB_CLASS_VENDOR_SPEC
+        *      if0 class: USB_CLASS_VENDOR_SPEC
+        *      if0/ep0: control
+        *      if0/ep1: bulk in
+        *      if0/ep2: bulk out (ok if swapped with bulk in)
+        */
+       if (CONFIGDESC(usb)->bNumInterfaces != 1) {
+               ret = -1;
+               goto fail;
+       }
+
+       /* Check interface */
+       if (IFDESC(usb, CONTROL_IF).bInterfaceClass != USB_CLASS_VENDOR_SPEC ||
+           IFDESC(usb, CONTROL_IF).bInterfaceSubClass != 2 ||
+           IFDESC(usb, CONTROL_IF).bInterfaceProtocol != 0xff) {
+               brcmf_dbg(ERROR, "invalid control interface: class %d, subclass %d, proto %d\n",
+                         IFDESC(usb, CONTROL_IF).bInterfaceClass,
+                         IFDESC(usb, CONTROL_IF).bInterfaceSubClass,
+                         IFDESC(usb, CONTROL_IF).bInterfaceProtocol);
+               ret = -1;
+               goto fail;
+       }
+
+       /* Check control endpoint */
+       endpoint = &IFEPDESC(usb, CONTROL_IF, 0);
+       if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+               != USB_ENDPOINT_XFER_INT) {
+               brcmf_dbg(ERROR, "invalid control endpoint %d\n",
+                         endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
+               ret = -1;
+               goto fail;
+       }
+
+       endpoint_num = endpoint->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+       usbdev_probe_info.intr_pipe = usb_rcvintpipe(usb, endpoint_num);
+
+       usbdev_probe_info.rx_pipe = 0;
+       usbdev_probe_info.rx_pipe2 = 0;
+       usbdev_probe_info.tx_pipe = 0;
+       num_of_eps = IFDESC(usb, BULK_IF).bNumEndpoints - 1;
+
+       /* Check data endpoints and get pipes */
+       for (ep = 1; ep <= num_of_eps; ep++) {
+               endpoint = &IFEPDESC(usb, BULK_IF, ep);
+               if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
+                   USB_ENDPOINT_XFER_BULK) {
+                       brcmf_dbg(ERROR, "invalid data endpoint %d\n", ep);
+                       ret = -1;
+                       goto fail;
+               }
+
+               endpoint_num = endpoint->bEndpointAddress &
+                              USB_ENDPOINT_NUMBER_MASK;
+               if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+                       == USB_DIR_IN) {
+                       if (!usbdev_probe_info.rx_pipe) {
+                               usbdev_probe_info.rx_pipe =
+                                       usb_rcvbulkpipe(usb, endpoint_num);
+                       } else {
+                               usbdev_probe_info.rx_pipe2 =
+                                       usb_rcvbulkpipe(usb, endpoint_num);
+                       }
+               } else {
+                       usbdev_probe_info.tx_pipe =
+                                       usb_sndbulkpipe(usb, endpoint_num);
+               }
+       }
+
+       /* Allocate interrupt URB and data buffer */
+       /* RNDIS says 8-byte intr, our old drivers used 4-byte */
+       if (IFEPDESC(usb, CONTROL_IF, 0).wMaxPacketSize == cpu_to_le16(16))
+               usbdev_probe_info.intr_size = 8;
+       else
+               usbdev_probe_info.intr_size = 4;
+
+       usbdev_probe_info.interval = IFEPDESC(usb, CONTROL_IF, 0).bInterval;
+
+       usbdev_probe_info.device_speed = usb->speed;
+       if (usb->speed == USB_SPEED_HIGH)
+               brcmf_dbg(INFO, "Broadcom high speed USB wireless device detected\n");
+       else
+               brcmf_dbg(INFO, "Broadcom full speed USB wireless device detected\n");
+
+       ret = brcmf_usb_probe_cb(&usb->dev, "", USB_BUS, 0);
+       if (ret)
+               goto fail;
+
+       /* Success */
+       return 0;
+
+fail:
+       brcmf_dbg(ERROR, "failed with errno %d\n", ret);
+       usb_set_intfdata(intf, NULL);
+       return ret;
+
+}
+
+static void
+brcmf_usb_disconnect(struct usb_interface *intf)
+{
+       struct usb_device *usb = interface_to_usbdev(intf);
+
+       brcmf_dbg(TRACE, "enter\n");
+       brcmf_usb_disconnect_cb(brcmf_usb_get_buspub(&usb->dev));
+       usb_set_intfdata(intf, NULL);
+}
+
+/*
+ *     only need to signal the bus being down and update the suspend state.
+ */
+static int brcmf_usb_suspend(struct usb_interface *intf, pm_message_t state)
+{
+       struct usb_device *usb = interface_to_usbdev(intf);
+       struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev);
+
+       brcmf_dbg(TRACE, "enter\n");
+       devinfo->bus_pub.state = BCMFMAC_USB_STATE_DOWN;
+       devinfo->suspend_state = USBOS_SUSPEND_STATE_SUSPENDED;
+       return 0;
+}
+
+/*
+ *     mark suspend state active and crank up the bus.
+ */
+static int brcmf_usb_resume(struct usb_interface *intf)
+{
+       struct usb_device *usb = interface_to_usbdev(intf);
+       struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev);
+
+       brcmf_dbg(TRACE, "enter\n");
+       devinfo->suspend_state = USBOS_SUSPEND_STATE_DEVICE_ACTIVE;
+       brcmf_bus_start(&usb->dev);
+       return 0;
+}
+
+#define BRCMF_USB_VENDOR_ID_BROADCOM   0x0a5c
+#define BRCMF_USB_DEVICE_ID_43236      0xbd17
+#define BRCMF_USB_DEVICE_ID_BCMFW      0x0bdc
+
+static struct usb_device_id brcmf_usb_devid_table[] = {
+       { USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_43236) },
+       /* special entry for device with firmware loaded and running */
+       { USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_BCMFW) },
+       { }
+};
+MODULE_DEVICE_TABLE(usb, brcmf_usb_devid_table);
+MODULE_FIRMWARE(BRCMF_USB_43236_FW_NAME);
+
+/* TODO: suspend and resume entries */
+static struct usb_driver brcmf_usbdrvr = {
+       .name = KBUILD_MODNAME,
+       .probe = brcmf_usb_probe,
+       .disconnect = brcmf_usb_disconnect,
+       .id_table = brcmf_usb_devid_table,
+       .suspend = brcmf_usb_suspend,
+       .resume = brcmf_usb_resume,
+       .supports_autosuspend = 1
+};
+
+void brcmf_usb_exit(void)
+{
+       usb_deregister(&brcmf_usbdrvr);
+       kfree(g_image.data);
+       g_image.data = NULL;
+       g_image.len = 0;
+}
+
+void brcmf_usb_init(void)
+{
+       usb_register(&brcmf_usbdrvr);
+}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.h b/drivers/net/wireless/brcm80211/brcmfmac/usb.h
new file mode 100644 (file)
index 0000000..acfa5e8
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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_USB_H
+#define BRCMFMAC_USB_H
+
+enum brcmf_usb_state {
+       BCMFMAC_USB_STATE_DL_PENDING,
+       BCMFMAC_USB_STATE_DL_DONE,
+       BCMFMAC_USB_STATE_UP,
+       BCMFMAC_USB_STATE_DOWN,
+       BCMFMAC_USB_STATE_PNP_FWDL,
+       BCMFMAC_USB_STATE_DISCONNECT,
+       BCMFMAC_USB_STATE_SLEEP
+};
+
+enum brcmf_usb_pnp_state {
+       BCMFMAC_USB_PNP_DISCONNECT,
+       BCMFMAC_USB_PNP_SLEEP,
+       BCMFMAC_USB_PNP_RESUME,
+};
+
+struct brcmf_stats {
+       u32 tx_ctlpkts;
+       u32 tx_ctlerrs;
+       u32 rx_ctlpkts;
+       u32 rx_ctlerrs;
+};
+
+struct brcmf_usbdev {
+       struct brcmf_bus *bus;
+       struct brcmf_usbdev_info *devinfo;
+       enum brcmf_usb_state state;
+       struct brcmf_stats stats;
+       int ntxq, nrxq, rxsize;
+       u32 bus_mtu;
+       int devid;
+       int chiprev; /* chip revsion number */
+};
+
+/* IO Request Block (IRB) */
+struct brcmf_usbreq {
+       struct list_head list;
+       struct brcmf_usbdev_info *devinfo;
+       struct urb *urb;
+       struct sk_buff  *skb;
+};
+
+#endif /* BRCMFMAC_USB_H */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb_rdl.h b/drivers/net/wireless/brcm80211/brcmfmac/usb_rdl.h
new file mode 100644 (file)
index 0000000..0a35c51
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * 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 _USB_RDL_H
+#define _USB_RDL_H
+
+/* Control messages: bRequest values */
+#define DL_GETSTATE    0       /* returns the rdl_state_t struct */
+#define DL_CHECK_CRC   1       /* currently unused */
+#define DL_GO          2       /* execute downloaded image */
+#define DL_START       3       /* initialize dl state */
+#define DL_REBOOT      4       /* reboot the device in 2 seconds */
+#define DL_GETVER      5       /* returns the bootrom_id_t struct */
+#define DL_GO_PROTECTED        6       /* execute the downloaded code and set reset
+                                * event to occur in 2 seconds.  It is the
+                                * responsibility of the downloaded code to
+                                * clear this event
+                                */
+#define DL_EXEC                7       /* jump to a supplied address */
+#define DL_RESETCFG    8       /* To support single enum on dongle
+                                * - Not used by bootloader
+                                */
+#define DL_DEFER_RESP_OK 9     /* Potentially defer the response to setup
+                                * if resp unavailable
+                                */
+
+/* states */
+#define DL_WAITING     0       /* waiting to rx first pkt */
+#define DL_READY       1       /* hdr was good, waiting for more of the
+                                * compressed image */
+#define DL_BAD_HDR     2       /* hdr was corrupted */
+#define DL_BAD_CRC     3       /* compressed image was corrupted */
+#define DL_RUNNABLE    4       /* download was successful,waiting for go cmd */
+#define DL_START_FAIL  5       /* failed to initialize correctly */
+#define DL_NVRAM_TOOBIG        6       /* host specified nvram data exceeds DL_NVRAM
+                                * value */
+#define DL_IMAGE_TOOBIG        7       /* download image too big (exceeds DATA_START
+                                *  for rdl) */
+
+struct rdl_state_le {
+       __le32 state;
+       __le32 bytes;
+};
+
+struct bootrom_id_le {
+       __le32 chip;    /* Chip id */
+       __le32 chiprev; /* Chip rev */
+       __le32 ramsize; /* Size of  RAM */
+       __le32 remapbase;       /* Current remap base address */
+       __le32 boardtype;       /* Type of board */
+       __le32 boardrev;        /* Board revision */
+};
+
+#define RDL_CHUNK      1500  /* size of each dl transfer */
+
+#define TRX_OFFSETS_DLFWLEN_IDX        0
+#define TRX_OFFSETS_JUMPTO_IDX 1
+#define TRX_OFFSETS_NVM_LEN_IDX        2
+
+#define TRX_OFFSETS_DLBASE_IDX  0
+
+#endif  /* _USB_RDL_H */
index 74c95a597950426f10fc1029d4f0b2faea31ce38..15d7f00513be9e052f8b915782542c7b9f574ef9 100644 (file)
@@ -1376,7 +1376,7 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
        memset(&join_params, 0, sizeof(join_params));
        join_params_size = sizeof(join_params.ssid_le);
 
-       ssid.SSID_len = min_t(u32, sizeof(ssid.SSID), sme->ssid_len);
+       ssid.SSID_len = min_t(u32, sizeof(ssid.SSID), (u32)sme->ssid_len);
        memcpy(&join_params.ssid_le.SSID, sme->ssid, ssid.SSID_len);
        memcpy(&ssid.SSID, sme->ssid, ssid.SSID_len);
        join_params.ssid_le.SSID_len = cpu_to_le32(ssid.SSID_len);
@@ -3297,7 +3297,9 @@ static struct brcmf_cfg80211_event_q *brcmf_deq_event(
 }
 
 /*
-** push event to tail of the queue
+*      push event to tail of the queue
+*
+*      remark: this function may not sleep as it is called in atomic context.
 */
 
 static s32
@@ -3306,17 +3308,18 @@ brcmf_enq_event(struct brcmf_cfg80211_priv *cfg_priv, u32 event,
 {
        struct brcmf_cfg80211_event_q *e;
        s32 err = 0;
+       ulong flags;
 
-       e = kzalloc(sizeof(struct brcmf_cfg80211_event_q), GFP_KERNEL);
+       e = kzalloc(sizeof(struct brcmf_cfg80211_event_q), GFP_ATOMIC);
        if (!e)
                return -ENOMEM;
 
        e->etype = event;
        memcpy(&e->emsg, msg, sizeof(struct brcmf_event_msg));
 
-       spin_lock_irq(&cfg_priv->evt_q_lock);
+       spin_lock_irqsave(&cfg_priv->evt_q_lock, flags);
        list_add_tail(&e->evt_q_list, &cfg_priv->evt_q_list);
-       spin_unlock_irq(&cfg_priv->evt_q_lock);
+       spin_unlock_irqrestore(&cfg_priv->evt_q_lock, flags);
 
        return err;
 }
index dbee69620a90412c0cbcdab4b113cb8c1b10f816..95b5902bc4b3a3241f68cde20434b8592ba71ebc 100644 (file)
@@ -959,14 +959,13 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
                if (supr_status) {
                        update_rate = false;
                        if (supr_status == TX_STATUS_SUPR_BADCH) {
-                               wiphy_err(wiphy, "%s: Pkt tx suppressed, "
-                                         "illegal channel possibly %d\n",
+                               wiphy_err(wiphy,
+                                         "%s: Pkt tx suppressed, illegal channel possibly %d\n",
                                          __func__, CHSPEC_CHANNEL(
                                          wlc->default_bss->chanspec));
                        } else {
                                if (supr_status != TX_STATUS_SUPR_FRAG)
-                                       wiphy_err(wiphy, "%s:"
-                                                 "supr_status 0x%x\n",
+                                       wiphy_err(wiphy, "%s: supr_status 0x%x\n",
                                                  __func__, supr_status);
                        }
                        /* no need to retry for badch; will fail again */
@@ -988,9 +987,8 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
                        }
                } else if (txs->phyerr) {
                        update_rate = false;
-                       wiphy_err(wiphy, "wl%d: ampdu tx phy "
-                                 "error (0x%x)\n", wlc->pub->unit,
-                                 txs->phyerr);
+                       wiphy_err(wiphy, "%s: ampdu tx phy error (0x%x)\n",
+                                 __func__, txs->phyerr);
 
                        if (brcm_msg_level & LOG_ERROR_VAL) {
                                brcmu_prpkt("txpkt (AMPDU)", p);
@@ -1018,10 +1016,10 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
                ack_recd = false;
                if (ba_recd) {
                        bindex = MODSUB_POW2(seq, start_seq, SEQNUM_MAX);
-                       BCMMSG(wlc->wiphy, "tid %d seq %d,"
-                               " start_seq %d, bindex %d set %d, index %d\n",
-                               tid, seq, start_seq, bindex,
-                               isset(bitmap, bindex), index);
+                       BCMMSG(wiphy,
+                              "tid %d seq %d, start_seq %d, bindex %d set %d, index %d\n",
+                              tid, seq, start_seq, bindex,
+                              isset(bitmap, bindex), index);
                        /* if acked then clear bit and free packet */
                        if ((bindex < AMPDU_TX_BA_MAX_WSIZE)
                            && isset(bitmap, bindex)) {
index c8427978d09e503adb58264d2b6e5e2d1d9ef143..569ab8abd2a1c2d132eb1fbe273d09f077d68c3e 100644 (file)
@@ -1136,8 +1136,8 @@ static int brcms_suspend(struct bcma_device *pdev)
        hw = bcma_get_drvdata(pdev);
        wl = hw->priv;
        if (!wl) {
-               wiphy_err(wl->wiphy,
-                         "brcms_suspend: bcma_get_drvdata failed\n");
+               pr_err("%s: %s: no driver private struct!\n", KBUILD_MODNAME,
+                      __func__);
                return -ENODEV;
        }
 
@@ -1169,25 +1169,31 @@ static struct bcma_driver brcms_bcma_driver = {
 /**
  * This is the main entry point for the brcmsmac driver.
  *
- * This function determines if a device pointed to by pdev is a WL device,
- * and if so, performs a brcms_attach() on it.
- *
+ * This function is scheduled upon module initialization and
+ * does the driver registration, which result in brcms_bcma_probe()
+ * call resulting in the driver bringup.
  */
-static int __init brcms_module_init(void)
+static void brcms_driver_init(struct work_struct *work)
 {
-       int error = -ENODEV;
+       int error;
+
+       error = bcma_driver_register(&brcms_bcma_driver);
+       if (error)
+               pr_err("%s: register returned %d\n", __func__, error);
+}
+
+static DECLARE_WORK(brcms_driver_work, brcms_driver_init);
 
+static int __init brcms_module_init(void)
+{
 #ifdef DEBUG
        if (msglevel != 0xdeadbeef)
                brcm_msg_level = msglevel;
-#endif                         /* DEBUG */
-
-       error = bcma_driver_register(&brcms_bcma_driver);
-       pr_err("%s: register returned %d\n", __func__, error);
-       if (!error)
-               return 0;
+#endif
+       if (!schedule_work(&brcms_driver_work))
+               return -EBUSY;
 
-       return error;
+       return 0;
 }
 
 /**
@@ -1199,6 +1205,7 @@ static int __init brcms_module_init(void)
  */
 static void __exit brcms_module_exit(void)
 {
+       cancel_work_sync(&brcms_driver_work);
        bcma_driver_unregister(&brcms_bcma_driver);
 }
 
index 90331dd22e5d29b11c19123a771e25f9f6765a1d..231ddf4a674f8523e850d50ea73160f5d0b8d069 100644 (file)
@@ -2901,7 +2901,6 @@ brcms_b_read_objmem(struct brcms_hardware *wlc_hw, uint offset, u32 sel)
                objoff += 2;
 
        return bcma_read16(core, objoff);
-;
 }
 
 static void
index 62eedd82534d6cfea04c087b4ded9c599e98ad16..39095741fd05f948a9538d1b2740db7530112ccc 100644 (file)
@@ -17824,8 +17824,6 @@ static void wlc_phy_txpwrctrl_pwr_setup_nphy(struct brcms_phy *pi)
        if (pi->sh->sromrev < 4) {
                idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_2g;
                idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_2g;
-               target_pwr_qtrdbm[0] = 13 * 4;
-               target_pwr_qtrdbm[1] = 13 * 4;
                a1[0] = -424;
                a1[1] = -424;
                b0[0] = 5612;
@@ -17839,10 +17837,6 @@ static void wlc_phy_txpwrctrl_pwr_setup_nphy(struct brcms_phy *pi)
                case WL_CHAN_FREQ_RANGE_2G:
                        idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_2g;
                        idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_2g;
-                       target_pwr_qtrdbm[0] =
-                               pi->nphy_pwrctrl_info[0].max_pwr_2g;
-                       target_pwr_qtrdbm[1] =
-                               pi->nphy_pwrctrl_info[1].max_pwr_2g;
                        a1[0] = pi->nphy_pwrctrl_info[0].pwrdet_2g_a1;
                        a1[1] = pi->nphy_pwrctrl_info[1].pwrdet_2g_a1;
                        b0[0] = pi->nphy_pwrctrl_info[0].pwrdet_2g_b0;
@@ -17853,10 +17847,6 @@ static void wlc_phy_txpwrctrl_pwr_setup_nphy(struct brcms_phy *pi)
                case WL_CHAN_FREQ_RANGE_5GL:
                        idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_5g;
                        idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_5g;
-                       target_pwr_qtrdbm[0] =
-                               pi->nphy_pwrctrl_info[0].max_pwr_5gl;
-                       target_pwr_qtrdbm[1] =
-                               pi->nphy_pwrctrl_info[1].max_pwr_5gl;
                        a1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gl_a1;
                        a1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gl_a1;
                        b0[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gl_b0;
@@ -17867,10 +17857,6 @@ static void wlc_phy_txpwrctrl_pwr_setup_nphy(struct brcms_phy *pi)
                case WL_CHAN_FREQ_RANGE_5GM:
                        idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_5g;
                        idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_5g;
-                       target_pwr_qtrdbm[0] =
-                               pi->nphy_pwrctrl_info[0].max_pwr_5gm;
-                       target_pwr_qtrdbm[1] =
-                               pi->nphy_pwrctrl_info[1].max_pwr_5gm;
                        a1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gm_a1;
                        a1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gm_a1;
                        b0[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gm_b0;
@@ -17881,10 +17867,6 @@ static void wlc_phy_txpwrctrl_pwr_setup_nphy(struct brcms_phy *pi)
                case WL_CHAN_FREQ_RANGE_5GH:
                        idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_5g;
                        idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_5g;
-                       target_pwr_qtrdbm[0] =
-                               pi->nphy_pwrctrl_info[0].max_pwr_5gh;
-                       target_pwr_qtrdbm[1] =
-                               pi->nphy_pwrctrl_info[1].max_pwr_5gh;
                        a1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gh_a1;
                        a1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gh_a1;
                        b0[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gh_b0;
@@ -17895,8 +17877,6 @@ static void wlc_phy_txpwrctrl_pwr_setup_nphy(struct brcms_phy *pi)
                default:
                        idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_2g;
                        idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_2g;
-                       target_pwr_qtrdbm[0] = 13 * 4;
-                       target_pwr_qtrdbm[1] = 13 * 4;
                        a1[0] = -424;
                        a1[1] = -424;
                        b0[0] = 5612;
@@ -17907,6 +17887,7 @@ static void wlc_phy_txpwrctrl_pwr_setup_nphy(struct brcms_phy *pi)
                }
        }
 
+       /* use the provided transmit power */
        target_pwr_qtrdbm[0] = (s8) pi->tx_power_max;
        target_pwr_qtrdbm[1] = (s8) pi->tx_power_max;
 
@@ -19989,12 +19970,11 @@ static void wlc_phy_radio_init_2057(struct brcms_phy *pi)
                switch (pi->pubpi.radiorev) {
                case 5:
 
-                       if (pi->pubpi.radiover == 0x0)
+                       if (NREV_IS(pi->pubpi.phy_rev, 8))
                                regs_2057_ptr = regs_2057_rev5;
-                       else if (pi->pubpi.radiover == 0x1)
+                       else if (NREV_IS(pi->pubpi.phy_rev, 9))
                                regs_2057_ptr = regs_2057_rev5v1;
-                       else
-                               break;
+                       break;
 
                case 7:
 
index 5637436430381a12d6322fbac9e9be1ec27de276..b96f4b9d74bdb2af5bab3403323fab243a8db0d7 100644 (file)
@@ -621,7 +621,7 @@ static inline void cpu_to_le16_buf(u16 *buf, uint nwords)
 /*
  * convert binary srom data into linked list of srom variable items.
  */
-static void
+static int
 _initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list)
 {
        struct brcms_srom_list_head *entry;
@@ -638,6 +638,9 @@ _initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list)
 
        /* first store the srom revision */
        entry = kzalloc(sizeof(struct brcms_srom_list_head), GFP_KERNEL);
+       if (!entry)
+               return -ENOMEM;
+
        entry->varid = BRCMS_SROM_REV;
        entry->var_type = BRCMS_SROM_UNUMBER;
        entry->uval = sromrev;
@@ -715,6 +718,8 @@ _initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list)
 
                entry = kzalloc(sizeof(struct brcms_srom_list_head) +
                                extra_space, GFP_KERNEL);
+               if (!entry)
+                       return -ENOMEM;
                entry->varid = id;
                entry->var_type = type;
                if (flags & SRFL_ETHADDR) {
@@ -754,6 +759,8 @@ _initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list)
                        entry =
                            kzalloc(sizeof(struct brcms_srom_list_head),
                                    GFP_KERNEL);
+                       if (!entry)
+                               return -ENOMEM;
                        entry->varid = srv->varid+p;
                        entry->var_type = BRCMS_SROM_UNUMBER;
                        entry->uval = val;
@@ -761,6 +768,7 @@ _initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list)
                }
                pb += psz;
        }
+       return 0;
 }
 
 /*
@@ -906,7 +914,9 @@ int srom_var_init(struct si_pub *sih)
                INIT_LIST_HEAD(&sii->var_list);
 
                /* parse SROM into name=value pairs. */
-               _initvars_srom_pci(sromrev, srom, &sii->var_list);
+               err = _initvars_srom_pci(sromrev, srom, &sii->var_list);
+               if (err)
+                       srom_free_vars(sih);
        }
 
 errout:
index e847737ccc9d122783bdf7d337bf2f32e734a605..f0551f807f6987717f5022152c481e95c6db9607 100644 (file)
@@ -298,8 +298,6 @@ static const char *command_types[] = {
 };
 #endif
 
-#define WEXT_USECHANNELS 1
-
 static const long ipw2100_frequencies[] = {
        2412, 2417, 2422, 2427,
        2432, 2437, 2442, 2447,
@@ -309,13 +307,6 @@ static const long ipw2100_frequencies[] = {
 
 #define FREQ_COUNT     ARRAY_SIZE(ipw2100_frequencies)
 
-static const long ipw2100_rates_11b[] = {
-       1000000,
-       2000000,
-       5500000,
-       11000000
-};
-
 static struct ieee80211_rate ipw2100_bg_rates[] = {
        { .bitrate = 10 },
        { .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
@@ -323,7 +314,7 @@ static struct ieee80211_rate ipw2100_bg_rates[] = {
        { .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
 };
 
-#define RATE_COUNT ARRAY_SIZE(ipw2100_rates_11b)
+#define RATE_COUNT ARRAY_SIZE(ipw2100_bg_rates)
 
 /* Pre-decl until we get the code solid and then we can clean it up */
 static void ipw2100_tx_send_commands(struct ipw2100_priv *priv);
@@ -6893,7 +6884,7 @@ static int ipw2100_wx_get_range(struct net_device *dev,
        range->num_bitrates = RATE_COUNT;
 
        for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++) {
-               range->bitrate[i] = ipw2100_rates_11b[i];
+               range->bitrate[i] = ipw2100_bg_rates[i].bitrate * 100 * 1000;
        }
 
        range->min_rts = MIN_RTS_THRESHOLD;
@@ -8105,61 +8096,41 @@ static int ipw2100_wx_get_crc_check(struct net_device *dev,
 #endif                         /* CONFIG_IPW2100_MONITOR */
 
 static iw_handler ipw2100_wx_handlers[] = {
-       NULL,                   /* SIOCSIWCOMMIT */
-       ipw2100_wx_get_name,    /* SIOCGIWNAME */
-       NULL,                   /* SIOCSIWNWID */
-       NULL,                   /* SIOCGIWNWID */
-       ipw2100_wx_set_freq,    /* SIOCSIWFREQ */
-       ipw2100_wx_get_freq,    /* SIOCGIWFREQ */
-       ipw2100_wx_set_mode,    /* SIOCSIWMODE */
-       ipw2100_wx_get_mode,    /* SIOCGIWMODE */
-       NULL,                   /* SIOCSIWSENS */
-       NULL,                   /* SIOCGIWSENS */
-       NULL,                   /* SIOCSIWRANGE */
-       ipw2100_wx_get_range,   /* SIOCGIWRANGE */
-       NULL,                   /* SIOCSIWPRIV */
-       NULL,                   /* SIOCGIWPRIV */
-       NULL,                   /* SIOCSIWSTATS */
-       NULL,                   /* SIOCGIWSTATS */
-       NULL,                   /* SIOCSIWSPY */
-       NULL,                   /* SIOCGIWSPY */
-       NULL,                   /* SIOCGIWTHRSPY */
-       NULL,                   /* SIOCWIWTHRSPY */
-       ipw2100_wx_set_wap,     /* SIOCSIWAP */
-       ipw2100_wx_get_wap,     /* SIOCGIWAP */
-       ipw2100_wx_set_mlme,    /* SIOCSIWMLME */
-       NULL,                   /* SIOCGIWAPLIST -- deprecated */
-       ipw2100_wx_set_scan,    /* SIOCSIWSCAN */
-       ipw2100_wx_get_scan,    /* SIOCGIWSCAN */
-       ipw2100_wx_set_essid,   /* SIOCSIWESSID */
-       ipw2100_wx_get_essid,   /* SIOCGIWESSID */
-       ipw2100_wx_set_nick,    /* SIOCSIWNICKN */
-       ipw2100_wx_get_nick,    /* SIOCGIWNICKN */
-       NULL,                   /* -- hole -- */
-       NULL,                   /* -- hole -- */
-       ipw2100_wx_set_rate,    /* SIOCSIWRATE */
-       ipw2100_wx_get_rate,    /* SIOCGIWRATE */
-       ipw2100_wx_set_rts,     /* SIOCSIWRTS */
-       ipw2100_wx_get_rts,     /* SIOCGIWRTS */
-       ipw2100_wx_set_frag,    /* SIOCSIWFRAG */
-       ipw2100_wx_get_frag,    /* SIOCGIWFRAG */
-       ipw2100_wx_set_txpow,   /* SIOCSIWTXPOW */
-       ipw2100_wx_get_txpow,   /* SIOCGIWTXPOW */
-       ipw2100_wx_set_retry,   /* SIOCSIWRETRY */
-       ipw2100_wx_get_retry,   /* SIOCGIWRETRY */
-       ipw2100_wx_set_encode,  /* SIOCSIWENCODE */
-       ipw2100_wx_get_encode,  /* SIOCGIWENCODE */
-       ipw2100_wx_set_power,   /* SIOCSIWPOWER */
-       ipw2100_wx_get_power,   /* SIOCGIWPOWER */
-       NULL,                   /* -- hole -- */
-       NULL,                   /* -- hole -- */
-       ipw2100_wx_set_genie,   /* SIOCSIWGENIE */
-       ipw2100_wx_get_genie,   /* SIOCGIWGENIE */
-       ipw2100_wx_set_auth,    /* SIOCSIWAUTH */
-       ipw2100_wx_get_auth,    /* SIOCGIWAUTH */
-       ipw2100_wx_set_encodeext,       /* SIOCSIWENCODEEXT */
-       ipw2100_wx_get_encodeext,       /* SIOCGIWENCODEEXT */
-       NULL,                   /* SIOCSIWPMKSA */
+       IW_HANDLER(SIOCGIWNAME, ipw2100_wx_get_name),
+       IW_HANDLER(SIOCSIWFREQ, ipw2100_wx_set_freq),
+       IW_HANDLER(SIOCGIWFREQ, ipw2100_wx_get_freq),
+       IW_HANDLER(SIOCSIWMODE, ipw2100_wx_set_mode),
+       IW_HANDLER(SIOCGIWMODE, ipw2100_wx_get_mode),
+       IW_HANDLER(SIOCGIWRANGE, ipw2100_wx_get_range),
+       IW_HANDLER(SIOCSIWAP, ipw2100_wx_set_wap),
+       IW_HANDLER(SIOCGIWAP, ipw2100_wx_get_wap),
+       IW_HANDLER(SIOCSIWMLME, ipw2100_wx_set_mlme),
+       IW_HANDLER(SIOCSIWSCAN, ipw2100_wx_set_scan),
+       IW_HANDLER(SIOCGIWSCAN, ipw2100_wx_get_scan),
+       IW_HANDLER(SIOCSIWESSID, ipw2100_wx_set_essid),
+       IW_HANDLER(SIOCGIWESSID, ipw2100_wx_get_essid),
+       IW_HANDLER(SIOCSIWNICKN, ipw2100_wx_set_nick),
+       IW_HANDLER(SIOCGIWNICKN, ipw2100_wx_get_nick),
+       IW_HANDLER(SIOCSIWRATE, ipw2100_wx_set_rate),
+       IW_HANDLER(SIOCGIWRATE, ipw2100_wx_get_rate),
+       IW_HANDLER(SIOCSIWRTS, ipw2100_wx_set_rts),
+       IW_HANDLER(SIOCGIWRTS, ipw2100_wx_get_rts),
+       IW_HANDLER(SIOCSIWFRAG, ipw2100_wx_set_frag),
+       IW_HANDLER(SIOCGIWFRAG, ipw2100_wx_get_frag),
+       IW_HANDLER(SIOCSIWTXPOW, ipw2100_wx_set_txpow),
+       IW_HANDLER(SIOCGIWTXPOW, ipw2100_wx_get_txpow),
+       IW_HANDLER(SIOCSIWRETRY, ipw2100_wx_set_retry),
+       IW_HANDLER(SIOCGIWRETRY, ipw2100_wx_get_retry),
+       IW_HANDLER(SIOCSIWENCODE, ipw2100_wx_set_encode),
+       IW_HANDLER(SIOCGIWENCODE, ipw2100_wx_get_encode),
+       IW_HANDLER(SIOCSIWPOWER, ipw2100_wx_set_power),
+       IW_HANDLER(SIOCGIWPOWER, ipw2100_wx_get_power),
+       IW_HANDLER(SIOCSIWGENIE, ipw2100_wx_set_genie),
+       IW_HANDLER(SIOCGIWGENIE, ipw2100_wx_get_genie),
+       IW_HANDLER(SIOCSIWAUTH, ipw2100_wx_set_auth),
+       IW_HANDLER(SIOCGIWAUTH, ipw2100_wx_get_auth),
+       IW_HANDLER(SIOCSIWENCODEEXT, ipw2100_wx_set_encodeext),
+       IW_HANDLER(SIOCGIWENCODEEXT, ipw2100_wx_get_encodeext),
 };
 
 #define IPW2100_PRIV_SET_MONITOR       SIOCIWFIRSTPRIV
index ecb561d7a7a07016e8de302f8e21b0b800f573dd..66e84ec0eb55445ee16ff20dfe58038629343569 100644 (file)
@@ -27,8 +27,6 @@
 #ifndef __ipw2200_h__
 #define __ipw2200_h__
 
-#define WEXT_USECHANNELS 1
-
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
index 5e1a19fd354dcd4ffcb3629642996556d2d0c346..f767dd106b09e53d4de130e38b22d0e5490a84a8 100644 (file)
@@ -503,3 +503,9 @@ il3945_ucode_general_stats_read(struct file *file, char __user *user_buf,
        kfree(buf);
        return ret;
 }
+
+const struct il_debugfs_ops il3945_debugfs_ops = {
+       .rx_stats_read = il3945_ucode_rx_stats_read,
+       .tx_stats_read = il3945_ucode_tx_stats_read,
+       .general_stats_read = il3945_ucode_general_stats_read,
+};
index aa8f5c0bd64234fb64c3358faeeb81725b48643e..0ccc934a35bb2846822f0ef6e9ce30e3962d1420 100644 (file)
@@ -573,7 +573,6 @@ il3945_tx_skb(struct il_priv *il, struct sk_buff *skb)
        len = (u16) skb->len;
        tx_cmd->len = cpu_to_le16(len);
 
-       il_dbg_log_tx_data_frame(il, len, hdr);
        il_update_stats(il, true, fc, len);
        tx_cmd->tx_flags &= ~TX_CMD_FLG_ANT_A_MSK;
        tx_cmd->tx_flags &= ~TX_CMD_FLG_ANT_B_MSK;
@@ -616,7 +615,7 @@ il3945_tx_skb(struct il_priv *il, struct sk_buff *skb)
 
        /* Add buffer containing Tx command and MAC(!) header to TFD's
         * first entry */
-       il->ops->lib->txq_attach_buf_to_tfd(il, txq, txcmd_phys, len, 1, 0);
+       il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, len, 1, 0);
 
        /* Set up TFD's 2nd entry to point directly to remainder of skb,
         * if any (802.11 null frames have no payload). */
@@ -625,8 +624,8 @@ il3945_tx_skb(struct il_priv *il, struct sk_buff *skb)
                phys_addr =
                    pci_map_single(il->pci_dev, skb->data + hdr_len, len,
                                   PCI_DMA_TODEVICE);
-               il->ops->lib->txq_attach_buf_to_tfd(il, txq, phys_addr, len, 0,
-                                                   U32_PAD(len));
+               il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, len, 0,
+                                              U32_PAD(len));
        }
 
        /* Tell device the write idx *just past* this latest filled TFD */
@@ -810,16 +809,16 @@ il3945_hdl_card_state(struct il_priv *il, struct il_rx_buf *rxb)
        _il_wr(il, CSR_UCODE_DRV_GP1_SET, CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
 
        if (flags & HW_CARD_DISABLED)
-               set_bit(S_RF_KILL_HW, &il->status);
+               set_bit(S_RFKILL, &il->status);
        else
-               clear_bit(S_RF_KILL_HW, &il->status);
+               clear_bit(S_RFKILL, &il->status);
 
        il_scan_cancel(il);
 
-       if ((test_bit(S_RF_KILL_HW, &status) !=
-            test_bit(S_RF_KILL_HW, &il->status)))
+       if ((test_bit(S_RFKILL, &status) !=
+            test_bit(S_RFKILL, &il->status)))
                wiphy_rfkill_set_hw_state(il->hw->wiphy,
-                                         test_bit(S_RF_KILL_HW, &il->status));
+                                         test_bit(S_RFKILL, &il->status));
        else
                wake_up(&il->wait_command_queue);
 }
@@ -2167,7 +2166,7 @@ il3945_alive_start(struct il_priv *il)
        D_INFO("RFKILL status: 0x%x\n", rfkill);
 
        if (rfkill & 0x1) {
-               clear_bit(S_RF_KILL_HW, &il->status);
+               clear_bit(S_RFKILL, &il->status);
                /* if RFKILL is not on, then wait for thermal
                 * sensor in adapter to kick in */
                while (il3945_hw_get_temperature(il) == 0) {
@@ -2179,7 +2178,7 @@ il3945_alive_start(struct il_priv *il)
                        D_INFO("Thermal calibration took %dus\n",
                               thermal_spin * 10);
        } else
-               set_bit(S_RF_KILL_HW, &il->status);
+               set_bit(S_RFKILL, &il->status);
 
        /* After the ALIVE response, we can send commands to 3945 uCode */
        set_bit(S_ALIVE, &il->status);
@@ -2273,12 +2272,8 @@ __il3945_down(struct il_priv *il)
         * clear all bits but the RF Kill bits and return */
        if (!il_is_init(il)) {
                il->status =
-                   test_bit(S_RF_KILL_HW,
-                            &il->
-                            status) << S_RF_KILL_HW |
-                   test_bit(S_GEO_CONFIGURED,
-                            &il->
-                            status) << S_GEO_CONFIGURED |
+                   test_bit(S_RFKILL, &il->status) << S_RFKILL |
+                   test_bit(S_GEO_CONFIGURED, &il->status) << S_GEO_CONFIGURED |
                    test_bit(S_EXIT_PENDING, &il->status) << S_EXIT_PENDING;
                goto exit;
        }
@@ -2286,25 +2281,30 @@ __il3945_down(struct il_priv *il)
        /* ...otherwise clear out all the status bits but the RF Kill
         * bit and continue taking the NIC down. */
        il->status &=
-           test_bit(S_RF_KILL_HW,
-                    &il->status) << S_RF_KILL_HW | test_bit(S_GEO_CONFIGURED,
-                                                            &il->
-                                                            status) <<
-           S_GEO_CONFIGURED | test_bit(S_FW_ERROR,
-                                       &il->
-                                       status) << S_FW_ERROR |
+           test_bit(S_RFKILL, &il->status) << S_RFKILL |
+           test_bit(S_GEO_CONFIGURED, &il->status) << S_GEO_CONFIGURED |
+           test_bit(S_FW_ERROR, &il->status) << S_FW_ERROR |
            test_bit(S_EXIT_PENDING, &il->status) << S_EXIT_PENDING;
 
+       /*
+        * We disabled and synchronized interrupt, and priv->mutex is taken, so
+        * here is the only thread which will program device registers, but
+        * still have lockdep assertions, so we are taking reg_lock.
+        */
+       spin_lock_irq(&il->reg_lock);
+       /* FIXME: il_grab_nic_access if rfkill is off ? */
+
        il3945_hw_txq_ctx_stop(il);
        il3945_hw_rxq_stop(il);
-
        /* Power-down device's busmaster DMA clocks */
-       il_wr_prph(il, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT);
+       _il_wr_prph(il, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT);
        udelay(5);
-
        /* Stop the device, and put it in low power state */
-       il_apm_stop(il);
+       _il_apm_stop(il);
+
+       spin_unlock_irq(&il->reg_lock);
 
+       il3945_hw_txq_ctx_free(il);
 exit:
        memset(&il->card_alive, 0, sizeof(struct il_alive_resp));
 
@@ -2371,9 +2371,9 @@ __il3945_up(struct il_priv *il)
 
        /* If platform's RF_KILL switch is NOT set to KILL */
        if (_il_rd(il, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
-               clear_bit(S_RF_KILL_HW, &il->status);
+               clear_bit(S_RFKILL, &il->status);
        else {
-               set_bit(S_RF_KILL_HW, &il->status);
+               set_bit(S_RFKILL, &il->status);
                IL_WARN("Radio disabled by HW RF Kill switch\n");
                return -ENODEV;
        }
@@ -2405,7 +2405,7 @@ __il3945_up(struct il_priv *il)
               il->ucode_data.len);
 
        /* We return success when we resume from suspend and rf_kill is on. */
-       if (test_bit(S_RF_KILL_HW, &il->status))
+       if (test_bit(S_RFKILL, &il->status))
                return 0;
 
        for (i = 0; i < MAX_HW_RESTARTS; i++) {
@@ -2413,7 +2413,7 @@ __il3945_up(struct il_priv *il)
                /* load bootstrap state machine,
                 * load bootstrap program into processor's memory,
                 * prepare to load the "initialize" uCode */
-               rc = il->ops->lib->load_ucode(il);
+               rc = il->ops->load_ucode(il);
 
                if (rc) {
                        IL_ERR("Unable to set up bootstrap uCode: %d\n", rc);
@@ -2485,15 +2485,15 @@ il3945_rfkill_poll(struct work_struct *data)
 {
        struct il_priv *il =
            container_of(data, struct il_priv, _3945.rfkill_poll.work);
-       bool old_rfkill = test_bit(S_RF_KILL_HW, &il->status);
+       bool old_rfkill = test_bit(S_RFKILL, &il->status);
        bool new_rfkill =
            !(_il_rd(il, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW);
 
        if (new_rfkill != old_rfkill) {
                if (new_rfkill)
-                       set_bit(S_RF_KILL_HW, &il->status);
+                       set_bit(S_RFKILL, &il->status);
                else
-                       clear_bit(S_RF_KILL_HW, &il->status);
+                       clear_bit(S_RFKILL, &il->status);
 
                wiphy_rfkill_set_hw_state(il->hw->wiphy, new_rfkill);
 
@@ -2782,10 +2782,9 @@ il3945_mac_start(struct ieee80211_hw *hw)
        struct il_priv *il = hw->priv;
        int ret;
 
-       D_MAC80211("enter\n");
-
        /* we should be verifying the device is ready to be opened */
        mutex_lock(&il->mutex);
+       D_MAC80211("enter\n");
 
        /* fetch ucode file from disk, alloc and copy to bus-master buffers ...
         * ucode filename and max sizes are card-specific. */
@@ -2941,15 +2940,19 @@ il3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
         * hardware will then not attempt to decrypt the frames.
         */
        if (vif->type == NL80211_IFTYPE_ADHOC &&
-           !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
+           !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
+               D_MAC80211("leave - IBSS RSN\n");
                return -EOPNOTSUPP;
+       }
 
        static_key = !il_is_associated(il);
 
        if (!static_key) {
                sta_id = il_sta_id_or_broadcast(il, sta);
-               if (sta_id == IL_INVALID_STATION)
+               if (sta_id == IL_INVALID_STATION) {
+                       D_MAC80211("leave - station not found\n");
                        return -EINVAL;
+               }
        }
 
        mutex_lock(&il->mutex);
@@ -2974,8 +2977,8 @@ il3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                ret = -EINVAL;
        }
 
+       D_MAC80211("leave ret %d\n", ret);
        mutex_unlock(&il->mutex);
-       D_MAC80211("leave\n");
 
        return ret;
 }
@@ -2990,9 +2993,8 @@ il3945_mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
        bool is_ap = vif->type == NL80211_IFTYPE_STATION;
        u8 sta_id;
 
-       D_INFO("received request to add station %pM\n", sta->addr);
        mutex_lock(&il->mutex);
-       D_INFO("proceeding to add station %pM\n", sta->addr);
+       D_INFO("station %pM\n", sta->addr);
        sta_priv->common.sta_id = IL_INVALID_STATION;
 
        ret = il_add_station_common(il, sta->addr, is_ap, sta, &sta_id);
@@ -3098,11 +3100,9 @@ il3945_store_debug_level(struct device *d, struct device_attribute *attr,
        ret = strict_strtoul(buf, 0, &val);
        if (ret)
                IL_INFO("%s is not in hex or decimal form.\n", buf);
-       else {
+       else
                il->debug_level = val;
-               if (il_alloc_traffic_mem(il))
-                       IL_ERR("Not enough memory to generate traffic log\n");
-       }
+
        return strnlen(buf, count);
 }
 
@@ -3619,12 +3619,12 @@ il3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        D_INFO("*** LOAD DRIVER ***\n");
        il->cfg = cfg;
        il->ops = &il3945_ops;
+#ifdef CONFIG_IWLEGACY_DEBUGFS
+       il->debugfs_ops = &il3945_debugfs_ops;
+#endif
        il->pci_dev = pdev;
        il->inta_mask = CSR_INI_SET_MASK;
 
-       if (il_alloc_traffic_mem(il))
-               IL_ERR("Not enough memory to generate traffic log\n");
-
        /***************************
         * 2. Initializing PCI bus
         * *************************/
@@ -3655,7 +3655,7 @@ il3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        /***********************
         * 3. Read REV Register
         * ********************/
-       il->hw_base = pci_iomap(pdev, 0, 0);
+       il->hw_base = pci_ioremap_bar(pdev, 0);
        if (!il->hw_base) {
                err = -ENODEV;
                goto out_pci_release_regions;
@@ -3669,7 +3669,7 @@ il3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
         * PCI Tx retries from interfering with C3 CPU state */
        pci_write_config_byte(pdev, 0x41, 0x00);
 
-       /* these spin locks will be used in apm_ops.init and EEPROM access
+       /* these spin locks will be used in apm_init and EEPROM access
         * we should init now
         */
        spin_lock_init(&il->reg_lock);
@@ -3780,14 +3780,13 @@ out_unset_hw_params:
 out_eeprom_free:
        il_eeprom_free(il);
 out_iounmap:
-       pci_iounmap(pdev, il->hw_base);
+       iounmap(il->hw_base);
 out_pci_release_regions:
        pci_release_regions(pdev);
 out_pci_disable_device:
        pci_set_drvdata(pdev, NULL);
        pci_disable_device(pdev);
 out_ieee80211_free_hw:
-       il_free_traffic_mem(il);
        ieee80211_free_hw(il->hw);
 out:
        return err;
@@ -3855,12 +3854,11 @@ il3945_pci_remove(struct pci_dev *pdev)
         * until now... */
        destroy_workqueue(il->workqueue);
        il->workqueue = NULL;
-       il_free_traffic_mem(il);
 
        free_irq(pdev->irq, il);
        pci_disable_msi(pdev);
 
-       pci_iounmap(pdev, il->hw_base);
+       iounmap(il->hw_base);
        pci_release_regions(pdev);
        pci_disable_device(pdev);
        pci_set_drvdata(pdev, NULL);
index 6c1ae5fab8999ee4cebb6c8c489d0cef019cc8c9..456f32da6b26e2a1f5d60241e20739c7f423b825 100644 (file)
@@ -57,10 +57,6 @@ il3945_send_led_cmd(struct il_priv *il, struct il_led_cmd *led_cmd)
        return il_send_cmd(il, &cmd);
 }
 
-const struct il_led_ops il3945_led_ops = {
-       .cmd = il3945_send_led_cmd,
-};
-
 #define IL_DECLARE_RATE_INFO(r, ip, in, rp, rn, pp, np)    \
        [RATE_##r##M_IDX] = { RATE_##r##M_PLCP,   \
                                    RATE_##r##M_IEEE,   \
@@ -303,7 +299,7 @@ il3945_tx_queue_reclaim(struct il_priv *il, int txq_id, int idx)
                skb = txq->skbs[txq->q.read_ptr];
                ieee80211_tx_status_irqsafe(il->hw, skb);
                txq->skbs[txq->q.read_ptr] = NULL;
-               il->ops->lib->txq_free_tfd(il, txq);
+               il->ops->txq_free_tfd(il, txq);
        }
 
        if (il_queue_space(q) > q->low_mark && txq_id >= 0 &&
@@ -577,8 +573,6 @@ il3945_hdl_rx(struct il_priv *il, struct il_rx_buf *rxb)
                network_packet ? '*' : ' ', le16_to_cpu(rx_hdr->channel),
                rx_status.signal, rx_status.signal, rx_status.rate_idx);
 
-       il_dbg_log_rx_data_frame(il, le16_to_cpu(rx_hdr->len), header);
-
        if (network_packet) {
                il->_3945.last_beacon_time =
                    le32_to_cpu(rx_end->beacon_timestamp);
@@ -796,7 +790,6 @@ il3945_rx_init(struct il_priv *il, struct il_rx_queue *rxq)
 static int
 il3945_tx_reset(struct il_priv *il)
 {
-
        /* bypass mode */
        il_wr_prph(il, ALM_SCD_MODE_REG, 0x2);
 
@@ -833,8 +826,7 @@ il3945_tx_reset(struct il_priv *il)
 static int
 il3945_txq_ctx_reset(struct il_priv *il)
 {
-       int rc;
-       int txq_id, slots_num;
+       int rc, txq_id;
 
        il3945_hw_txq_ctx_free(il);
 
@@ -850,10 +842,7 @@ il3945_txq_ctx_reset(struct il_priv *il)
 
        /* Tx queue(s) */
        for (txq_id = 0; txq_id < il->hw_params.max_txq_num; txq_id++) {
-               slots_num =
-                   (txq_id ==
-                    IL39_CMD_QUEUE_NUM) ? TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
-               rc = il_tx_queue_init(il, &il->txq[txq_id], slots_num, txq_id);
+               rc = il_tx_queue_init(il, txq_id);
                if (rc) {
                        IL_ERR("Tx %d queue init failed\n", txq_id);
                        goto error;
@@ -958,12 +947,11 @@ il3945_hw_nic_init(struct il_priv *il)
        struct il_rx_queue *rxq = &il->rxq;
 
        spin_lock_irqsave(&il->lock, flags);
-       il->ops->lib->apm_ops.init(il);
+       il3945_apm_init(il);
        spin_unlock_irqrestore(&il->lock, flags);
 
        il3945_set_pwr_vmain(il);
-
-       il->ops->lib->apm_ops.config(il);
+       il3945_nic_config(il);
 
        /* Allocate the RX queue, or reset if it is already allocated */
        if (!rxq->bd) {
@@ -1014,7 +1002,7 @@ il3945_hw_txq_ctx_free(struct il_priv *il)
                                il_tx_queue_free(il, txq_id);
 
        /* free tx queue structure */
-       il_txq_mem(il);
+       il_free_txq_mem(il);
 }
 
 void
@@ -1023,18 +1011,17 @@ il3945_hw_txq_ctx_stop(struct il_priv *il)
        int txq_id;
 
        /* stop SCD */
-       il_wr_prph(il, ALM_SCD_MODE_REG, 0);
-       il_wr_prph(il, ALM_SCD_TXFACT_REG, 0);
+       _il_wr_prph(il, ALM_SCD_MODE_REG, 0);
+       _il_wr_prph(il, ALM_SCD_TXFACT_REG, 0);
 
        /* reset TFD queues */
        for (txq_id = 0; txq_id < il->hw_params.max_txq_num; txq_id++) {
-               il_wr(il, FH39_TCSR_CONFIG(txq_id), 0x0);
-               il_poll_bit(il, FH39_TSSR_TX_STATUS,
-                           FH39_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(txq_id),
-                           1000);
+               _il_wr(il, FH39_TCSR_CONFIG(txq_id), 0x0);
+               _il_poll_bit(il, FH39_TSSR_TX_STATUS,
+                            FH39_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(txq_id),
+                            FH39_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(txq_id),
+                            1000);
        }
-
-       il3945_hw_txq_ctx_free(il);
 }
 
 /**
@@ -1613,7 +1600,7 @@ il3945_hw_reg_comp_txpower_temp(struct il_priv *il)
        }
 
        /* send Txpower command for current channel to ucode */
-       return il->ops->lib->send_tx_power(il);
+       return il->ops->send_tx_power(il);
 }
 
 int
@@ -2183,12 +2170,14 @@ il3945_txpower_set_from_eeprom(struct il_priv *il)
 int
 il3945_hw_rxq_stop(struct il_priv *il)
 {
-       int rc;
+       int ret;
 
-       il_wr(il, FH39_RCSR_CONFIG(0), 0);
-       rc = il_poll_bit(il, FH39_RSSR_STATUS,
-                        FH39_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000);
-       if (rc < 0)
+       _il_wr(il, FH39_RCSR_CONFIG(0), 0);
+       ret = _il_poll_bit(il, FH39_RSSR_STATUS,
+                          FH39_RSSR_CHNL0_RX_STATUS_CHNL_IDLE,
+                          FH39_RSSR_CHNL0_RX_STATUS_CHNL_IDLE,
+                          1000);
+       if (ret < 0)
                IL_ERR("Can't stop Rx DMA.\n");
 
        return 0;
@@ -2630,65 +2619,31 @@ il3945_load_bsm(struct il_priv *il)
        return 0;
 }
 
-static struct il_hcmd_ops il3945_hcmd = {
-       .rxon_assoc = il3945_send_rxon_assoc,
-       .commit_rxon = il3945_commit_rxon,
-};
-
-static struct il_lib_ops il3945_lib = {
+const struct il_ops il3945_ops = {
        .txq_attach_buf_to_tfd = il3945_hw_txq_attach_buf_to_tfd,
        .txq_free_tfd = il3945_hw_txq_free_tfd,
        .txq_init = il3945_hw_tx_queue_init,
        .load_ucode = il3945_load_bsm,
        .dump_nic_error_log = il3945_dump_nic_error_log,
-       .apm_ops = {
-                   .init = il3945_apm_init,
-                   .config = il3945_nic_config,
-                   },
-       .eeprom_ops = {
-                      .regulatory_bands = {
-                                           EEPROM_REGULATORY_BAND_1_CHANNELS,
-                                           EEPROM_REGULATORY_BAND_2_CHANNELS,
-                                           EEPROM_REGULATORY_BAND_3_CHANNELS,
-                                           EEPROM_REGULATORY_BAND_4_CHANNELS,
-                                           EEPROM_REGULATORY_BAND_5_CHANNELS,
-                                           EEPROM_REGULATORY_BAND_NO_HT40,
-                                           EEPROM_REGULATORY_BAND_NO_HT40,
-                                           },
-                      .acquire_semaphore = il3945_eeprom_acquire_semaphore,
-                      .release_semaphore = il3945_eeprom_release_semaphore,
-                      },
+       .apm_init = il3945_apm_init,
        .send_tx_power = il3945_send_tx_power,
        .is_valid_rtc_data_addr = il3945_hw_valid_rtc_data_addr,
+       .eeprom_acquire_semaphore = il3945_eeprom_acquire_semaphore,
+       .eeprom_release_semaphore = il3945_eeprom_release_semaphore,
 
-#ifdef CONFIG_IWLEGACY_DEBUGFS
-       .debugfs_ops = {
-                       .rx_stats_read = il3945_ucode_rx_stats_read,
-                       .tx_stats_read = il3945_ucode_tx_stats_read,
-                       .general_stats_read = il3945_ucode_general_stats_read,
-                       },
-#endif
-};
-
-static const struct il_legacy_ops il3945_legacy_ops = {
-       .post_associate = il3945_post_associate,
-       .config_ap = il3945_config_ap,
-       .manage_ibss_station = il3945_manage_ibss_station,
-};
+       .rxon_assoc = il3945_send_rxon_assoc,
+       .commit_rxon = il3945_commit_rxon,
 
-static struct il_hcmd_utils_ops il3945_hcmd_utils = {
        .get_hcmd_size = il3945_get_hcmd_size,
        .build_addsta_hcmd = il3945_build_addsta_hcmd,
        .request_scan = il3945_request_scan,
        .post_scan = il3945_post_scan,
-};
 
-const struct il_ops il3945_ops = {
-       .lib = &il3945_lib,
-       .hcmd = &il3945_hcmd,
-       .utils = &il3945_hcmd_utils,
-       .led = &il3945_led_ops,
-       .legacy = &il3945_legacy_ops,
+       .post_associate = il3945_post_associate,
+       .config_ap = il3945_config_ap,
+       .manage_ibss_station = il3945_manage_ibss_station,
+
+       .send_led_cmd = il3945_send_led_cmd,
 };
 
 static struct il_cfg il3945_bg_cfg = {
@@ -2707,7 +2662,17 @@ static struct il_cfg il3945_bg_cfg = {
        .set_l0s = false,
        .use_bsm = true,
        .led_compensation = 64,
-       .wd_timeout = IL_DEF_WD_TIMEOUT
+       .wd_timeout = IL_DEF_WD_TIMEOUT,
+
+       .regulatory_bands = {
+               EEPROM_REGULATORY_BAND_1_CHANNELS,
+               EEPROM_REGULATORY_BAND_2_CHANNELS,
+               EEPROM_REGULATORY_BAND_3_CHANNELS,
+               EEPROM_REGULATORY_BAND_4_CHANNELS,
+               EEPROM_REGULATORY_BAND_5_CHANNELS,
+               EEPROM_REGULATORY_BAND_NO_HT40,
+               EEPROM_REGULATORY_BAND_NO_HT40,
+       },
 };
 
 static struct il_cfg il3945_abg_cfg = {
@@ -2726,7 +2691,17 @@ static struct il_cfg il3945_abg_cfg = {
        .set_l0s = false,
        .use_bsm = true,
        .led_compensation = 64,
-       .wd_timeout = IL_DEF_WD_TIMEOUT
+       .wd_timeout = IL_DEF_WD_TIMEOUT,
+
+       .regulatory_bands = {
+               EEPROM_REGULATORY_BAND_1_CHANNELS,
+               EEPROM_REGULATORY_BAND_2_CHANNELS,
+               EEPROM_REGULATORY_BAND_3_CHANNELS,
+               EEPROM_REGULATORY_BAND_4_CHANNELS,
+               EEPROM_REGULATORY_BAND_5_CHANNELS,
+               EEPROM_REGULATORY_BAND_NO_HT40,
+               EEPROM_REGULATORY_BAND_NO_HT40,
+       },
 };
 
 DEFINE_PCI_DEVICE_TABLE(il3945_hw_card_ids) = {
index c00a8d30b6feb7324707b1a9aa7102578a6095b5..1d45075e0d5b51a21e234b44c4603bb0c0481ce6 100644 (file)
@@ -595,13 +595,7 @@ struct il3945_tfd {
 } __packed;
 
 #ifdef CONFIG_IWLEGACY_DEBUGFS
-ssize_t il3945_ucode_rx_stats_read(struct file *file, char __user *user_buf,
-                                  size_t count, loff_t *ppos);
-ssize_t il3945_ucode_tx_stats_read(struct file *file, char __user *user_buf,
-                                  size_t count, loff_t *ppos);
-ssize_t il3945_ucode_general_stats_read(struct file *file,
-                                       char __user *user_buf, size_t count,
-                                       loff_t *ppos);
+extern const struct il_debugfs_ops il3945_debugfs_ops;
 #endif
 
 #endif
index fe9171506a91c32fcc2e61811cb3cabb85572c0d..e78bdefb8952ca605ae8eb1d3243274b80bdd63f 100644 (file)
@@ -79,18 +79,6 @@ struct stats_general_data {
        u32 beacon_energy_c;
 };
 
-void
-il4965_calib_free_results(struct il_priv *il)
-{
-       int i;
-
-       for (i = 0; i < IL_CALIB_MAX; i++) {
-               kfree(il->calib_results[i].buf);
-               il->calib_results[i].buf = NULL;
-               il->calib_results[i].buf_len = 0;
-       }
-}
-
 /*****************************************************************************
  * RUNTIME calibrations framework
  *****************************************************************************/
@@ -923,8 +911,8 @@ il4965_chain_noise_calibration(struct il_priv *il, void *stat_resp)
        /* Some power changes may have been made during the calibration.
         * Update and commit the RXON
         */
-       if (il->ops->lib->update_chain_flags)
-               il->ops->lib->update_chain_flags(il);
+       if (il->ops->update_chain_flags)
+               il->ops->update_chain_flags(il);
 
        data->state = IL_CHAIN_NOISE_DONE;
        il_power_update_mode(il, false);
index 98ec39f56ba34c107f5a6fd8498e8d9166afaea8..c8153fc64f7465b8bfb87ac8700840cb08e3ebc4 100644 (file)
@@ -744,3 +744,9 @@ il4965_ucode_general_stats_read(struct file *file, char __user *user_buf,
        kfree(buf);
        return ret;
 }
+
+const struct il_debugfs_ops il4965_debugfs_ops = {
+       .rx_stats_read = il4965_ucode_rx_stats_read,
+       .tx_stats_read = il4965_ucode_tx_stats_read,
+       .general_stats_read = il4965_ucode_general_stats_read,
+};
index 235812ac6a0dae0d30116f1737d5c47d40c7bb8d..7b54dbb338be6127bec123f8414cd3231eaabb00 100644 (file)
@@ -199,18 +199,14 @@ il4965_hw_nic_init(struct il_priv *il)
        struct il_rx_queue *rxq = &il->rxq;
        int ret;
 
-       /* nic_init */
        spin_lock_irqsave(&il->lock, flags);
-       il->ops->lib->apm_ops.init(il);
-
+       il_apm_init(il);
        /* Set interrupt coalescing calibration timer to default (512 usecs) */
        il_write8(il, CSR_INT_COALESCING, IL_HOST_INT_CALIB_TIMEOUT_DEF);
-
        spin_unlock_irqrestore(&il->lock, flags);
 
        il4965_set_pwr_vmain(il);
-
-       il->ops->lib->apm_ops.config(il);
+       il4965_nic_config(il);
 
        /* Allocate the RX queue, or reset if it is already allocated */
        if (!rxq->bd) {
@@ -445,11 +441,15 @@ il4965_rx_queue_free(struct il_priv *il, struct il_rx_queue *rxq)
 int
 il4965_rxq_stop(struct il_priv *il)
 {
+       int ret;
 
-       /* stop Rx DMA */
-       il_wr(il, FH49_MEM_RCSR_CHNL0_CONFIG_REG, 0);
-       il_poll_bit(il, FH49_MEM_RSSR_RX_STATUS_REG,
-                   FH49_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000);
+       _il_wr(il, FH49_MEM_RCSR_CHNL0_CONFIG_REG, 0);
+       ret = _il_poll_bit(il, FH49_MEM_RSSR_RX_STATUS_REG,
+                          FH49_RSSR_CHNL0_RX_STATUS_CHNL_IDLE,
+                          FH49_RSSR_CHNL0_RX_STATUS_CHNL_IDLE,
+                          1000);
+       if (ret < 0)
+               IL_ERR("Can't stop Rx DMA.\n");
 
        return 0;
 }
@@ -692,7 +692,6 @@ il4965_hdl_rx(struct il_priv *il, struct il_rx_buf *rxb)
        /* Find max signal strength (dBm) among 3 antenna/receiver chains */
        rx_status.signal = il4965_calc_rssi(il, phy_res);
 
-       il_dbg_log_rx_data_frame(il, len, header);
        D_STATS("Rssi %d, TSF %llu\n", rx_status.signal,
                (unsigned long long)rx_status.mactime);
 
@@ -1343,12 +1342,11 @@ il4965_accumulative_stats(struct il_priv *il, __le32 * stats)
 }
 #endif
 
-#define REG_RECALIB_PERIOD (60)
-
 void
 il4965_hdl_stats(struct il_priv *il, struct il_rx_buf *rxb)
 {
-       int change;
+       const int recalib_seconds = 60;
+       bool change;
        struct il_rx_pkt *pkt = rxb_addr(rxb);
 
        D_RX("Statistics notification received (%d vs %d).\n",
@@ -1369,20 +1367,21 @@ il4965_hdl_stats(struct il_priv *il, struct il_rx_buf *rxb)
 
        set_bit(S_STATS, &il->status);
 
-       /* Reschedule the stats timer to occur in
-        * REG_RECALIB_PERIOD seconds to ensure we get a
-        * thermal update even if the uCode doesn't give
-        * us one */
+       /*
+        * Reschedule the stats timer to occur in recalib_seconds to ensure
+        * we get a thermal update even if the uCode doesn't give us one
+        */
        mod_timer(&il->stats_periodic,
-                 jiffies + msecs_to_jiffies(REG_RECALIB_PERIOD * 1000));
+                 jiffies + msecs_to_jiffies(recalib_seconds * 1000));
 
        if (unlikely(!test_bit(S_SCANNING, &il->status)) &&
            (pkt->hdr.cmd == N_STATS)) {
                il4965_rx_calc_noise(il);
                queue_work(il->workqueue, &il->run_time_calib_work);
        }
-       if (il->ops->lib->temp_ops.temperature && change)
-               il->ops->lib->temp_ops.temperature(il);
+
+       if (change)
+               il4965_temperature_calib(il);
 }
 
 void
@@ -1694,7 +1693,7 @@ il4965_tx_skb(struct il_priv *il, struct sk_buff *skb)
                sta_priv = (void *)sta->drv_priv;
 
        if (sta_priv && sta_priv->asleep &&
-           (info->flags & IEEE80211_TX_CTL_POLL_RESPONSE)) {
+           (info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER)) {
                /*
                 * This sends an asynchronous command to the device,
                 * but we can rely on it being processed before the
@@ -1785,7 +1784,6 @@ il4965_tx_skb(struct il_priv *il, struct sk_buff *skb)
 
        /* TODO need this for burst mode later on */
        il4965_tx_cmd_build_basic(il, skb, tx_cmd, info, hdr, sta_id);
-       il_dbg_log_tx_data_frame(il, len, hdr);
 
        il4965_tx_cmd_build_rate(il, tx_cmd, info, fc);
 
@@ -1815,7 +1813,7 @@ il4965_tx_skb(struct il_priv *il, struct sk_buff *skb)
        dma_unmap_len_set(out_meta, len, firstlen);
        /* Add buffer containing Tx command and MAC(!) header to TFD's
         * first entry */
-       il->ops->lib->txq_attach_buf_to_tfd(il, txq, txcmd_phys, firstlen, 1, 0);
+       il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, firstlen, 1, 0);
 
        if (!ieee80211_has_morefrags(hdr->frame_control)) {
                txq->need_update = 1;
@@ -1831,8 +1829,8 @@ il4965_tx_skb(struct il_priv *il, struct sk_buff *skb)
                phys_addr =
                    pci_map_single(il->pci_dev, skb->data + hdr_len, secondlen,
                                   PCI_DMA_TODEVICE);
-               il->ops->lib->txq_attach_buf_to_tfd(il, txq, phys_addr,
-                                                   secondlen, 0, 0);
+               il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, secondlen,
+                                              0, 0);
        }
 
        scratch_phys =
@@ -1852,8 +1850,7 @@ il4965_tx_skb(struct il_priv *il, struct sk_buff *skb)
 
        /* Set up entry for this TFD in Tx byte-count array */
        if (info->flags & IEEE80211_TX_CTL_AMPDU)
-               il->ops->lib->txq_update_byte_cnt_tbl(il, txq,
-                                                     le16_to_cpu(tx_cmd->len));
+               il->ops->txq_update_byte_cnt_tbl(il, txq, le16_to_cpu(tx_cmd->len));
 
        pci_dma_sync_single_for_device(il->pci_dev, txcmd_phys, firstlen,
                                       PCI_DMA_BIDIRECTIONAL);
@@ -1942,7 +1939,7 @@ il4965_hw_txq_ctx_free(struct il_priv *il)
        il4965_free_dma_ptr(il, &il->scd_bc_tbls);
 
        /* free tx queue structure */
-       il_txq_mem(il);
+       il_free_txq_mem(il);
 }
 
 /**
@@ -1955,8 +1952,7 @@ il4965_hw_txq_ctx_free(struct il_priv *il)
 int
 il4965_txq_ctx_alloc(struct il_priv *il)
 {
-       int ret;
-       int txq_id, slots_num;
+       int ret, txq_id;
        unsigned long flags;
 
        /* Free all tx/cmd queues and keep-warm buffer */
@@ -1993,10 +1989,7 @@ il4965_txq_ctx_alloc(struct il_priv *il)
 
        /* Alloc and init all Tx queues, including the command queue (#4/#9) */
        for (txq_id = 0; txq_id < il->hw_params.max_txq_num; txq_id++) {
-               slots_num =
-                   (txq_id ==
-                    il->cmd_queue) ? TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
-               ret = il_tx_queue_init(il, &il->txq[txq_id], slots_num, txq_id);
+               ret = il_tx_queue_init(il, txq_id);
                if (ret) {
                        IL_ERR("Tx %d queue init failed\n", txq_id);
                        goto error;
@@ -2017,52 +2010,27 @@ error_bc_tbls:
 void
 il4965_txq_ctx_reset(struct il_priv *il)
 {
-       int txq_id, slots_num;
+       int txq_id;
        unsigned long flags;
 
        spin_lock_irqsave(&il->lock, flags);
 
        /* Turn off all Tx DMA fifos */
        il4965_txq_set_sched(il, 0);
-
        /* Tell NIC where to find the "keep warm" buffer */
        il_wr(il, FH49_KW_MEM_ADDR_REG, il->kw.dma >> 4);
 
        spin_unlock_irqrestore(&il->lock, flags);
 
        /* Alloc and init all Tx queues, including the command queue (#4) */
-       for (txq_id = 0; txq_id < il->hw_params.max_txq_num; txq_id++) {
-               slots_num =
-                   txq_id == il->cmd_queue ? TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
-               il_tx_queue_reset(il, &il->txq[txq_id], slots_num, txq_id);
-       }
+       for (txq_id = 0; txq_id < il->hw_params.max_txq_num; txq_id++)
+               il_tx_queue_reset(il, txq_id);
 }
 
-/**
- * il4965_txq_ctx_stop - Stop all Tx DMA channels
- */
 void
-il4965_txq_ctx_stop(struct il_priv *il)
+il4965_txq_ctx_unmap(struct il_priv *il)
 {
-       int ch, txq_id;
-       unsigned long flags;
-
-       /* Turn off all Tx DMA fifos */
-       spin_lock_irqsave(&il->lock, flags);
-
-       il4965_txq_set_sched(il, 0);
-
-       /* Stop each Tx DMA channel, and wait for it to be idle */
-       for (ch = 0; ch < il->hw_params.dma_chnl_num; ch++) {
-               il_wr(il, FH49_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0);
-               if (il_poll_bit
-                   (il, FH49_TSSR_TX_STATUS_REG,
-                    FH49_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch), 1000))
-                       IL_ERR("Failing on timeout while stopping"
-                              " DMA channel %d [0x%08x]", ch,
-                              il_rd(il, FH49_TSSR_TX_STATUS_REG));
-       }
-       spin_unlock_irqrestore(&il->lock, flags);
+       int txq_id;
 
        if (!il->txq)
                return;
@@ -2075,6 +2043,30 @@ il4965_txq_ctx_stop(struct il_priv *il)
                        il_tx_queue_unmap(il, txq_id);
 }
 
+/**
+ * il4965_txq_ctx_stop - Stop all Tx DMA channels
+ */
+void
+il4965_txq_ctx_stop(struct il_priv *il)
+{
+       int ch, ret;
+
+       _il_wr_prph(il, IL49_SCD_TXFACT, 0);
+
+       /* Stop each Tx DMA channel, and wait for it to be idle */
+       for (ch = 0; ch < il->hw_params.dma_chnl_num; ch++) {
+               _il_wr(il, FH49_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0);
+               ret =
+                   _il_poll_bit(il, FH49_TSSR_TX_STATUS_REG,
+                                FH49_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch),
+                                FH49_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch),
+                                1000);
+               if (ret < 0)
+                       IL_ERR("Timeout stopping DMA channel %d [0x%08x]",
+                              ch, _il_rd(il, FH49_TSSR_TX_STATUS_REG));
+       }
+}
+
 /*
  * Find first available (lowest unused) Tx Queue, mark it "active".
  * Called only when finding queue for aggregation.
@@ -2474,7 +2466,7 @@ il4965_tx_queue_reclaim(struct il_priv *il, int txq_id, int idx)
                il4965_tx_status(il, skb, txq_id >= IL4965_FIRST_AMPDU_QUEUE);
 
                txq->skbs[txq->q.read_ptr] = NULL;
-               il->ops->lib->txq_free_tfd(il, txq);
+               il->ops->txq_free_tfd(il, txq);
        }
        return nfreed;
 }
@@ -2548,6 +2540,308 @@ il4965_tx_status_reply_compressed_ba(struct il_priv *il, struct il_ht_agg *agg,
        return 0;
 }
 
+static inline bool
+il4965_is_tx_success(u32 status)
+{
+       status &= TX_STATUS_MSK;
+       return (status == TX_STATUS_SUCCESS || status == TX_STATUS_DIRECT_DONE);
+}
+
+static u8
+il4965_find_station(struct il_priv *il, const u8 *addr)
+{
+       int i;
+       int start = 0;
+       int ret = IL_INVALID_STATION;
+       unsigned long flags;
+
+       if (il->iw_mode == NL80211_IFTYPE_ADHOC)
+               start = IL_STA_ID;
+
+       if (is_broadcast_ether_addr(addr))
+               return il->hw_params.bcast_id;
+
+       spin_lock_irqsave(&il->sta_lock, flags);
+       for (i = start; i < il->hw_params.max_stations; i++)
+               if (il->stations[i].used &&
+                   (!compare_ether_addr(il->stations[i].sta.sta.addr, addr))) {
+                       ret = i;
+                       goto out;
+               }
+
+       D_ASSOC("can not find STA %pM total %d\n", addr, il->num_stations);
+
+out:
+       /*
+        * It may be possible that more commands interacting with stations
+        * arrive before we completed processing the adding of
+        * station
+        */
+       if (ret != IL_INVALID_STATION &&
+           (!(il->stations[ret].used & IL_STA_UCODE_ACTIVE) ||
+            ((il->stations[ret].used & IL_STA_UCODE_ACTIVE) &&
+             (il->stations[ret].used & IL_STA_UCODE_INPROGRESS)))) {
+               IL_ERR("Requested station info for sta %d before ready.\n",
+                      ret);
+               ret = IL_INVALID_STATION;
+       }
+       spin_unlock_irqrestore(&il->sta_lock, flags);
+       return ret;
+}
+
+static int
+il4965_get_ra_sta_id(struct il_priv *il, struct ieee80211_hdr *hdr)
+{
+       if (il->iw_mode == NL80211_IFTYPE_STATION)
+               return IL_AP_ID;
+       else {
+               u8 *da = ieee80211_get_DA(hdr);
+
+               return il4965_find_station(il, da);
+       }
+}
+
+static inline u32
+il4965_get_scd_ssn(struct il4965_tx_resp *tx_resp)
+{
+       return le32_to_cpup(&tx_resp->u.status + tx_resp->frame_count) & MAX_SN;
+}
+
+static inline u32
+il4965_tx_status_to_mac80211(u32 status)
+{
+       status &= TX_STATUS_MSK;
+
+       switch (status) {
+       case TX_STATUS_SUCCESS:
+       case TX_STATUS_DIRECT_DONE:
+               return IEEE80211_TX_STAT_ACK;
+       case TX_STATUS_FAIL_DEST_PS:
+               return IEEE80211_TX_STAT_TX_FILTERED;
+       default:
+               return 0;
+       }
+}
+
+/**
+ * il4965_tx_status_reply_tx - Handle Tx response for frames in aggregation queue
+ */
+static int
+il4965_tx_status_reply_tx(struct il_priv *il, struct il_ht_agg *agg,
+                         struct il4965_tx_resp *tx_resp, int txq_id,
+                         u16 start_idx)
+{
+       u16 status;
+       struct agg_tx_status *frame_status = tx_resp->u.agg_status;
+       struct ieee80211_tx_info *info = NULL;
+       struct ieee80211_hdr *hdr = NULL;
+       u32 rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
+       int i, sh, idx;
+       u16 seq;
+       if (agg->wait_for_ba)
+               D_TX_REPLY("got tx response w/o block-ack\n");
+
+       agg->frame_count = tx_resp->frame_count;
+       agg->start_idx = start_idx;
+       agg->rate_n_flags = rate_n_flags;
+       agg->bitmap = 0;
+
+       /* num frames attempted by Tx command */
+       if (agg->frame_count == 1) {
+               /* Only one frame was attempted; no block-ack will arrive */
+               status = le16_to_cpu(frame_status[0].status);
+               idx = start_idx;
+
+               D_TX_REPLY("FrameCnt = %d, StartIdx=%d idx=%d\n",
+                          agg->frame_count, agg->start_idx, idx);
+
+               info = IEEE80211_SKB_CB(il->txq[txq_id].skbs[idx]);
+               info->status.rates[0].count = tx_resp->failure_frame + 1;
+               info->flags &= ~IEEE80211_TX_CTL_AMPDU;
+               info->flags |= il4965_tx_status_to_mac80211(status);
+               il4965_hwrate_to_tx_control(il, rate_n_flags, info);
+
+               D_TX_REPLY("1 Frame 0x%x failure :%d\n", status & 0xff,
+                          tx_resp->failure_frame);
+               D_TX_REPLY("Rate Info rate_n_flags=%x\n", rate_n_flags);
+
+               agg->wait_for_ba = 0;
+       } else {
+               /* Two or more frames were attempted; expect block-ack */
+               u64 bitmap = 0;
+               int start = agg->start_idx;
+               struct sk_buff *skb;
+
+               /* Construct bit-map of pending frames within Tx win */
+               for (i = 0; i < agg->frame_count; i++) {
+                       u16 sc;
+                       status = le16_to_cpu(frame_status[i].status);
+                       seq = le16_to_cpu(frame_status[i].sequence);
+                       idx = SEQ_TO_IDX(seq);
+                       txq_id = SEQ_TO_QUEUE(seq);
+
+                       if (status &
+                           (AGG_TX_STATE_FEW_BYTES_MSK |
+                            AGG_TX_STATE_ABORT_MSK))
+                               continue;
+
+                       D_TX_REPLY("FrameCnt = %d, txq_id=%d idx=%d\n",
+                                  agg->frame_count, txq_id, idx);
+
+                       skb = il->txq[txq_id].skbs[idx];
+                       if (WARN_ON_ONCE(skb == NULL))
+                               return -1;
+                       hdr = (struct ieee80211_hdr *) skb->data;
+
+                       sc = le16_to_cpu(hdr->seq_ctrl);
+                       if (idx != (SEQ_TO_SN(sc) & 0xff)) {
+                               IL_ERR("BUG_ON idx doesn't match seq control"
+                                      " idx=%d, seq_idx=%d, seq=%d\n", idx,
+                                      SEQ_TO_SN(sc), hdr->seq_ctrl);
+                               return -1;
+                       }
+
+                       D_TX_REPLY("AGG Frame i=%d idx %d seq=%d\n", i, idx,
+                                  SEQ_TO_SN(sc));
+
+                       sh = idx - start;
+                       if (sh > 64) {
+                               sh = (start - idx) + 0xff;
+                               bitmap = bitmap << sh;
+                               sh = 0;
+                               start = idx;
+                       } else if (sh < -64)
+                               sh = 0xff - (start - idx);
+                       else if (sh < 0) {
+                               sh = start - idx;
+                               start = idx;
+                               bitmap = bitmap << sh;
+                               sh = 0;
+                       }
+                       bitmap |= 1ULL << sh;
+                       D_TX_REPLY("start=%d bitmap=0x%llx\n", start,
+                                  (unsigned long long)bitmap);
+               }
+
+               agg->bitmap = bitmap;
+               agg->start_idx = start;
+               D_TX_REPLY("Frames %d start_idx=%d bitmap=0x%llx\n",
+                          agg->frame_count, agg->start_idx,
+                          (unsigned long long)agg->bitmap);
+
+               if (bitmap)
+                       agg->wait_for_ba = 1;
+       }
+       return 0;
+}
+
+/**
+ * il4965_hdl_tx - Handle standard (non-aggregation) Tx response
+ */
+static void
+il4965_hdl_tx(struct il_priv *il, struct il_rx_buf *rxb)
+{
+       struct il_rx_pkt *pkt = rxb_addr(rxb);
+       u16 sequence = le16_to_cpu(pkt->hdr.sequence);
+       int txq_id = SEQ_TO_QUEUE(sequence);
+       int idx = SEQ_TO_IDX(sequence);
+       struct il_tx_queue *txq = &il->txq[txq_id];
+       struct sk_buff *skb;
+       struct ieee80211_hdr *hdr;
+       struct ieee80211_tx_info *info;
+       struct il4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
+       u32 status = le32_to_cpu(tx_resp->u.status);
+       int uninitialized_var(tid);
+       int sta_id;
+       int freed;
+       u8 *qc = NULL;
+       unsigned long flags;
+
+       if (idx >= txq->q.n_bd || il_queue_used(&txq->q, idx) == 0) {
+               IL_ERR("Read idx for DMA queue txq_id (%d) idx %d "
+                      "is out of range [0-%d] %d %d\n", txq_id, idx,
+                      txq->q.n_bd, txq->q.write_ptr, txq->q.read_ptr);
+               return;
+       }
+
+       txq->time_stamp = jiffies;
+
+       skb = txq->skbs[txq->q.read_ptr];
+       info = IEEE80211_SKB_CB(skb);
+       memset(&info->status, 0, sizeof(info->status));
+
+       hdr = (struct ieee80211_hdr *) skb->data;
+       if (ieee80211_is_data_qos(hdr->frame_control)) {
+               qc = ieee80211_get_qos_ctl(hdr);
+               tid = qc[0] & 0xf;
+       }
+
+       sta_id = il4965_get_ra_sta_id(il, hdr);
+       if (txq->sched_retry && unlikely(sta_id == IL_INVALID_STATION)) {
+               IL_ERR("Station not known\n");
+               return;
+       }
+
+       spin_lock_irqsave(&il->sta_lock, flags);
+       if (txq->sched_retry) {
+               const u32 scd_ssn = il4965_get_scd_ssn(tx_resp);
+               struct il_ht_agg *agg = NULL;
+               WARN_ON(!qc);
+
+               agg = &il->stations[sta_id].tid[tid].agg;
+
+               il4965_tx_status_reply_tx(il, agg, tx_resp, txq_id, idx);
+
+               /* check if BAR is needed */
+               if (tx_resp->frame_count == 1 &&
+                   !il4965_is_tx_success(status))
+                       info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
+
+               if (txq->q.read_ptr != (scd_ssn & 0xff)) {
+                       idx = il_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd);
+                       D_TX_REPLY("Retry scheduler reclaim scd_ssn "
+                                  "%d idx %d\n", scd_ssn, idx);
+                       freed = il4965_tx_queue_reclaim(il, txq_id, idx);
+                       if (qc)
+                               il4965_free_tfds_in_queue(il, sta_id, tid,
+                                                         freed);
+
+                       if (il->mac80211_registered &&
+                           il_queue_space(&txq->q) > txq->q.low_mark &&
+                           agg->state != IL_EMPTYING_HW_QUEUE_DELBA)
+                               il_wake_queue(il, txq);
+               }
+       } else {
+               info->status.rates[0].count = tx_resp->failure_frame + 1;
+               info->flags |= il4965_tx_status_to_mac80211(status);
+               il4965_hwrate_to_tx_control(il,
+                                           le32_to_cpu(tx_resp->rate_n_flags),
+                                           info);
+
+               D_TX_REPLY("TXQ %d status %s (0x%08x) "
+                          "rate_n_flags 0x%x retries %d\n", txq_id,
+                          il4965_get_tx_fail_reason(status), status,
+                          le32_to_cpu(tx_resp->rate_n_flags),
+                          tx_resp->failure_frame);
+
+               freed = il4965_tx_queue_reclaim(il, txq_id, idx);
+               if (qc && likely(sta_id != IL_INVALID_STATION))
+                       il4965_free_tfds_in_queue(il, sta_id, tid, freed);
+               else if (sta_id == IL_INVALID_STATION)
+                       D_TX_REPLY("Station not known\n");
+
+               if (il->mac80211_registered &&
+                   il_queue_space(&txq->q) > txq->q.low_mark)
+                       il_wake_queue(il, txq);
+       }
+       if (qc && likely(sta_id != IL_INVALID_STATION))
+               il4965_txq_check_empty(il, sta_id, tid, txq_id);
+
+       il4965_check_abort_status(il, tx_resp->frame_count, status);
+
+       spin_unlock_irqrestore(&il->sta_lock, flags);
+}
+
 /**
  * translate ucode response to mac80211 tx status control values
  */
@@ -3352,8 +3646,8 @@ il4965_sta_modify_sleep_tx_count(struct il_priv *il, int sta_id, int cnt)
 void
 il4965_update_chain_flags(struct il_priv *il)
 {
-       if (il->ops->hcmd->set_rxon_chain) {
-               il->ops->hcmd->set_rxon_chain(il);
+       if (il->ops->set_rxon_chain) {
+               il->ops->set_rxon_chain(il);
                if (il->active.rx_chain != il->staging.rx_chain)
                        il_commit_rxon(il);
        }
@@ -3726,9 +4020,9 @@ il4965_hdl_alive(struct il_priv *il, struct il_rx_buf *rxb)
  * This callback is provided in order to send a stats request.
  *
  * This timer function is continually reset to execute within
- * REG_RECALIB_PERIOD seconds since the last N_STATS
- * was received.  We need to ensure we receive the stats in order
- * to update the temperature used for calibrating the TXPOWER.
+ * 60 seconds since the last N_STATS was received.  We need to
+ * ensure we receive the stats in order to update the temperature
+ * used for calibrating the TXPOWER.
  */
 static void
 il4965_bg_stats_periodic(unsigned long data)
@@ -3778,7 +4072,7 @@ il4965_perform_ct_kill_task(struct il_priv *il)
        _il_rd(il, CSR_UCODE_DRV_GP1);
 
        spin_lock_irqsave(&il->reg_lock, flags);
-       if (!_il_grab_nic_access(il))
+       if (likely(_il_grab_nic_access(il)))
                _il_release_nic_access(il);
        spin_unlock_irqrestore(&il->reg_lock, flags);
 }
@@ -3816,17 +4110,17 @@ il4965_hdl_card_state(struct il_priv *il, struct il_rx_buf *rxb)
                il4965_perform_ct_kill_task(il);
 
        if (flags & HW_CARD_DISABLED)
-               set_bit(S_RF_KILL_HW, &il->status);
+               set_bit(S_RFKILL, &il->status);
        else
-               clear_bit(S_RF_KILL_HW, &il->status);
+               clear_bit(S_RFKILL, &il->status);
 
        if (!(flags & RXON_CARD_DISABLED))
                il_scan_cancel(il);
 
-       if ((test_bit(S_RF_KILL_HW, &status) !=
-            test_bit(S_RF_KILL_HW, &il->status)))
+       if ((test_bit(S_RFKILL, &status) !=
+            test_bit(S_RFKILL, &il->status)))
                wiphy_rfkill_set_hw_state(il->hw->wiphy,
-                                         test_bit(S_RF_KILL_HW, &il->status));
+                                         test_bit(S_RFKILL, &il->status));
        else
                wake_up(&il->wait_command_queue);
 }
@@ -3868,10 +4162,11 @@ il4965_setup_handlers(struct il_priv *il)
        /* Rx handlers */
        il->handlers[N_RX_PHY] = il4965_hdl_rx_phy;
        il->handlers[N_RX_MPDU] = il4965_hdl_rx;
+       il->handlers[N_RX] = il4965_hdl_rx;
        /* block ack */
        il->handlers[N_COMPRESSED_BA] = il4965_hdl_compressed_ba;
-       /* Set up hardware specific Rx handlers */
-       il->ops->lib->handler_setup(il);
+       /* Tx response */
+       il->handlers[C_TX] = il4965_hdl_tx;
 }
 
 /**
@@ -4101,9 +4396,8 @@ il4965_irq_tasklet(struct il_priv *il)
        /* HW RF KILL switch toggled */
        if (inta & CSR_INT_BIT_RF_KILL) {
                int hw_rf_kill = 0;
-               if (!
-                   (_il_rd(il, CSR_GP_CNTRL) &
-                    CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
+
+               if (!(_il_rd(il, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
                        hw_rf_kill = 1;
 
                IL_WARN("RF_KILL bit toggled to %s.\n",
@@ -4118,9 +4412,9 @@ il4965_irq_tasklet(struct il_priv *il)
                 */
                if (!test_bit(S_ALIVE, &il->status)) {
                        if (hw_rf_kill)
-                               set_bit(S_RF_KILL_HW, &il->status);
+                               set_bit(S_RFKILL, &il->status);
                        else
-                               clear_bit(S_RF_KILL_HW, &il->status);
+                               clear_bit(S_RFKILL, &il->status);
                        wiphy_rfkill_set_hw_state(il->hw->wiphy, hw_rf_kill);
                }
 
@@ -4244,11 +4538,9 @@ il4965_store_debug_level(struct device *d, struct device_attribute *attr,
        ret = strict_strtoul(buf, 0, &val);
        if (ret)
                IL_ERR("%s is not in hex or decimal form.\n", buf);
-       else {
+       else
                il->debug_level = val;
-               if (il_alloc_traffic_mem(il))
-                       IL_ERR("Not enough memory to generate traffic log\n");
-       }
+
        return strnlen(buf, count);
 }
 
@@ -4773,7 +5065,7 @@ il4965_dump_nic_error_log(struct il_priv *il)
        else
                base = le32_to_cpu(il->card_alive.error_event_table_ptr);
 
-       if (!il->ops->lib->is_valid_rtc_data_addr(base)) {
+       if (!il->ops->is_valid_rtc_data_addr(base)) {
                IL_ERR("Not valid error log pointer 0x%08X for %s uCode\n",
                       base, (il->ucode_type == UCODE_INIT) ? "Init" : "RT");
                return;
@@ -5002,8 +5294,8 @@ il4965_alive_start(struct il_priv *il)
                /* Initialize our rx_config data */
                il_connection_init_rx_config(il);
 
-               if (il->ops->hcmd->set_rxon_chain)
-                       il->ops->hcmd->set_rxon_chain(il);
+               if (il->ops->set_rxon_chain)
+                       il->ops->set_rxon_chain(il);
        }
 
        /* Configure bluetooth coexistence if enabled */
@@ -5091,12 +5383,8 @@ __il4965_down(struct il_priv *il)
         * clear all bits but the RF Kill bit and return */
        if (!il_is_init(il)) {
                il->status =
-                   test_bit(S_RF_KILL_HW,
-                            &il->
-                            status) << S_RF_KILL_HW |
-                   test_bit(S_GEO_CONFIGURED,
-                            &il->
-                            status) << S_GEO_CONFIGURED |
+                   test_bit(S_RFKILL, &il->status) << S_RFKILL |
+                   test_bit(S_GEO_CONFIGURED, &il->status) << S_GEO_CONFIGURED |
                    test_bit(S_EXIT_PENDING, &il->status) << S_EXIT_PENDING;
                goto exit;
        }
@@ -5104,28 +5392,32 @@ __il4965_down(struct il_priv *il)
        /* ...otherwise clear out all the status bits but the RF Kill
         * bit and continue taking the NIC down. */
        il->status &=
-           test_bit(S_RF_KILL_HW,
-                    &il->status) << S_RF_KILL_HW | test_bit(S_GEO_CONFIGURED,
-                                                            &il->
-                                                            status) <<
-           S_GEO_CONFIGURED | test_bit(S_FW_ERROR,
-                                       &il->
-                                       status) << S_FW_ERROR |
+           test_bit(S_RFKILL, &il->status) << S_RFKILL |
+           test_bit(S_GEO_CONFIGURED, &il->status) << S_GEO_CONFIGURED |
+           test_bit(S_FW_ERROR, &il->status) << S_FW_ERROR |
            test_bit(S_EXIT_PENDING, &il->status) << S_EXIT_PENDING;
 
+       /*
+        * We disabled and synchronized interrupt, and priv->mutex is taken, so
+        * here is the only thread which will program device registers, but
+        * still have lockdep assertions, so we are taking reg_lock.
+        */
+       spin_lock_irq(&il->reg_lock);
+       /* FIXME: il_grab_nic_access if rfkill is off ? */
+
        il4965_txq_ctx_stop(il);
        il4965_rxq_stop(il);
-
        /* Power-down device's busmaster DMA clocks */
-       il_wr_prph(il, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT);
+       _il_wr_prph(il, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT);
        udelay(5);
-
        /* Make sure (redundant) we've released our request to stay awake */
-       il_clear_bit(il, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-
+       _il_clear_bit(il, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
        /* Stop the device, and put it in low power state */
-       il_apm_stop(il);
+       _il_apm_stop(il);
+
+       spin_unlock_irq(&il->reg_lock);
 
+       il4965_txq_ctx_unmap(il);
 exit:
        memset(&il->card_alive, 0, sizeof(struct il_alive_resp));
 
@@ -5146,40 +5438,36 @@ il4965_down(struct il_priv *il)
        il4965_cancel_deferred_work(il);
 }
 
-#define HW_READY_TIMEOUT (50)
 
-static int
+static void
 il4965_set_hw_ready(struct il_priv *il)
 {
-       int ret = 0;
+       int ret;
 
        il_set_bit(il, CSR_HW_IF_CONFIG_REG,
                   CSR_HW_IF_CONFIG_REG_BIT_NIC_READY);
 
        /* See if we got it */
-       ret =
-           _il_poll_bit(il, CSR_HW_IF_CONFIG_REG,
-                        CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
-                        CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, HW_READY_TIMEOUT);
-       if (ret != -ETIMEDOUT)
+       ret = _il_poll_bit(il, CSR_HW_IF_CONFIG_REG,
+                          CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
+                          CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
+                          100);
+       if (ret >= 0)
                il->hw_ready = true;
-       else
-               il->hw_ready = false;
 
-       D_INFO("hardware %s\n", (il->hw_ready == 1) ? "ready" : "not ready");
-       return ret;
+       D_INFO("hardware %s ready\n", (il->hw_ready) ? "" : "not");
 }
 
-static int
+static void
 il4965_prepare_card_hw(struct il_priv *il)
 {
-       int ret = 0;
+       int ret;
 
-       D_INFO("il4965_prepare_card_hw enter\n");
+       il->hw_ready = false;
 
-       ret = il4965_set_hw_ready(il);
+       il4965_set_hw_ready(il);
        if (il->hw_ready)
-               return ret;
+               return;
 
        /* If HW is not ready, prepare the conditions to check again */
        il_set_bit(il, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_PREPARE);
@@ -5192,8 +5480,6 @@ il4965_prepare_card_hw(struct il_priv *il)
        /* HW should be ready by now, check again. */
        if (ret != -ETIMEDOUT)
                il4965_set_hw_ready(il);
-
-       return ret;
 }
 
 #define MAX_HW_RESTARTS 5
@@ -5221,22 +5507,19 @@ __il4965_up(struct il_priv *il)
        }
 
        il4965_prepare_card_hw(il);
-
        if (!il->hw_ready) {
-               IL_WARN("Exit HW not ready\n");
+               IL_ERR("HW not ready\n");
                return -EIO;
        }
 
        /* If platform's RF_KILL switch is NOT set to KILL */
        if (_il_rd(il, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
-               clear_bit(S_RF_KILL_HW, &il->status);
-       else
-               set_bit(S_RF_KILL_HW, &il->status);
-
-       if (il_is_rfkill(il)) {
+               clear_bit(S_RFKILL, &il->status);
+       else {
+               set_bit(S_RFKILL, &il->status);
                wiphy_rfkill_set_hw_state(il->hw->wiphy, true);
 
-               il_enable_interrupts(il);
+               il_enable_rfkill_int(il);
                IL_WARN("Radio disabled by HW RF Kill switch\n");
                return 0;
        }
@@ -5275,7 +5558,7 @@ __il4965_up(struct il_priv *il)
                /* load bootstrap state machine,
                 * load bootstrap program into processor's memory,
                 * prepare to load the "initialize" uCode */
-               ret = il->ops->lib->load_ucode(il);
+               ret = il->ops->load_ucode(il);
 
                if (ret) {
                        IL_ERR("Unable to set up bootstrap uCode: %d\n", ret);
@@ -5316,7 +5599,7 @@ il4965_bg_init_alive_start(struct work_struct *data)
        if (test_bit(S_EXIT_PENDING, &il->status))
                goto out;
 
-       il->ops->lib->init_alive_start(il);
+       il->ops->init_alive_start(il);
 out:
        mutex_unlock(&il->mutex);
 }
@@ -5748,7 +6031,7 @@ il4965_mac_channel_switch(struct ieee80211_hw *hw,
        if (!il_is_associated(il))
                goto out;
 
-       if (!il->ops->lib->set_channel_switch)
+       if (!il->ops->set_channel_switch)
                goto out;
 
        ch = channel->hw_value;
@@ -5800,7 +6083,7 @@ il4965_mac_channel_switch(struct ieee80211_hw *hw,
         */
        set_bit(S_CHANNEL_SWITCH_PENDING, &il->status);
        il->switch_channel = cpu_to_le16(ch);
-       if (il->ops->lib->set_channel_switch(il, ch_switch)) {
+       if (il->ops->set_channel_switch(il, ch_switch)) {
                clear_bit(S_CHANNEL_SWITCH_PENDING, &il->status);
                il->switch_channel = 0;
                ieee80211_chswitch_done(il->vif, false);
@@ -5883,7 +6166,7 @@ il4965_bg_txpower_work(struct work_struct *work)
        /* Regardless of if we are associated, we must reconfigure the
         * TX power since frames can be sent on non-radar channels while
         * not associated */
-       il->ops->lib->send_tx_power(il);
+       il->ops->send_tx_power(il);
 
        /* Update last_temperature to keep is_calib_needed from running
         * when it isn't needed... */
@@ -6035,8 +6318,8 @@ il4965_init_drv(struct il_priv *il)
        il->force_reset.reset_duration = IL_DELAY_NEXT_FORCE_FW_RELOAD;
 
        /* Choose which receivers/antennas to use */
-       if (il->ops->hcmd->set_rxon_chain)
-               il->ops->hcmd->set_rxon_chain(il);
+       if (il->ops->set_rxon_chain)
+               il->ops->set_rxon_chain(il);
 
        il_init_scan_params(il);
 
@@ -6064,7 +6347,6 @@ err:
 static void
 il4965_uninit_drv(struct il_priv *il)
 {
-       il4965_calib_free_results(il);
        il_free_geos(il);
        il_free_channel_map(il);
        kfree(il->scan_cmd);
@@ -6180,12 +6462,12 @@ il4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        D_INFO("*** LOAD DRIVER ***\n");
        il->cfg = cfg;
        il->ops = &il4965_ops;
+#ifdef CONFIG_IWLEGACY_DEBUGFS
+       il->debugfs_ops = &il4965_debugfs_ops;
+#endif
        il->pci_dev = pdev;
        il->inta_mask = CSR_INI_SET_MASK;
 
-       if (il_alloc_traffic_mem(il))
-               IL_ERR("Not enough memory to generate traffic log\n");
-
        /**************************
         * 2. Initializing PCI bus
         **************************/
@@ -6224,7 +6506,7 @@ il4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        /***********************
         * 3. Read REV register
         ***********************/
-       il->hw_base = pci_iomap(pdev, 0, 0);
+       il->hw_base = pci_ioremap_bar(pdev, 0);
        if (!il->hw_base) {
                err = -ENODEV;
                goto out_pci_release_regions;
@@ -6329,12 +6611,12 @@ il4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        /* If platform's RF_KILL switch is NOT set to KILL */
        if (_il_rd(il, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
-               clear_bit(S_RF_KILL_HW, &il->status);
+               clear_bit(S_RFKILL, &il->status);
        else
-               set_bit(S_RF_KILL_HW, &il->status);
+               set_bit(S_RFKILL, &il->status);
 
        wiphy_rfkill_set_hw_state(il->hw->wiphy,
-                                 test_bit(S_RF_KILL_HW, &il->status));
+                                 test_bit(S_RFKILL, &il->status));
 
        il_power_initialize(il);
 
@@ -6356,14 +6638,13 @@ out_disable_msi:
 out_free_eeprom:
        il_eeprom_free(il);
 out_iounmap:
-       pci_iounmap(pdev, il->hw_base);
+       iounmap(il->hw_base);
 out_pci_release_regions:
        pci_set_drvdata(pdev, NULL);
        pci_release_regions(pdev);
 out_pci_disable_device:
        pci_disable_device(pdev);
 out_ieee80211_free_hw:
-       il_free_traffic_mem(il);
        ieee80211_free_hw(il->hw);
 out:
        return err;
@@ -6434,11 +6715,10 @@ il4965_pci_remove(struct pci_dev *pdev)
         * until now... */
        destroy_workqueue(il->workqueue);
        il->workqueue = NULL;
-       il_free_traffic_mem(il);
 
        free_irq(il->pci_dev->irq, il);
        pci_disable_msi(il->pci_dev);
-       pci_iounmap(pdev, il->hw_base);
+       iounmap(il->hw_base);
        pci_release_regions(pdev);
        pci_disable_device(pdev);
        pci_set_drvdata(pdev, NULL);
index 79e4e7971338bd225236b0cda63009756a1f8a3e..5db11714e04705cd9f68c061c59dfdab6abecfc6 100644 (file)
@@ -264,10 +264,6 @@ il4965_led_enable(struct il_priv *il)
        _il_wr(il, CSR_LED_REG, CSR_LED_REG_TRUN_ON);
 }
 
-const struct il_led_ops il4965_led_ops = {
-       .cmd = il4965_send_led_cmd,
-};
-
 static int il4965_send_tx_power(struct il_priv *il);
 static int il4965_hw_get_temperature(struct il_priv *il);
 
@@ -508,7 +504,7 @@ iw4965_is_ht40_channel(__le32 rxon_flags)
                chan_mod == CHANNEL_MODE_MIXED);
 }
 
-static void
+void
 il4965_nic_config(struct il_priv *il)
 {
        unsigned long flags;
@@ -1678,7 +1674,7 @@ il4965_is_temp_calib_needed(struct il_priv *il)
        return 1;
 }
 
-static void
+void
 il4965_temperature_calib(struct il_priv *il)
 {
        s32 temp;
@@ -1737,323 +1733,6 @@ il4965_build_addsta_hcmd(const struct il_addsta_cmd *cmd, u8 * data)
        return (u16) sizeof(struct il4965_addsta_cmd);
 }
 
-static inline u32
-il4965_get_scd_ssn(struct il4965_tx_resp *tx_resp)
-{
-       return le32_to_cpup(&tx_resp->u.status + tx_resp->frame_count) & MAX_SN;
-}
-
-static inline u32
-il4965_tx_status_to_mac80211(u32 status)
-{
-       status &= TX_STATUS_MSK;
-
-       switch (status) {
-       case TX_STATUS_SUCCESS:
-       case TX_STATUS_DIRECT_DONE:
-               return IEEE80211_TX_STAT_ACK;
-       case TX_STATUS_FAIL_DEST_PS:
-               return IEEE80211_TX_STAT_TX_FILTERED;
-       default:
-               return 0;
-       }
-}
-
-static inline bool
-il4965_is_tx_success(u32 status)
-{
-       status &= TX_STATUS_MSK;
-       return (status == TX_STATUS_SUCCESS || status == TX_STATUS_DIRECT_DONE);
-}
-
-/**
- * il4965_tx_status_reply_tx - Handle Tx response for frames in aggregation queue
- */
-static int
-il4965_tx_status_reply_tx(struct il_priv *il, struct il_ht_agg *agg,
-                         struct il4965_tx_resp *tx_resp, int txq_id,
-                         u16 start_idx)
-{
-       u16 status;
-       struct agg_tx_status *frame_status = tx_resp->u.agg_status;
-       struct ieee80211_tx_info *info = NULL;
-       struct ieee80211_hdr *hdr = NULL;
-       u32 rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
-       int i, sh, idx;
-       u16 seq;
-       if (agg->wait_for_ba)
-               D_TX_REPLY("got tx response w/o block-ack\n");
-
-       agg->frame_count = tx_resp->frame_count;
-       agg->start_idx = start_idx;
-       agg->rate_n_flags = rate_n_flags;
-       agg->bitmap = 0;
-
-       /* num frames attempted by Tx command */
-       if (agg->frame_count == 1) {
-               /* Only one frame was attempted; no block-ack will arrive */
-               status = le16_to_cpu(frame_status[0].status);
-               idx = start_idx;
-
-               D_TX_REPLY("FrameCnt = %d, StartIdx=%d idx=%d\n",
-                          agg->frame_count, agg->start_idx, idx);
-
-               info = IEEE80211_SKB_CB(il->txq[txq_id].skbs[idx]);
-               info->status.rates[0].count = tx_resp->failure_frame + 1;
-               info->flags &= ~IEEE80211_TX_CTL_AMPDU;
-               info->flags |= il4965_tx_status_to_mac80211(status);
-               il4965_hwrate_to_tx_control(il, rate_n_flags, info);
-
-               D_TX_REPLY("1 Frame 0x%x failure :%d\n", status & 0xff,
-                          tx_resp->failure_frame);
-               D_TX_REPLY("Rate Info rate_n_flags=%x\n", rate_n_flags);
-
-               agg->wait_for_ba = 0;
-       } else {
-               /* Two or more frames were attempted; expect block-ack */
-               u64 bitmap = 0;
-               int start = agg->start_idx;
-               struct sk_buff *skb;
-
-               /* Construct bit-map of pending frames within Tx win */
-               for (i = 0; i < agg->frame_count; i++) {
-                       u16 sc;
-                       status = le16_to_cpu(frame_status[i].status);
-                       seq = le16_to_cpu(frame_status[i].sequence);
-                       idx = SEQ_TO_IDX(seq);
-                       txq_id = SEQ_TO_QUEUE(seq);
-
-                       if (status &
-                           (AGG_TX_STATE_FEW_BYTES_MSK |
-                            AGG_TX_STATE_ABORT_MSK))
-                               continue;
-
-                       D_TX_REPLY("FrameCnt = %d, txq_id=%d idx=%d\n",
-                                  agg->frame_count, txq_id, idx);
-
-                       skb = il->txq[txq_id].skbs[idx];
-                       if (WARN_ON_ONCE(skb == NULL))
-                               return -1;
-                       hdr = (struct ieee80211_hdr *) skb->data;
-
-                       sc = le16_to_cpu(hdr->seq_ctrl);
-                       if (idx != (SEQ_TO_SN(sc) & 0xff)) {
-                               IL_ERR("BUG_ON idx doesn't match seq control"
-                                      " idx=%d, seq_idx=%d, seq=%d\n", idx,
-                                      SEQ_TO_SN(sc), hdr->seq_ctrl);
-                               return -1;
-                       }
-
-                       D_TX_REPLY("AGG Frame i=%d idx %d seq=%d\n", i, idx,
-                                  SEQ_TO_SN(sc));
-
-                       sh = idx - start;
-                       if (sh > 64) {
-                               sh = (start - idx) + 0xff;
-                               bitmap = bitmap << sh;
-                               sh = 0;
-                               start = idx;
-                       } else if (sh < -64)
-                               sh = 0xff - (start - idx);
-                       else if (sh < 0) {
-                               sh = start - idx;
-                               start = idx;
-                               bitmap = bitmap << sh;
-                               sh = 0;
-                       }
-                       bitmap |= 1ULL << sh;
-                       D_TX_REPLY("start=%d bitmap=0x%llx\n", start,
-                                  (unsigned long long)bitmap);
-               }
-
-               agg->bitmap = bitmap;
-               agg->start_idx = start;
-               D_TX_REPLY("Frames %d start_idx=%d bitmap=0x%llx\n",
-                          agg->frame_count, agg->start_idx,
-                          (unsigned long long)agg->bitmap);
-
-               if (bitmap)
-                       agg->wait_for_ba = 1;
-       }
-       return 0;
-}
-
-static u8
-il4965_find_station(struct il_priv *il, const u8 * addr)
-{
-       int i;
-       int start = 0;
-       int ret = IL_INVALID_STATION;
-       unsigned long flags;
-
-       if ((il->iw_mode == NL80211_IFTYPE_ADHOC))
-               start = IL_STA_ID;
-
-       if (is_broadcast_ether_addr(addr))
-               return il->hw_params.bcast_id;
-
-       spin_lock_irqsave(&il->sta_lock, flags);
-       for (i = start; i < il->hw_params.max_stations; i++)
-               if (il->stations[i].used &&
-                   (!compare_ether_addr(il->stations[i].sta.sta.addr, addr))) {
-                       ret = i;
-                       goto out;
-               }
-
-       D_ASSOC("can not find STA %pM total %d\n", addr, il->num_stations);
-
-out:
-       /*
-        * It may be possible that more commands interacting with stations
-        * arrive before we completed processing the adding of
-        * station
-        */
-       if (ret != IL_INVALID_STATION &&
-           (!(il->stations[ret].used & IL_STA_UCODE_ACTIVE) ||
-            ((il->stations[ret].used & IL_STA_UCODE_ACTIVE) &&
-             (il->stations[ret].used & IL_STA_UCODE_INPROGRESS)))) {
-               IL_ERR("Requested station info for sta %d before ready.\n",
-                      ret);
-               ret = IL_INVALID_STATION;
-       }
-       spin_unlock_irqrestore(&il->sta_lock, flags);
-       return ret;
-}
-
-static int
-il4965_get_ra_sta_id(struct il_priv *il, struct ieee80211_hdr *hdr)
-{
-       if (il->iw_mode == NL80211_IFTYPE_STATION) {
-               return IL_AP_ID;
-       } else {
-               u8 *da = ieee80211_get_DA(hdr);
-               return il4965_find_station(il, da);
-       }
-}
-
-/**
- * il4965_hdl_tx - Handle standard (non-aggregation) Tx response
- */
-static void
-il4965_hdl_tx(struct il_priv *il, struct il_rx_buf *rxb)
-{
-       struct il_rx_pkt *pkt = rxb_addr(rxb);
-       u16 sequence = le16_to_cpu(pkt->hdr.sequence);
-       int txq_id = SEQ_TO_QUEUE(sequence);
-       int idx = SEQ_TO_IDX(sequence);
-       struct il_tx_queue *txq = &il->txq[txq_id];
-       struct sk_buff *skb;
-       struct ieee80211_hdr *hdr;
-       struct ieee80211_tx_info *info;
-       struct il4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
-       u32 status = le32_to_cpu(tx_resp->u.status);
-       int uninitialized_var(tid);
-       int sta_id;
-       int freed;
-       u8 *qc = NULL;
-       unsigned long flags;
-
-       if (idx >= txq->q.n_bd || il_queue_used(&txq->q, idx) == 0) {
-               IL_ERR("Read idx for DMA queue txq_id (%d) idx %d "
-                      "is out of range [0-%d] %d %d\n", txq_id, idx,
-                      txq->q.n_bd, txq->q.write_ptr, txq->q.read_ptr);
-               return;
-       }
-
-       txq->time_stamp = jiffies;
-
-       skb = txq->skbs[txq->q.read_ptr];
-       info = IEEE80211_SKB_CB(skb);
-       memset(&info->status, 0, sizeof(info->status));
-
-       hdr = (struct ieee80211_hdr *) skb->data;
-       if (ieee80211_is_data_qos(hdr->frame_control)) {
-               qc = ieee80211_get_qos_ctl(hdr);
-               tid = qc[0] & 0xf;
-       }
-
-       sta_id = il4965_get_ra_sta_id(il, hdr);
-       if (txq->sched_retry && unlikely(sta_id == IL_INVALID_STATION)) {
-               IL_ERR("Station not known\n");
-               return;
-       }
-
-       spin_lock_irqsave(&il->sta_lock, flags);
-       if (txq->sched_retry) {
-               const u32 scd_ssn = il4965_get_scd_ssn(tx_resp);
-               struct il_ht_agg *agg = NULL;
-               WARN_ON(!qc);
-
-               agg = &il->stations[sta_id].tid[tid].agg;
-
-               il4965_tx_status_reply_tx(il, agg, tx_resp, txq_id, idx);
-
-               /* check if BAR is needed */
-               if ((tx_resp->frame_count == 1) &&
-                   !il4965_is_tx_success(status))
-                       info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
-
-               if (txq->q.read_ptr != (scd_ssn & 0xff)) {
-                       idx = il_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd);
-                       D_TX_REPLY("Retry scheduler reclaim scd_ssn "
-                                  "%d idx %d\n", scd_ssn, idx);
-                       freed = il4965_tx_queue_reclaim(il, txq_id, idx);
-                       if (qc)
-                               il4965_free_tfds_in_queue(il, sta_id, tid,
-                                                         freed);
-
-                       if (il->mac80211_registered &&
-                           il_queue_space(&txq->q) > txq->q.low_mark &&
-                           agg->state != IL_EMPTYING_HW_QUEUE_DELBA)
-                               il_wake_queue(il, txq);
-               }
-       } else {
-               info->status.rates[0].count = tx_resp->failure_frame + 1;
-               info->flags |= il4965_tx_status_to_mac80211(status);
-               il4965_hwrate_to_tx_control(il,
-                                           le32_to_cpu(tx_resp->rate_n_flags),
-                                           info);
-
-               D_TX_REPLY("TXQ %d status %s (0x%08x) "
-                          "rate_n_flags 0x%x retries %d\n", txq_id,
-                          il4965_get_tx_fail_reason(status), status,
-                          le32_to_cpu(tx_resp->rate_n_flags),
-                          tx_resp->failure_frame);
-
-               freed = il4965_tx_queue_reclaim(il, txq_id, idx);
-               if (qc && likely(sta_id != IL_INVALID_STATION))
-                       il4965_free_tfds_in_queue(il, sta_id, tid, freed);
-               else if (sta_id == IL_INVALID_STATION)
-                       D_TX_REPLY("Station not known\n");
-
-               if (il->mac80211_registered &&
-                   il_queue_space(&txq->q) > txq->q.low_mark)
-                       il_wake_queue(il, txq);
-       }
-       if (qc && likely(sta_id != IL_INVALID_STATION))
-               il4965_txq_check_empty(il, sta_id, tid, txq_id);
-
-       il4965_check_abort_status(il, tx_resp->frame_count, status);
-
-       spin_unlock_irqrestore(&il->sta_lock, flags);
-}
-
-/* Set up 4965-specific Rx frame reply handlers */
-static void
-il4965_handler_setup(struct il_priv *il)
-{
-       /* Legacy Rx frames */
-       il->handlers[N_RX] = il4965_hdl_rx;
-       /* Tx response */
-       il->handlers[C_TX] = il4965_hdl_tx;
-}
-
-static struct il_hcmd_ops il4965_hcmd = {
-       .rxon_assoc = il4965_send_rxon_assoc,
-       .commit_rxon = il4965_commit_rxon,
-       .set_rxon_chain = il4965_set_rxon_chain,
-};
-
 static void
 il4965_post_scan(struct il_priv *il)
 {
@@ -2093,8 +1772,8 @@ il4965_post_associate(struct il_priv *il)
 
        il_set_rxon_ht(il, &il->current_ht_config);
 
-       if (il->ops->hcmd->set_rxon_chain)
-               il->ops->hcmd->set_rxon_chain(il);
+       if (il->ops->set_rxon_chain)
+               il->ops->set_rxon_chain(il);
 
        il->staging.assoc_id = cpu_to_le16(vif->bss_conf.aid);
 
@@ -2168,8 +1847,8 @@ il4965_config_ap(struct il_priv *il)
                /* AP has all antennas */
                il->chain_noise_data.active_chains = il->hw_params.valid_rx_ant;
                il_set_rxon_ht(il, &il->current_ht_config);
-               if (il->ops->hcmd->set_rxon_chain)
-                       il->ops->hcmd->set_rxon_chain(il);
+               if (il->ops->set_rxon_chain)
+                       il->ops->set_rxon_chain(il);
 
                il->staging.assoc_id = 0;
 
@@ -2193,68 +1872,38 @@ il4965_config_ap(struct il_priv *il)
        il4965_send_beacon_cmd(il);
 }
 
-static struct il_hcmd_utils_ops il4965_hcmd_utils = {
-       .get_hcmd_size = il4965_get_hcmd_size,
-       .build_addsta_hcmd = il4965_build_addsta_hcmd,
-       .request_scan = il4965_request_scan,
-       .post_scan = il4965_post_scan,
-};
-
-static struct il_lib_ops il4965_lib = {
+const struct il_ops il4965_ops = {
        .txq_update_byte_cnt_tbl = il4965_txq_update_byte_cnt_tbl,
        .txq_attach_buf_to_tfd = il4965_hw_txq_attach_buf_to_tfd,
        .txq_free_tfd = il4965_hw_txq_free_tfd,
        .txq_init = il4965_hw_tx_queue_init,
-       .handler_setup = il4965_handler_setup,
        .is_valid_rtc_data_addr = il4965_hw_valid_rtc_data_addr,
        .init_alive_start = il4965_init_alive_start,
        .load_ucode = il4965_load_bsm,
        .dump_nic_error_log = il4965_dump_nic_error_log,
        .dump_fh = il4965_dump_fh,
        .set_channel_switch = il4965_hw_channel_switch,
-       .apm_ops = {
-                   .init = il_apm_init,
-                   .config = il4965_nic_config,
-                   },
-       .eeprom_ops = {
-                      .regulatory_bands = {
-                                           EEPROM_REGULATORY_BAND_1_CHANNELS,
-                                           EEPROM_REGULATORY_BAND_2_CHANNELS,
-                                           EEPROM_REGULATORY_BAND_3_CHANNELS,
-                                           EEPROM_REGULATORY_BAND_4_CHANNELS,
-                                           EEPROM_REGULATORY_BAND_5_CHANNELS,
-                                           EEPROM_4965_REGULATORY_BAND_24_HT40_CHANNELS,
-                                           EEPROM_4965_REGULATORY_BAND_52_HT40_CHANNELS},
-                      .acquire_semaphore = il4965_eeprom_acquire_semaphore,
-                      .release_semaphore = il4965_eeprom_release_semaphore,
-                      },
+       .apm_init = il_apm_init,
        .send_tx_power = il4965_send_tx_power,
        .update_chain_flags = il4965_update_chain_flags,
-       .temp_ops = {
-                    .temperature = il4965_temperature_calib,
-                    },
-#ifdef CONFIG_IWLEGACY_DEBUGFS
-       .debugfs_ops = {
-                       .rx_stats_read = il4965_ucode_rx_stats_read,
-                       .tx_stats_read = il4965_ucode_tx_stats_read,
-                       .general_stats_read = il4965_ucode_general_stats_read,
-                       },
-#endif
-};
+       .eeprom_acquire_semaphore = il4965_eeprom_acquire_semaphore,
+       .eeprom_release_semaphore = il4965_eeprom_release_semaphore,
+
+       .rxon_assoc = il4965_send_rxon_assoc,
+       .commit_rxon = il4965_commit_rxon,
+       .set_rxon_chain = il4965_set_rxon_chain,
+
+       .get_hcmd_size = il4965_get_hcmd_size,
+       .build_addsta_hcmd = il4965_build_addsta_hcmd,
+       .request_scan = il4965_request_scan,
+       .post_scan = il4965_post_scan,
 
-static const struct il_legacy_ops il4965_legacy_ops = {
        .post_associate = il4965_post_associate,
        .config_ap = il4965_config_ap,
        .manage_ibss_station = il4965_manage_ibss_station,
        .update_bcast_stations = il4965_update_bcast_stations,
-};
 
-const struct il_ops il4965_ops = {
-       .lib = &il4965_lib,
-       .hcmd = &il4965_hcmd,
-       .utils = &il4965_hcmd_utils,
-       .led = &il4965_led_ops,
-       .legacy = &il4965_legacy_ops,
+       .send_led_cmd = il4965_send_led_cmd,
 };
 
 struct il_cfg il4965_cfg = {
@@ -2288,6 +1937,17 @@ struct il_cfg il4965_cfg = {
        .ucode_tracing = true,
        .sensitivity_calib_by_driver = true,
        .chain_noise_calib_by_driver = true,
+
+       .regulatory_bands = {
+               EEPROM_REGULATORY_BAND_1_CHANNELS,
+               EEPROM_REGULATORY_BAND_2_CHANNELS,
+               EEPROM_REGULATORY_BAND_3_CHANNELS,
+               EEPROM_REGULATORY_BAND_4_CHANNELS,
+               EEPROM_REGULATORY_BAND_5_CHANNELS,
+               EEPROM_4965_REGULATORY_BAND_24_HT40_CHANNELS,
+               EEPROM_4965_REGULATORY_BAND_52_HT40_CHANNELS
+       },
+
 };
 
 /* Module firmware */
index 83ab60496388e2b40a62cee01faec0b3fde491ff..1db677689cfe36b18940c406e302519c51591bef 100644 (file)
@@ -60,6 +60,8 @@ int il4965_rx_init(struct il_priv *il, struct il_rx_queue *rxq);
 int il4965_hw_nic_init(struct il_priv *il);
 int il4965_dump_fh(struct il_priv *il, char **buf, bool display);
 
+void il4965_nic_config(struct il_priv *il);
+
 /* rx */
 void il4965_rx_queue_restock(struct il_priv *il);
 void il4965_rx_replenish(struct il_priv *il);
@@ -67,8 +69,6 @@ void il4965_rx_replenish_now(struct il_priv *il);
 void il4965_rx_queue_free(struct il_priv *il, struct il_rx_queue *rxq);
 int il4965_rxq_stop(struct il_priv *il);
 int il4965_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band);
-void il4965_hdl_rx(struct il_priv *il, struct il_rx_buf *rxb);
-void il4965_hdl_rx_phy(struct il_priv *il, struct il_rx_buf *rxb);
 void il4965_rx_handle(struct il_priv *il);
 
 /* tx */
@@ -84,7 +84,6 @@ int il4965_tx_agg_start(struct il_priv *il, struct ieee80211_vif *vif,
 int il4965_tx_agg_stop(struct il_priv *il, struct ieee80211_vif *vif,
                       struct ieee80211_sta *sta, u16 tid);
 int il4965_txq_check_empty(struct il_priv *il, int sta_id, u8 tid, int txq_id);
-void il4965_hdl_compressed_ba(struct il_priv *il, struct il_rx_buf *rxb);
 int il4965_tx_queue_reclaim(struct il_priv *il, int txq_id, int idx);
 void il4965_hw_txq_ctx_free(struct il_priv *il);
 int il4965_txq_ctx_alloc(struct il_priv *il);
@@ -106,12 +105,6 @@ void il4965_set_wr_ptrs(struct il_priv *il, int txq_id, u32 idx);
 void il4965_tx_queue_set_status(struct il_priv *il, struct il_tx_queue *txq,
                                int tx_fifo_id, int scd_retry);
 
-/* rx */
-void il4965_hdl_missed_beacon(struct il_priv *il, struct il_rx_buf *rxb);
-bool il4965_good_plcp_health(struct il_priv *il, struct il_rx_pkt *pkt);
-void il4965_hdl_stats(struct il_priv *il, struct il_rx_buf *rxb);
-void il4965_hdl_c_stats(struct il_priv *il, struct il_rx_buf *rxb);
-
 /* scan */
 int il4965_request_scan(struct il_priv *il, struct ieee80211_vif *vif);
 
@@ -275,6 +268,7 @@ il4965_hw_valid_rtc_data_addr(u32 addr)
        ((t) < IL_TX_POWER_TEMPERATURE_MIN || \
         (t) > IL_TX_POWER_TEMPERATURE_MAX)
 
+extern void il4965_temperature_calib(struct il_priv *il);
 /********************* END TEMPERATURE ***************************************/
 
 /********************* START TXPOWER *****************************************/
@@ -933,17 +927,10 @@ void il4965_chain_noise_calibration(struct il_priv *il, void *stat_resp);
 void il4965_sensitivity_calibration(struct il_priv *il, void *resp);
 void il4965_init_sensitivity(struct il_priv *il);
 void il4965_reset_run_time_calib(struct il_priv *il);
-void il4965_calib_free_results(struct il_priv *il);
 
 /* Debug */
 #ifdef CONFIG_IWLEGACY_DEBUGFS
-ssize_t il4965_ucode_rx_stats_read(struct file *file, char __user *user_buf,
-                                  size_t count, loff_t *ppos);
-ssize_t il4965_ucode_tx_stats_read(struct file *file, char __user *user_buf,
-                                  size_t count, loff_t *ppos);
-ssize_t il4965_ucode_general_stats_read(struct file *file,
-                                       char __user *user_buf, size_t count,
-                                       loff_t *ppos);
+extern const struct il_debugfs_ops il4965_debugfs_ops;
 #endif
 
 /****************************/
index 05bd375cb845b73fbf94401ba57bfc50c59d448d..fb919727b8bb520bc32f2c151997e1d33c721eab 100644 (file)
@@ -6,45 +6,6 @@ config IWLEGACY
        select LEDS_TRIGGERS
        select MAC80211_LEDS
 
-menu "Debugging Options"
-       depends on IWLEGACY
-
-config IWLEGACY_DEBUG
-       bool "Enable full debugging output in iwlegacy (iwl 3945/4965) drivers"
-       depends on IWLEGACY
-       ---help---
-         This option will enable debug tracing output for the iwlegacy
-         drivers.
-
-         This will result in the kernel module being ~100k larger.  You can
-         control which debug output is sent to the kernel log by setting the
-         value in
-
-               /sys/class/net/wlan0/device/debug_level
-
-         This entry will only exist if this option is enabled.
-
-         To set a value, simply echo an 8-byte hex value to the same file:
-
-                 % echo 0x43fff > /sys/class/net/wlan0/device/debug_level
-
-         You can find the list of debug mask values in:
-                 drivers/net/wireless/iwlegacy/common.h
-
-         If this is your first time using this driver, you should say Y here
-         as the debug information can assist others in helping you resolve
-         any problems you may encounter.
-
-config IWLEGACY_DEBUGFS
-        bool "iwlegacy (iwl 3945/4965) debugfs support"
-        depends on IWLEGACY && MAC80211_DEBUGFS
-        ---help---
-         Enable creation of debugfs files for the iwlegacy drivers. This
-         is a low-impact option that allows getting insight into the
-         driver's state at runtime.
-
-endmenu
-
 config IWL4965
        tristate "Intel Wireless WiFi 4965AGN (iwl4965)"
        depends on PCI && MAC80211
@@ -98,3 +59,42 @@ config IWL3945
          inserted in and removed from the running kernel whenever you want),
          say M here and read <file:Documentation/kbuild/modules.txt>.  The
          module will be called iwl3945.
+
+menu "iwl3945 / iwl4965 Debugging Options"
+       depends on IWLEGACY
+
+config IWLEGACY_DEBUG
+       bool "Enable full debugging output in iwlegacy (iwl 3945/4965) drivers"
+       depends on IWLEGACY
+       ---help---
+         This option will enable debug tracing output for the iwlegacy
+         drivers.
+
+         This will result in the kernel module being ~100k larger.  You can
+         control which debug output is sent to the kernel log by setting the
+         value in
+
+               /sys/class/net/wlan0/device/debug_level
+
+         This entry will only exist if this option is enabled.
+
+         To set a value, simply echo an 8-byte hex value to the same file:
+
+                 % echo 0x43fff > /sys/class/net/wlan0/device/debug_level
+
+         You can find the list of debug mask values in:
+                 drivers/net/wireless/iwlegacy/common.h
+
+         If this is your first time using this driver, you should say Y here
+         as the debug information can assist others in helping you resolve
+         any problems you may encounter.
+
+config IWLEGACY_DEBUGFS
+        bool "iwlegacy (iwl 3945/4965) debugfs support"
+        depends on IWLEGACY && MAC80211_DEBUGFS
+        ---help---
+         Enable creation of debugfs files for the iwlegacy drivers. This
+         is a low-impact option that allows getting insight into the
+         driver's state at runtime.
+
+endmenu
index 04ec38e5eaaf61308b5dee23d269908a0c5045c2..b42052b47d8e290ebede79489c70aa094cd3f3bf 100644 (file)
@@ -81,7 +81,7 @@ il_clear_bit(struct il_priv *p, u32 r, u32 m)
 }
 EXPORT_SYMBOL(il_clear_bit);
 
-int
+bool
 _il_grab_nic_access(struct il_priv *il)
 {
        int ret;
@@ -111,14 +111,15 @@ _il_grab_nic_access(struct il_priv *il)
            _il_poll_bit(il, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
                         (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
                          CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000);
-       if (ret < 0) {
+       if (unlikely(ret < 0)) {
                val = _il_rd(il, CSR_GP_CNTRL);
-               IL_ERR("MAC is in deep sleep!.  CSR_GP_CNTRL = 0x%08X\n", val);
+               WARN_ONCE(1, "Timeout waiting for ucode processor access "
+                            "(CSR_GP_CNTRL 0x%08x)\n", val);
                _il_wr(il, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI);
-               return -EIO;
+               return false;
        }
 
-       return 0;
+       return true;
 }
 EXPORT_SYMBOL_GPL(_il_grab_nic_access);
 
@@ -160,7 +161,7 @@ il_wr_prph(struct il_priv *il, u32 addr, u32 val)
        unsigned long reg_flags;
 
        spin_lock_irqsave(&il->reg_lock, reg_flags);
-       if (!_il_grab_nic_access(il)) {
+       if (likely(_il_grab_nic_access(il))) {
                _il_wr_prph(il, addr, val);
                _il_release_nic_access(il);
        }
@@ -178,7 +179,6 @@ il_read_targ_mem(struct il_priv *il, u32 addr)
        _il_grab_nic_access(il);
 
        _il_wr(il, HBUS_TARG_MEM_RADDR, addr);
-       rmb();
        value = _il_rd(il, HBUS_TARG_MEM_RDAT);
 
        _il_release_nic_access(il);
@@ -193,9 +193,8 @@ il_write_targ_mem(struct il_priv *il, u32 addr, u32 val)
        unsigned long reg_flags;
 
        spin_lock_irqsave(&il->reg_lock, reg_flags);
-       if (!_il_grab_nic_access(il)) {
+       if (likely(_il_grab_nic_access(il))) {
                _il_wr(il, HBUS_TARG_MEM_WADDR, addr);
-               wmb();
                _il_wr(il, HBUS_TARG_MEM_WDAT, val);
                _il_release_nic_access(il);
        }
@@ -351,7 +350,7 @@ il_send_cmd_sync(struct il_priv *il, struct il_host_cmd *cmd)
                }
        }
 
-       if (test_bit(S_RF_KILL_HW, &il->status)) {
+       if (test_bit(S_RFKILL, &il->status)) {
                IL_ERR("Command %s aborted: RF KILL Switch\n",
                       il_get_cmd_string(cmd->id));
                ret = -ECANCELED;
@@ -520,7 +519,7 @@ il_led_cmd(struct il_priv *il, unsigned long on, unsigned long off)
            il_blink_compensation(il, off,
                                  il->cfg->led_compensation);
 
-       ret = il->ops->led->cmd(il, &led_cmd);
+       ret = il->ops->send_led_cmd(il, &led_cmd);
        if (!ret) {
                il->blink_on = on;
                il->blink_off = off;
@@ -731,7 +730,7 @@ il_eeprom_init(struct il_priv *il)
        }
        e = (__le16 *) il->eeprom;
 
-       il->ops->lib->apm_ops.init(il);
+       il->ops->apm_init(il);
 
        ret = il_eeprom_verify_signature(il);
        if (ret < 0) {
@@ -741,7 +740,7 @@ il_eeprom_init(struct il_priv *il)
        }
 
        /* Make sure driver (instead of uCode) is allowed to read EEPROM */
-       ret = il->ops->lib->eeprom_ops.acquire_semaphore(il);
+       ret = il->ops->eeprom_acquire_semaphore(il);
        if (ret < 0) {
                IL_ERR("Failed to acquire EEPROM semaphore.\n");
                ret = -ENOENT;
@@ -773,7 +772,7 @@ il_eeprom_init(struct il_priv *il)
 
        ret = 0;
 done:
-       il->ops->lib->eeprom_ops.release_semaphore(il);
+       il->ops->eeprom_release_semaphore(il);
 
 err:
        if (ret)
@@ -799,8 +798,8 @@ il_init_band_reference(const struct il_priv *il, int eep_band,
                       const struct il_eeprom_channel **eeprom_ch_info,
                       const u8 **eeprom_ch_idx)
 {
-       u32 offset =
-           il->ops->lib->eeprom_ops.regulatory_bands[eep_band - 1];
+       u32 offset = il->cfg->regulatory_bands[eep_band - 1];
+
        switch (eep_band) {
        case 1:         /* 2.4GHz band */
                *eeprom_ch_count = ARRAY_SIZE(il_eeprom_band_1);
@@ -1001,10 +1000,8 @@ il_init_channel_map(struct il_priv *il)
        }
 
        /* Check if we do have HT40 channels */
-       if (il->ops->lib->eeprom_ops.regulatory_bands[5] ==
-           EEPROM_REGULATORY_BAND_NO_HT40 &&
-           il->ops->lib->eeprom_ops.regulatory_bands[6] ==
-           EEPROM_REGULATORY_BAND_NO_HT40)
+       if (il->cfg->regulatory_bands[5] == EEPROM_REGULATORY_BAND_NO_HT40 &&
+           il->cfg->regulatory_bands[6] == EEPROM_REGULATORY_BAND_NO_HT40)
                return 0;
 
        /* Two additional EEPROM bands for 2.4 and 5 GHz HT40 channels */
@@ -1158,9 +1155,9 @@ il_power_set_mode(struct il_priv *il, struct il_powertable_cmd *cmd, bool force)
                if (!(cmd->flags & IL_POWER_DRIVER_ALLOW_SLEEP_MSK))
                        clear_bit(S_POWER_PMI, &il->status);
 
-               if (il->ops->lib->update_chain_flags && update_chains)
-                       il->ops->lib->update_chain_flags(il);
-               else if (il->ops->lib->update_chain_flags)
+               if (il->ops->update_chain_flags && update_chains)
+                       il->ops->update_chain_flags(il);
+               else if (il->ops->update_chain_flags)
                        D_POWER("Cannot update the power, chain noise "
                                "calibration running: %d\n",
                                il->chain_noise_data.state);
@@ -1485,9 +1482,6 @@ il_scan_initiate(struct il_priv *il, struct ieee80211_vif *vif)
 
        lockdep_assert_held(&il->mutex);
 
-       if (WARN_ON(!il->ops->utils->request_scan))
-               return -EOPNOTSUPP;
-
        cancel_delayed_work(&il->scan_check);
 
        if (!il_is_ready_rf(il)) {
@@ -1510,7 +1504,7 @@ il_scan_initiate(struct il_priv *il, struct ieee80211_vif *vif)
        set_bit(S_SCANNING, &il->status);
        il->scan_start = jiffies;
 
-       ret = il->ops->utils->request_scan(il, vif);
+       ret = il->ops->request_scan(il, vif);
        if (ret) {
                clear_bit(S_SCANNING, &il->status);
                return ret;
@@ -1529,12 +1523,13 @@ il_mac_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
        struct il_priv *il = hw->priv;
        int ret;
 
-       D_MAC80211("enter\n");
-
-       if (req->n_channels == 0)
+       if (req->n_channels == 0) {
+               IL_ERR("Can not scan on no channels.\n");
                return -EINVAL;
+       }
 
        mutex_lock(&il->mutex);
+       D_MAC80211("enter\n");
 
        if (test_bit(S_SCANNING, &il->status)) {
                D_SCAN("Scan already in progress.\n");
@@ -1549,9 +1544,8 @@ il_mac_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 
        ret = il_scan_initiate(il, vif);
 
-       D_MAC80211("leave\n");
-
 out_unlock:
+       D_MAC80211("leave ret %d\n", ret);
        mutex_unlock(&il->mutex);
 
        return ret;
@@ -1672,7 +1666,7 @@ out_settings:
        il_power_set_mode(il, &il->power_data.sleep_cmd_next, false);
        il_set_tx_power(il, il->tx_power_next, false);
 
-       il->ops->utils->post_scan(il);
+       il->ops->post_scan(il);
 
 out:
        mutex_unlock(&il->mutex);
@@ -1814,7 +1808,7 @@ il_send_add_sta(struct il_priv *il, struct il_addsta_cmd *sta, u8 flags)
                might_sleep();
        }
 
-       cmd.len = il->ops->utils->build_addsta_hcmd(sta, data);
+       cmd.len = il->ops->build_addsta_hcmd(sta, data);
        ret = il_send_cmd(il, &cmd);
 
        if (ret || (flags & CMD_ASYNC))
@@ -2419,13 +2413,16 @@ il_mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
        struct il_station_priv_common *sta_common = (void *)sta->drv_priv;
        int ret;
 
-       D_INFO("received request to remove station %pM\n", sta->addr);
        mutex_lock(&il->mutex);
-       D_INFO("proceeding to remove station %pM\n", sta->addr);
+       D_MAC80211("enter station %pM\n", sta->addr);
+
        ret = il_remove_station(il, sta_common->sta_id, sta->addr);
        if (ret)
                IL_ERR("Error removing station %pM\n", sta->addr);
+
+       D_MAC80211("leave ret %d\n", ret);
        mutex_unlock(&il->mutex);
+
        return ret;
 }
 EXPORT_SYMBOL(il_mac_sta_remove);
@@ -2722,7 +2719,7 @@ il_tx_queue_unmap(struct il_priv *il, int txq_id)
                return;
 
        while (q->write_ptr != q->read_ptr) {
-               il->ops->lib->txq_free_tfd(il, txq);
+               il->ops->txq_free_tfd(il, txq);
                q->read_ptr = il_queue_inc_wrap(q->read_ptr, q->n_bd);
        }
 }
@@ -2890,20 +2887,22 @@ EXPORT_SYMBOL(il_queue_space);
  * il_queue_init - Initialize queue's high/low-water and read/write idxes
  */
 static int
-il_queue_init(struct il_priv *il, struct il_queue *q, int count, int slots_num,
-             u32 id)
+il_queue_init(struct il_priv *il, struct il_queue *q, int slots, u32 id)
 {
-       q->n_bd = count;
-       q->n_win = slots_num;
-       q->id = id;
+       /*
+        * TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
+        * il_queue_inc_wrap and il_queue_dec_wrap are broken.
+        */
+       BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
+       /* FIXME: remove q->n_bd */
+       q->n_bd = TFD_QUEUE_SIZE_MAX;
 
-       /* count must be power-of-two size, otherwise il_queue_inc_wrap
-        * and il_queue_dec_wrap are broken. */
-       BUG_ON(!is_power_of_2(count));
+       q->n_win = slots;
+       q->id = id;
 
-       /* slots_num must be power-of-two size, otherwise
+       /* slots_must be power-of-two size, otherwise
         * il_get_cmd_idx is broken. */
-       BUG_ON(!is_power_of_2(slots_num));
+       BUG_ON(!is_power_of_2(slots));
 
        q->low_mark = q->n_win / 4;
        if (q->low_mark < 4)
@@ -2962,12 +2961,11 @@ error:
  * il_tx_queue_init - Allocate and initialize one tx/cmd queue
  */
 int
-il_tx_queue_init(struct il_priv *il, struct il_tx_queue *txq, int slots_num,
-                u32 txq_id)
+il_tx_queue_init(struct il_priv *il, u32 txq_id)
 {
-       int i, len;
-       int ret;
-       int actual_slots = slots_num;
+       int i, len, ret;
+       int slots, actual_slots;
+       struct il_tx_queue *txq = &il->txq[txq_id];
 
        /*
         * Alloc buffer array for commands (Tx or other types of commands).
@@ -2977,8 +2975,13 @@ il_tx_queue_init(struct il_priv *il, struct il_tx_queue *txq, int slots_num,
         * For normal Tx queues (all other queues), no super-size command
         * space is needed.
         */
-       if (txq_id == il->cmd_queue)
-               actual_slots++;
+       if (txq_id == il->cmd_queue) {
+               slots = TFD_CMD_SLOTS;
+               actual_slots = slots + 1;
+       } else {
+               slots = TFD_TX_CMD_SLOTS;
+               actual_slots = slots;
+       }
 
        txq->meta =
            kzalloc(sizeof(struct il_cmd_meta) * actual_slots, GFP_KERNEL);
@@ -2991,7 +2994,7 @@ il_tx_queue_init(struct il_priv *il, struct il_tx_queue *txq, int slots_num,
        len = sizeof(struct il_device_cmd);
        for (i = 0; i < actual_slots; i++) {
                /* only happens for cmd queue */
-               if (i == slots_num)
+               if (i == slots)
                        len = IL_MAX_CMD_SIZE;
 
                txq->cmd[i] = kmalloc(len, GFP_KERNEL);
@@ -3014,15 +3017,11 @@ il_tx_queue_init(struct il_priv *il, struct il_tx_queue *txq, int slots_num,
        if (txq_id < 4)
                il_set_swq_id(txq, txq_id, txq_id);
 
-       /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
-        * il_queue_inc_wrap and il_queue_dec_wrap are broken. */
-       BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
-
        /* Initialize queue's high/low-water marks, and head/tail idxes */
-       il_queue_init(il, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
+       il_queue_init(il, &txq->q, slots, txq_id);
 
        /* Tell device where to find queue */
-       il->ops->lib->txq_init(il, txq);
+       il->ops->txq_init(il, txq);
 
        return 0;
 err:
@@ -3037,23 +3036,27 @@ out_free_arrays:
 EXPORT_SYMBOL(il_tx_queue_init);
 
 void
-il_tx_queue_reset(struct il_priv *il, struct il_tx_queue *txq, int slots_num,
-                 u32 txq_id)
+il_tx_queue_reset(struct il_priv *il, u32 txq_id)
 {
-       int actual_slots = slots_num;
+       int slots, actual_slots;
+       struct il_tx_queue *txq = &il->txq[txq_id];
 
-       if (txq_id == il->cmd_queue)
-               actual_slots++;
+       if (txq_id == il->cmd_queue) {
+               slots = TFD_CMD_SLOTS;
+               actual_slots = TFD_CMD_SLOTS + 1;
+       } else {
+               slots = TFD_TX_CMD_SLOTS;
+               actual_slots = TFD_TX_CMD_SLOTS;
+       }
 
        memset(txq->meta, 0, sizeof(struct il_cmd_meta) * actual_slots);
-
        txq->need_update = 0;
 
        /* Initialize queue's high/low-water marks, and head/tail idxes */
-       il_queue_init(il, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
+       il_queue_init(il, &txq->q, slots, txq_id);
 
        /* Tell device where to find queue */
-       il->ops->lib->txq_init(il, txq);
+       il->ops->txq_init(il, txq);
 }
 EXPORT_SYMBOL(il_tx_queue_reset);
 
@@ -3081,7 +3084,7 @@ il_enqueue_hcmd(struct il_priv *il, struct il_host_cmd *cmd)
        u32 idx;
        u16 fix_size;
 
-       cmd->len = il->ops->utils->get_hcmd_size(cmd->id, cmd->len);
+       cmd->len = il->ops->get_hcmd_size(cmd->id, cmd->len);
        fix_size = (u16) (cmd->len + sizeof(out_cmd->hdr));
 
        /* If any of the command structures end up being larger than
@@ -3160,9 +3163,9 @@ il_enqueue_hcmd(struct il_priv *il, struct il_host_cmd *cmd)
 #endif
        txq->need_update = 1;
 
-       if (il->ops->lib->txq_update_byte_cnt_tbl)
+       if (il->ops->txq_update_byte_cnt_tbl)
                /* Set up entry in queue's byte count circular buffer */
-               il->ops->lib->txq_update_byte_cnt_tbl(il, txq, 0);
+               il->ops->txq_update_byte_cnt_tbl(il, txq, 0);
 
        phys_addr =
            pci_map_single(il->pci_dev, &out_cmd->hdr, fix_size,
@@ -3170,7 +3173,7 @@ il_enqueue_hcmd(struct il_priv *il, struct il_host_cmd *cmd)
        dma_unmap_addr_set(out_meta, mapping, phys_addr);
        dma_unmap_len_set(out_meta, len, fix_size);
 
-       il->ops->lib->txq_attach_buf_to_tfd(il, txq, phys_addr, fix_size, 1,
+       il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, fix_size, 1,
                                            U32_PAD(cmd->len));
 
        /* Increment and update queue's write idx */
@@ -3845,8 +3848,8 @@ _il_set_rxon_ht(struct il_priv *il, struct il_ht_config *ht_conf)
                rxon->flags |= RXON_FLG_CHANNEL_MODE_LEGACY;
        }
 
-       if (il->ops->hcmd->set_rxon_chain)
-               il->ops->hcmd->set_rxon_chain(il);
+       if (il->ops->set_rxon_chain)
+               il->ops->set_rxon_chain(il);
 
        D_ASSOC("rxon flags 0x%X operation mode :0x%X "
                "extension channel offset 0x%x\n", le32_to_cpu(rxon->flags),
@@ -4104,9 +4107,9 @@ il_irq_handle_error(struct il_priv *il)
 
        IL_ERR("Loaded firmware version: %s\n", il->hw->wiphy->fw_version);
 
-       il->ops->lib->dump_nic_error_log(il);
-       if (il->ops->lib->dump_fh)
-               il->ops->lib->dump_fh(il, NULL, false);
+       il->ops->dump_nic_error_log(il);
+       if (il->ops->dump_fh)
+               il->ops->dump_fh(il, NULL, false);
 #ifdef CONFIG_IWLEGACY_DEBUG
        if (il_get_debug_level(il) & IL_DL_FW_ERRORS)
                il_print_rx_config_cmd(il);
@@ -4129,17 +4132,17 @@ il_irq_handle_error(struct il_priv *il)
 EXPORT_SYMBOL(il_irq_handle_error);
 
 static int
-il_apm_stop_master(struct il_priv *il)
+_il_apm_stop_master(struct il_priv *il)
 {
        int ret = 0;
 
        /* stop device's busmaster DMA activity */
-       il_set_bit(il, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
+       _il_set_bit(il, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
 
        ret =
            _il_poll_bit(il, CSR_RESET, CSR_RESET_REG_FLAG_MASTER_DISABLED,
                         CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
-       if (ret)
+       if (ret < 0)
                IL_WARN("Master Disable Timed Out, 100 usec\n");
 
        D_INFO("stop master\n");
@@ -4148,15 +4151,17 @@ il_apm_stop_master(struct il_priv *il)
 }
 
 void
-il_apm_stop(struct il_priv *il)
+_il_apm_stop(struct il_priv *il)
 {
+       lockdep_assert_held(&il->reg_lock);
+
        D_INFO("Stop card, put in low power state\n");
 
        /* Stop device's DMA activity */
-       il_apm_stop_master(il);
+       _il_apm_stop_master(il);
 
        /* Reset the entire device */
-       il_set_bit(il, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+       _il_set_bit(il, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
 
        udelay(10);
 
@@ -4164,7 +4169,18 @@ il_apm_stop(struct il_priv *il)
         * Clear "initialization complete" bit to move adapter from
         * D0A* (powered-up Active) --> D0U* (Uninitialized) state.
         */
-       il_clear_bit(il, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+       _il_clear_bit(il, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+}
+EXPORT_SYMBOL(_il_apm_stop);
+
+void
+il_apm_stop(struct il_priv *il)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&il->reg_lock, flags);
+       _il_apm_stop(il);
+       spin_unlock_irqrestore(&il->reg_lock, flags);
 }
 EXPORT_SYMBOL(il_apm_stop);
 
@@ -4293,7 +4309,7 @@ il_set_tx_power(struct il_priv *il, s8 tx_power, bool force)
        if (il->tx_power_user_lmt == tx_power && !force)
                return 0;
 
-       if (!il->ops->lib->send_tx_power)
+       if (!il->ops->send_tx_power)
                return -EOPNOTSUPP;
 
        /* 0 dBm mean 1 milliwatt */
@@ -4326,7 +4342,7 @@ il_set_tx_power(struct il_priv *il, s8 tx_power, bool force)
        prev_tx_power = il->tx_power_user_lmt;
        il->tx_power_user_lmt = tx_power;
 
-       ret = il->ops->lib->send_tx_power(il);
+       ret = il->ops->send_tx_power(il);
 
        /* if fail to set tx_power, restore the orig. tx power */
        if (ret) {
@@ -4465,8 +4481,14 @@ int
 il_mac_tx_last_beacon(struct ieee80211_hw *hw)
 {
        struct il_priv *il = hw->priv;
+       int ret;
 
-       return il->ibss_manager == IL_IBSS_MANAGER;
+       D_MAC80211("enter\n");
+
+       ret = (il->ibss_manager == IL_IBSS_MANAGER);
+
+       D_MAC80211("leave ret %d\n", ret);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(il_mac_tx_last_beacon);
 
@@ -4475,8 +4497,8 @@ il_set_mode(struct il_priv *il)
 {
        il_connection_init_rx_config(il);
 
-       if (il->ops->hcmd->set_rxon_chain)
-               il->ops->hcmd->set_rxon_chain(il);
+       if (il->ops->set_rxon_chain)
+               il->ops->set_rxon_chain(il);
 
        return il_commit_rxon(il);
 }
@@ -4487,9 +4509,8 @@ il_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
        struct il_priv *il = hw->priv;
        int err;
 
-       D_MAC80211("enter: type %d, addr %pM\n", vif->type, vif->addr);
-
        mutex_lock(&il->mutex);
+       D_MAC80211("enter: type %d, addr %pM\n", vif->type, vif->addr);
 
        if (!il_is_ready_rf(il)) {
                IL_WARN("Try to add interface when device not ready\n");
@@ -4512,9 +4533,9 @@ il_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
        }
 
 out:
+       D_MAC80211("leave err %d\n", err);
        mutex_unlock(&il->mutex);
 
-       D_MAC80211("leave\n");
        return err;
 }
 EXPORT_SYMBOL(il_mac_add_interface);
@@ -4540,20 +4561,17 @@ il_mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
        struct il_priv *il = hw->priv;
 
-       D_MAC80211("enter\n");
-
        mutex_lock(&il->mutex);
+       D_MAC80211("enter: type %d, addr %pM\n", vif->type, vif->addr);
 
        WARN_ON(il->vif != vif);
        il->vif = NULL;
 
        il_teardown_interface(il, vif, false);
-
        memset(il->bssid, 0, ETH_ALEN);
-       mutex_unlock(&il->mutex);
 
        D_MAC80211("leave\n");
-
+       mutex_unlock(&il->mutex);
 }
 EXPORT_SYMBOL(il_mac_remove_interface);
 
@@ -4573,259 +4591,12 @@ il_alloc_txq_mem(struct il_priv *il)
 EXPORT_SYMBOL(il_alloc_txq_mem);
 
 void
-il_txq_mem(struct il_priv *il)
+il_free_txq_mem(struct il_priv *il)
 {
        kfree(il->txq);
        il->txq = NULL;
 }
-EXPORT_SYMBOL(il_txq_mem);
-
-#ifdef CONFIG_IWLEGACY_DEBUGFS
-
-#define IL_TRAFFIC_DUMP_SIZE   (IL_TRAFFIC_ENTRY_SIZE * IL_TRAFFIC_ENTRIES)
-
-void
-il_reset_traffic_log(struct il_priv *il)
-{
-       il->tx_traffic_idx = 0;
-       il->rx_traffic_idx = 0;
-       if (il->tx_traffic)
-               memset(il->tx_traffic, 0, IL_TRAFFIC_DUMP_SIZE);
-       if (il->rx_traffic)
-               memset(il->rx_traffic, 0, IL_TRAFFIC_DUMP_SIZE);
-}
-
-int
-il_alloc_traffic_mem(struct il_priv *il)
-{
-       u32 traffic_size = IL_TRAFFIC_DUMP_SIZE;
-
-       if (il_debug_level & IL_DL_TX) {
-               if (!il->tx_traffic) {
-                       il->tx_traffic = kzalloc(traffic_size, GFP_KERNEL);
-                       if (!il->tx_traffic)
-                               return -ENOMEM;
-               }
-       }
-       if (il_debug_level & IL_DL_RX) {
-               if (!il->rx_traffic) {
-                       il->rx_traffic = kzalloc(traffic_size, GFP_KERNEL);
-                       if (!il->rx_traffic)
-                               return -ENOMEM;
-               }
-       }
-       il_reset_traffic_log(il);
-       return 0;
-}
-EXPORT_SYMBOL(il_alloc_traffic_mem);
-
-void
-il_free_traffic_mem(struct il_priv *il)
-{
-       kfree(il->tx_traffic);
-       il->tx_traffic = NULL;
-
-       kfree(il->rx_traffic);
-       il->rx_traffic = NULL;
-}
-EXPORT_SYMBOL(il_free_traffic_mem);
-
-void
-il_dbg_log_tx_data_frame(struct il_priv *il, u16 length,
-                        struct ieee80211_hdr *header)
-{
-       __le16 fc;
-       u16 len;
-
-       if (likely(!(il_debug_level & IL_DL_TX)))
-               return;
-
-       if (!il->tx_traffic)
-               return;
-
-       fc = header->frame_control;
-       if (ieee80211_is_data(fc)) {
-               len =
-                   (length >
-                    IL_TRAFFIC_ENTRY_SIZE) ? IL_TRAFFIC_ENTRY_SIZE : length;
-               memcpy((il->tx_traffic +
-                       (il->tx_traffic_idx * IL_TRAFFIC_ENTRY_SIZE)), header,
-                      len);
-               il->tx_traffic_idx =
-                   (il->tx_traffic_idx + 1) % IL_TRAFFIC_ENTRIES;
-       }
-}
-EXPORT_SYMBOL(il_dbg_log_tx_data_frame);
-
-void
-il_dbg_log_rx_data_frame(struct il_priv *il, u16 length,
-                        struct ieee80211_hdr *header)
-{
-       __le16 fc;
-       u16 len;
-
-       if (likely(!(il_debug_level & IL_DL_RX)))
-               return;
-
-       if (!il->rx_traffic)
-               return;
-
-       fc = header->frame_control;
-       if (ieee80211_is_data(fc)) {
-               len =
-                   (length >
-                    IL_TRAFFIC_ENTRY_SIZE) ? IL_TRAFFIC_ENTRY_SIZE : length;
-               memcpy((il->rx_traffic +
-                       (il->rx_traffic_idx * IL_TRAFFIC_ENTRY_SIZE)), header,
-                      len);
-               il->rx_traffic_idx =
-                   (il->rx_traffic_idx + 1) % IL_TRAFFIC_ENTRIES;
-       }
-}
-EXPORT_SYMBOL(il_dbg_log_rx_data_frame);
-
-const char *
-il_get_mgmt_string(int cmd)
-{
-       switch (cmd) {
-               IL_CMD(MANAGEMENT_ASSOC_REQ);
-               IL_CMD(MANAGEMENT_ASSOC_RESP);
-               IL_CMD(MANAGEMENT_REASSOC_REQ);
-               IL_CMD(MANAGEMENT_REASSOC_RESP);
-               IL_CMD(MANAGEMENT_PROBE_REQ);
-               IL_CMD(MANAGEMENT_PROBE_RESP);
-               IL_CMD(MANAGEMENT_BEACON);
-               IL_CMD(MANAGEMENT_ATIM);
-               IL_CMD(MANAGEMENT_DISASSOC);
-               IL_CMD(MANAGEMENT_AUTH);
-               IL_CMD(MANAGEMENT_DEAUTH);
-               IL_CMD(MANAGEMENT_ACTION);
-       default:
-               return "UNKNOWN";
-
-       }
-}
-
-const char *
-il_get_ctrl_string(int cmd)
-{
-       switch (cmd) {
-               IL_CMD(CONTROL_BACK_REQ);
-               IL_CMD(CONTROL_BACK);
-               IL_CMD(CONTROL_PSPOLL);
-               IL_CMD(CONTROL_RTS);
-               IL_CMD(CONTROL_CTS);
-               IL_CMD(CONTROL_ACK);
-               IL_CMD(CONTROL_CFEND);
-               IL_CMD(CONTROL_CFENDACK);
-       default:
-               return "UNKNOWN";
-
-       }
-}
-
-void
-il_clear_traffic_stats(struct il_priv *il)
-{
-       memset(&il->tx_stats, 0, sizeof(struct traffic_stats));
-       memset(&il->rx_stats, 0, sizeof(struct traffic_stats));
-}
-
-/*
- * if CONFIG_IWLEGACY_DEBUGFS defined,
- * il_update_stats function will
- * record all the MGMT, CTRL and DATA pkt for both TX and Rx pass
- * Use debugFs to display the rx/rx_stats
- * if CONFIG_IWLEGACY_DEBUGFS not being defined, then no MGMT and CTRL
- * information will be recorded, but DATA pkt still will be recorded
- * for the reason of il_led.c need to control the led blinking based on
- * number of tx and rx data.
- *
- */
-void
-il_update_stats(struct il_priv *il, bool is_tx, __le16 fc, u16 len)
-{
-       struct traffic_stats *stats;
-
-       if (is_tx)
-               stats = &il->tx_stats;
-       else
-               stats = &il->rx_stats;
-
-       if (ieee80211_is_mgmt(fc)) {
-               switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
-               case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
-                       stats->mgmt[MANAGEMENT_ASSOC_REQ]++;
-                       break;
-               case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP):
-                       stats->mgmt[MANAGEMENT_ASSOC_RESP]++;
-                       break;
-               case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
-                       stats->mgmt[MANAGEMENT_REASSOC_REQ]++;
-                       break;
-               case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP):
-                       stats->mgmt[MANAGEMENT_REASSOC_RESP]++;
-                       break;
-               case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ):
-                       stats->mgmt[MANAGEMENT_PROBE_REQ]++;
-                       break;
-               case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP):
-                       stats->mgmt[MANAGEMENT_PROBE_RESP]++;
-                       break;
-               case cpu_to_le16(IEEE80211_STYPE_BEACON):
-                       stats->mgmt[MANAGEMENT_BEACON]++;
-                       break;
-               case cpu_to_le16(IEEE80211_STYPE_ATIM):
-                       stats->mgmt[MANAGEMENT_ATIM]++;
-                       break;
-               case cpu_to_le16(IEEE80211_STYPE_DISASSOC):
-                       stats->mgmt[MANAGEMENT_DISASSOC]++;
-                       break;
-               case cpu_to_le16(IEEE80211_STYPE_AUTH):
-                       stats->mgmt[MANAGEMENT_AUTH]++;
-                       break;
-               case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
-                       stats->mgmt[MANAGEMENT_DEAUTH]++;
-                       break;
-               case cpu_to_le16(IEEE80211_STYPE_ACTION):
-                       stats->mgmt[MANAGEMENT_ACTION]++;
-                       break;
-               }
-       } else if (ieee80211_is_ctl(fc)) {
-               switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
-               case cpu_to_le16(IEEE80211_STYPE_BACK_REQ):
-                       stats->ctrl[CONTROL_BACK_REQ]++;
-                       break;
-               case cpu_to_le16(IEEE80211_STYPE_BACK):
-                       stats->ctrl[CONTROL_BACK]++;
-                       break;
-               case cpu_to_le16(IEEE80211_STYPE_PSPOLL):
-                       stats->ctrl[CONTROL_PSPOLL]++;
-                       break;
-               case cpu_to_le16(IEEE80211_STYPE_RTS):
-                       stats->ctrl[CONTROL_RTS]++;
-                       break;
-               case cpu_to_le16(IEEE80211_STYPE_CTS):
-                       stats->ctrl[CONTROL_CTS]++;
-                       break;
-               case cpu_to_le16(IEEE80211_STYPE_ACK):
-                       stats->ctrl[CONTROL_ACK]++;
-                       break;
-               case cpu_to_le16(IEEE80211_STYPE_CFEND):
-                       stats->ctrl[CONTROL_CFEND]++;
-                       break;
-               case cpu_to_le16(IEEE80211_STYPE_CFENDACK):
-                       stats->ctrl[CONTROL_CFENDACK]++;
-                       break;
-               }
-       } else {
-               /* data */
-               stats->data_cnt++;
-               stats->data_bytes += len;
-       }
-}
-EXPORT_SYMBOL(il_update_stats);
-#endif
+EXPORT_SYMBOL(il_free_txq_mem);
 
 int
 il_force_reset(struct il_priv *il, bool external)
@@ -4886,10 +4657,14 @@ il_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
        struct il_priv *il = hw->priv;
        int err;
 
-       if (newp2p)
-               return -EOPNOTSUPP;
-
        mutex_lock(&il->mutex);
+       D_MAC80211("enter: type %d, addr %pM newtype %d newp2p %d\n",
+                   vif->type, vif->addr, newtype, newp2p);
+
+       if (newp2p) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
 
        if (!il->vif || !il_is_ready_rf(il)) {
                /*
@@ -4916,7 +4691,9 @@ il_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
        err = 0;
 
 out:
+       D_MAC80211("leave err %d\n", err);
        mutex_unlock(&il->mutex);
+
        return err;
 }
 EXPORT_SYMBOL(il_mac_change_interface);
@@ -5113,9 +4890,9 @@ il_pci_resume(struct device *device)
                hw_rfkill = true;
 
        if (hw_rfkill)
-               set_bit(S_RF_KILL_HW, &il->status);
+               set_bit(S_RFKILL, &il->status);
        else
-               clear_bit(S_RF_KILL_HW, &il->status);
+               clear_bit(S_RFKILL, &il->status);
 
        wiphy_rfkill_set_hw_state(il->hw->wiphy, hw_rfkill);
 
@@ -5174,12 +4951,8 @@ il_mac_config(struct ieee80211_hw *hw, u32 changed)
        int scan_active = 0;
        bool ht_changed = false;
 
-       if (WARN_ON(!il->ops->legacy))
-               return -EOPNOTSUPP;
-
        mutex_lock(&il->mutex);
-
-       D_MAC80211("enter to channel %d changed 0x%X\n", channel->hw_value,
+       D_MAC80211("enter: channel %d changed 0x%X\n", channel->hw_value,
                   changed);
 
        if (unlikely(test_bit(S_SCANNING, &il->status))) {
@@ -5199,8 +4972,8 @@ il_mac_config(struct ieee80211_hw *hw, u32 changed)
                 * set up the SM PS mode to OFF if an HT channel is
                 * configured.
                 */
-               if (il->ops->hcmd->set_rxon_chain)
-                       il->ops->hcmd->set_rxon_chain(il);
+               if (il->ops->set_rxon_chain)
+                       il->ops->set_rxon_chain(il);
        }
 
        /* during scanning mac80211 will delay channel setting until
@@ -5269,8 +5042,8 @@ il_mac_config(struct ieee80211_hw *hw, u32 changed)
 
                spin_unlock_irqrestore(&il->lock, flags);
 
-               if (il->ops->legacy->update_bcast_stations)
-                       ret = il->ops->legacy->update_bcast_stations(il);
+               if (il->ops->update_bcast_stations)
+                       ret = il->ops->update_bcast_stations(il);
 
 set_ch_out:
                /* The list of supported rates and rate mask can be different
@@ -5308,8 +5081,9 @@ set_ch_out:
                il_update_qos(il);
 
 out:
-       D_MAC80211("leave\n");
+       D_MAC80211("leave ret %d\n", ret);
        mutex_unlock(&il->mutex);
+
        return ret;
 }
 EXPORT_SYMBOL(il_mac_config);
@@ -5320,24 +5094,17 @@ il_mac_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
        struct il_priv *il = hw->priv;
        unsigned long flags;
 
-       if (WARN_ON(!il->ops->legacy))
-               return;
-
        mutex_lock(&il->mutex);
-       D_MAC80211("enter\n");
+       D_MAC80211("enter: type %d, addr %pM\n", vif->type, vif->addr);
 
        spin_lock_irqsave(&il->lock, flags);
-       memset(&il->current_ht_config, 0, sizeof(struct il_ht_config));
-       spin_unlock_irqrestore(&il->lock, flags);
 
-       spin_lock_irqsave(&il->lock, flags);
+       memset(&il->current_ht_config, 0, sizeof(struct il_ht_config));
 
        /* new association get rid of ibss beacon skb */
        if (il->beacon_skb)
                dev_kfree_skb(il->beacon_skb);
-
        il->beacon_skb = NULL;
-
        il->timestamp = 0;
 
        spin_unlock_irqrestore(&il->lock, flags);
@@ -5349,17 +5116,14 @@ il_mac_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
                return;
        }
 
-       /* we are restarting association process
-        * clear RXON_FILTER_ASSOC_MSK bit
-        */
+       /* we are restarting association process */
        il->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
        il_commit_rxon(il);
 
        il_set_rate(il);
 
-       mutex_unlock(&il->mutex);
-
        D_MAC80211("leave\n");
+       mutex_unlock(&il->mutex);
 }
 EXPORT_SYMBOL(il_mac_reset_tsf);
 
@@ -5475,7 +5239,7 @@ il_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
                return;
        }
 
-       il->ops->legacy->post_associate(il);
+       il->ops->post_associate(il);
 }
 
 void
@@ -5485,14 +5249,11 @@ il_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
        struct il_priv *il = hw->priv;
        int ret;
 
-       if (WARN_ON(!il->ops->legacy))
-               return;
-
-       D_MAC80211("changes = 0x%X\n", changes);
-
        mutex_lock(&il->mutex);
+       D_MAC80211("enter: changes 0x%x\n", changes);
 
        if (!il_is_alive(il)) {
+               D_MAC80211("leave - not alive\n");
                mutex_unlock(&il->mutex);
                return;
        }
@@ -5523,8 +5284,7 @@ il_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                 * below/in post_associate will fail.
                 */
                if (il_scan_cancel_timeout(il, 100)) {
-                       IL_WARN("Aborted scan still in progress after 100ms\n");
-                       D_MAC80211("leaving - scan abort failed.\n");
+                       D_MAC80211("leave - scan abort failed\n");
                        mutex_unlock(&il->mutex);
                        return;
                }
@@ -5536,10 +5296,8 @@ il_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 
                        /* currently needed in a few places */
                        memcpy(il->bssid, bss_conf->bssid, ETH_ALEN);
-               } else {
+               } else
                        il->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-               }
-
        }
 
        /*
@@ -5590,8 +5348,8 @@ il_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
        if (changes & BSS_CHANGED_HT) {
                il_ht_conf(il, vif);
 
-               if (il->ops->hcmd->set_rxon_chain)
-                       il->ops->hcmd->set_rxon_chain(il);
+               if (il->ops->set_rxon_chain)
+                       il->ops->set_rxon_chain(il);
        }
 
        if (changes & BSS_CHANGED_ASSOC) {
@@ -5600,7 +5358,7 @@ il_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                        il->timestamp = bss_conf->timestamp;
 
                        if (!il_is_rfkill(il))
-                               il->ops->legacy->post_associate(il);
+                               il->ops->post_associate(il);
                } else
                        il_set_no_assoc(il, vif);
        }
@@ -5620,24 +5378,22 @@ il_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                        memcpy(il->staging.bssid_addr, bss_conf->bssid,
                               ETH_ALEN);
                        memcpy(il->bssid, bss_conf->bssid, ETH_ALEN);
-                       il->ops->legacy->config_ap(il);
+                       il->ops->config_ap(il);
                } else
                        il_set_no_assoc(il, vif);
        }
 
        if (changes & BSS_CHANGED_IBSS) {
-               ret =
-                   il->ops->legacy->manage_ibss_station(il, vif,
-                                                        bss_conf->ibss_joined);
+               ret = il->ops->manage_ibss_station(il, vif,
+                                                  bss_conf->ibss_joined);
                if (ret)
                        IL_ERR("failed to %s IBSS station %pM\n",
                               bss_conf->ibss_joined ? "add" : "remove",
                               bss_conf->bssid);
        }
 
-       mutex_unlock(&il->mutex);
-
        D_MAC80211("leave\n");
+       mutex_unlock(&il->mutex);
 }
 EXPORT_SYMBOL(il_mac_bss_info_changed);
 
index 708095644f17e24ed699205e4a09a3de4fe373f6..5f5017767b9990b54096b705c23310e866ff2d92 100644 (file)
@@ -425,12 +425,6 @@ struct il_eeprom_calib_info {
 
 #define EEPROM_REGULATORY_BAND_NO_HT40                 (0)
 
-struct il_eeprom_ops {
-       const u32 regulatory_bands[7];
-       int (*acquire_semaphore) (struct il_priv *il);
-       void (*release_semaphore) (struct il_priv *il);
-};
-
 int il_eeprom_init(struct il_priv *il);
 void il_eeprom_free(struct il_priv *il);
 const u8 *il_eeprom_query_addr(const struct il_priv *il, size_t offset);
@@ -962,26 +956,6 @@ enum il4965_chain_noise_state {
        IL_CHAIN_NOISE_DONE,
 };
 
-enum il4965_calib_enabled_state {
-       IL_CALIB_DISABLED = 0,  /* must be 0 */
-       IL_CALIB_ENABLED = 1,
-};
-
-/*
- * enum il_calib
- * defines the order in which results of initial calibrations
- * should be sent to the runtime uCode
- */
-enum il_calib {
-       IL_CALIB_MAX,
-};
-
-/* Opaque calibration results */
-struct il_calib_result {
-       void *buf;
-       size_t buf_len;
-};
-
 enum ucode_type {
        UCODE_NONE = 0,
        UCODE_INIT,
@@ -1156,13 +1130,15 @@ struct il_power_mgr {
 };
 
 struct il_priv {
-
-       /* ieee device used by generic ieee processing code */
        struct ieee80211_hw *hw;
        struct ieee80211_channel *ieee_channels;
        struct ieee80211_rate *ieee_rates;
+
        struct il_cfg *cfg;
        const struct il_ops *ops;
+#ifdef CONFIG_IWLEGACY_DEBUGFS
+       const struct il_debugfs_ops *debugfs_ops;
+#endif
 
        /* temporary frame storage list */
        struct list_head free_frames;
@@ -1199,9 +1175,6 @@ struct il_priv {
        s32 temperature;        /* degrees Kelvin */
        s32 last_temperature;
 
-       /* init calibration results */
-       struct il_calib_result calib_results[IL_CALIB_MAX];
-
        /* Scan related variables */
        unsigned long scan_start;
        unsigned long scan_start_tsf;
@@ -1557,24 +1530,6 @@ il_free_pages(struct il_priv *il, unsigned long page)
 #define IL_RX_BUF_SIZE_4K (4 * 1024)
 #define IL_RX_BUF_SIZE_8K (8 * 1024)
 
-struct il_hcmd_ops {
-       int (*rxon_assoc) (struct il_priv *il);
-       int (*commit_rxon) (struct il_priv *il);
-       void (*set_rxon_chain) (struct il_priv *il);
-};
-
-struct il_hcmd_utils_ops {
-       u16(*get_hcmd_size) (u8 cmd_id, u16 len);
-       u16(*build_addsta_hcmd) (const struct il_addsta_cmd *cmd, u8 *data);
-       int (*request_scan) (struct il_priv *il, struct ieee80211_vif *vif);
-       void (*post_scan) (struct il_priv *il);
-};
-
-struct il_apm_ops {
-       int (*init) (struct il_priv *il);
-       void (*config) (struct il_priv *il);
-};
-
 #ifdef CONFIG_IWLEGACY_DEBUGFS
 struct il_debugfs_ops {
        ssize_t(*rx_stats_read) (struct file *file, char __user *user_buf,
@@ -1587,11 +1542,7 @@ struct il_debugfs_ops {
 };
 #endif
 
-struct il_temp_ops {
-       void (*temperature) (struct il_priv *il);
-};
-
-struct il_lib_ops {
+struct il_ops {
        /* Handling TX */
        void (*txq_update_byte_cnt_tbl) (struct il_priv *il,
                                         struct il_tx_queue *txq,
@@ -1601,8 +1552,6 @@ struct il_lib_ops {
                                      u16 len, u8 reset, u8 pad);
        void (*txq_free_tfd) (struct il_priv *il, struct il_tx_queue *txq);
        int (*txq_init) (struct il_priv *il, struct il_tx_queue *txq);
-       /* setup Rx handler */
-       void (*handler_setup) (struct il_priv *il);
        /* alive notification after init uCode load */
        void (*init_alive_start) (struct il_priv *il);
        /* check validity of rtc data address */
@@ -1615,44 +1564,33 @@ struct il_lib_ops {
        int (*set_channel_switch) (struct il_priv *il,
                                   struct ieee80211_channel_switch *ch_switch);
        /* power management */
-       struct il_apm_ops apm_ops;
+       int (*apm_init) (struct il_priv *il);
 
-       /* power */
+       /* tx power */
        int (*send_tx_power) (struct il_priv *il);
        void (*update_chain_flags) (struct il_priv *il);
 
        /* eeprom operations */
-       struct il_eeprom_ops eeprom_ops;
-
-       /* temperature */
-       struct il_temp_ops temp_ops;
-
-#ifdef CONFIG_IWLEGACY_DEBUGFS
-       struct il_debugfs_ops debugfs_ops;
-#endif
+       int (*eeprom_acquire_semaphore) (struct il_priv *il);
+       void (*eeprom_release_semaphore) (struct il_priv *il);
 
-};
+       int (*rxon_assoc) (struct il_priv *il);
+       int (*commit_rxon) (struct il_priv *il);
+       void (*set_rxon_chain) (struct il_priv *il);
 
-struct il_led_ops {
-       int (*cmd) (struct il_priv *il, struct il_led_cmd *led_cmd);
-};
+       u16(*get_hcmd_size) (u8 cmd_id, u16 len);
+       u16(*build_addsta_hcmd) (const struct il_addsta_cmd *cmd, u8 *data);
 
-struct il_legacy_ops {
+       int (*request_scan) (struct il_priv *il, struct ieee80211_vif *vif);
+       void (*post_scan) (struct il_priv *il);
        void (*post_associate) (struct il_priv *il);
        void (*config_ap) (struct il_priv *il);
        /* station management */
        int (*update_bcast_stations) (struct il_priv *il);
        int (*manage_ibss_station) (struct il_priv *il,
                                    struct ieee80211_vif *vif, bool add);
-};
 
-struct il_ops {
-       const struct il_lib_ops *lib;
-       const struct il_hcmd_ops *hcmd;
-       const struct il_hcmd_utils_ops *utils;
-       const struct il_led_ops *led;
-       const struct il_nic_ops *nic;
-       const struct il_legacy_ops *legacy;
+       int (*send_led_cmd) (struct il_priv *il, struct il_led_cmd *led_cmd);
 };
 
 struct il_mod_params {
@@ -1665,22 +1603,6 @@ struct il_mod_params {
        int restart_fw;         /* def: 1 = restart firmware */
 };
 
-/*
- * @led_compensation: compensate on the led on/off time per HW according
- *     to the deviation to achieve the desired led frequency.
- *     The detail algorithm is described in common.c
- * @chain_noise_num_beacons: number of beacons used to compute chain noise
- * @wd_timeout: TX queues watchdog timeout
- * @temperature_kelvin: temperature report by uCode in kelvin
- * @ucode_tracing: support ucode continuous tracing
- * @sensitivity_calib_by_driver: driver has the capability to perform
- *     sensitivity calibration operation
- * @chain_noise_calib_by_driver: driver has the capability to perform
- *     chain noise calibration operation
- */
-struct il_base_params {
-};
-
 #define IL_LED_SOLID 11
 #define IL_DEF_LED_INTRVL cpu_to_le32(1000)
 
@@ -1769,6 +1691,8 @@ struct il_cfg {
        const bool ucode_tracing;
        const bool sensitivity_calib_by_driver;
        const bool chain_noise_calib_by_driver;
+
+       const u32 regulatory_bands[7];
 };
 
 /***************************
@@ -1800,60 +1724,24 @@ void il_mac_remove_interface(struct ieee80211_hw *hw,
 int il_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                            enum nl80211_iftype newtype, bool newp2p);
 int il_alloc_txq_mem(struct il_priv *il);
-void il_txq_mem(struct il_priv *il);
+void il_free_txq_mem(struct il_priv *il);
 
 #ifdef CONFIG_IWLEGACY_DEBUGFS
-int il_alloc_traffic_mem(struct il_priv *il);
-void il_free_traffic_mem(struct il_priv *il);
-void il_reset_traffic_log(struct il_priv *il);
-void il_dbg_log_tx_data_frame(struct il_priv *il, u16 length,
-                             struct ieee80211_hdr *header);
-void il_dbg_log_rx_data_frame(struct il_priv *il, u16 length,
-                             struct ieee80211_hdr *header);
-const char *il_get_mgmt_string(int cmd);
-const char *il_get_ctrl_string(int cmd);
-void il_clear_traffic_stats(struct il_priv *il);
-void il_update_stats(struct il_priv *il, bool is_tx, __le16 fc, u16 len);
+extern void il_update_stats(struct il_priv *il, bool is_tx, __le16 fc, u16 len);
 #else
-static inline int
-il_alloc_traffic_mem(struct il_priv *il)
-{
-       return 0;
-}
-
-static inline void
-il_free_traffic_mem(struct il_priv *il)
-{
-}
-
-static inline void
-il_reset_traffic_log(struct il_priv *il)
-{
-}
-
-static inline void
-il_dbg_log_tx_data_frame(struct il_priv *il, u16 length,
-                        struct ieee80211_hdr *header)
-{
-}
-
-static inline void
-il_dbg_log_rx_data_frame(struct il_priv *il, u16 length,
-                        struct ieee80211_hdr *header)
-{
-}
-
 static inline void
 il_update_stats(struct il_priv *il, bool is_tx, __le16 fc, u16 len)
 {
 }
 #endif
+
 /*****************************************************
- * RX handlers.
- * **************************************************/
+ * Handlers
+ ***************************************************/
 void il_hdl_pm_sleep(struct il_priv *il, struct il_rx_buf *rxb);
 void il_hdl_pm_debug_stats(struct il_priv *il, struct il_rx_buf *rxb);
 void il_hdl_error(struct il_priv *il, struct il_rx_buf *rxb);
+void il_hdl_csa(struct il_priv *il, struct il_rx_buf *rxb);
 
 /*****************************************************
 * RX
@@ -1864,25 +1752,20 @@ int il_rx_queue_alloc(struct il_priv *il);
 void il_rx_queue_update_write_ptr(struct il_priv *il, struct il_rx_queue *q);
 int il_rx_queue_space(const struct il_rx_queue *q);
 void il_tx_cmd_complete(struct il_priv *il, struct il_rx_buf *rxb);
-/* Handlers */
+
 void il_hdl_spectrum_measurement(struct il_priv *il, struct il_rx_buf *rxb);
 void il_recover_from_stats(struct il_priv *il, struct il_rx_pkt *pkt);
 void il_chswitch_done(struct il_priv *il, bool is_success);
-void il_hdl_csa(struct il_priv *il, struct il_rx_buf *rxb);
-
-/* TX helpers */
 
 /*****************************************************
 * TX
 ******************************************************/
-void il_txq_update_write_ptr(struct il_priv *il, struct il_tx_queue *txq);
-int il_tx_queue_init(struct il_priv *il, struct il_tx_queue *txq, int slots_num,
-                    u32 txq_id);
-void il_tx_queue_reset(struct il_priv *il, struct il_tx_queue *txq,
-                      int slots_num, u32 txq_id);
-void il_tx_queue_unmap(struct il_priv *il, int txq_id);
-void il_tx_queue_free(struct il_priv *il, int txq_id);
-void il_setup_watchdog(struct il_priv *il);
+extern void il_txq_update_write_ptr(struct il_priv *il, struct il_tx_queue *txq);
+extern int il_tx_queue_init(struct il_priv *il, u32 txq_id);
+extern void il_tx_queue_reset(struct il_priv *il, u32 txq_id);
+extern void il_tx_queue_unmap(struct il_priv *il, int txq_id);
+extern void il_tx_queue_free(struct il_priv *il, int txq_id);
+extern void il_setup_watchdog(struct il_priv *il);
 /*****************************************************
  * TX power
  ****************************************************/
@@ -2000,7 +1883,7 @@ void il_free_geos(struct il_priv *il);
 #define S_HCMD_ACTIVE  0       /* host command in progress */
 /* 1 is unused (used to be S_HCMD_SYNC_ACTIVE) */
 #define S_INT_ENABLED  2
-#define S_RF_KILL_HW   3
+#define S_RFKILL       3
 #define S_CT_KILL              4
 #define S_INIT         5
 #define S_ALIVE                6
@@ -2038,16 +1921,10 @@ il_is_init(struct il_priv *il)
        return test_bit(S_INIT, &il->status);
 }
 
-static inline int
-il_is_rfkill_hw(struct il_priv *il)
-{
-       return test_bit(S_RF_KILL_HW, &il->status);
-}
-
 static inline int
 il_is_rfkill(struct il_priv *il)
 {
-       return il_is_rfkill_hw(il);
+       return test_bit(S_RFKILL, &il->status);
 }
 
 static inline int
@@ -2068,7 +1945,9 @@ il_is_ready_rf(struct il_priv *il)
 
 extern void il_send_bt_config(struct il_priv *il);
 extern int il_send_stats_request(struct il_priv *il, u8 flags, bool clear);
-void il_apm_stop(struct il_priv *il);
+extern void il_apm_stop(struct il_priv *il);
+extern void _il_apm_stop(struct il_priv *il);
+
 int il_apm_init(struct il_priv *il);
 
 int il_send_rxon_timing(struct il_priv *il);
@@ -2076,13 +1955,13 @@ int il_send_rxon_timing(struct il_priv *il);
 static inline int
 il_send_rxon_assoc(struct il_priv *il)
 {
-       return il->ops->hcmd->rxon_assoc(il);
+       return il->ops->rxon_assoc(il);
 }
 
 static inline int
 il_commit_rxon(struct il_priv *il)
 {
-       return il->ops->hcmd->commit_rxon(il);
+       return il->ops->commit_rxon(il);
 }
 
 static inline const struct ieee80211_supported_band *
@@ -2103,7 +1982,7 @@ irqreturn_t il_isr(int irq, void *data);
 
 extern void il_set_bit(struct il_priv *p, u32 r, u32 m);
 extern void il_clear_bit(struct il_priv *p, u32 r, u32 m);
-extern int _il_grab_nic_access(struct il_priv *il);
+extern bool _il_grab_nic_access(struct il_priv *il);
 extern int _il_poll_bit(struct il_priv *il, u32 addr, u32 bits, u32 mask, int timeout);
 extern int il_poll_bit(struct il_priv *il, u32 addr, u32 mask, int timeout);
 extern u32 il_rd_prph(struct il_priv *il, u32 reg);
@@ -2114,20 +1993,20 @@ extern void il_write_targ_mem(struct il_priv *il, u32 addr, u32 val);
 static inline void
 _il_write8(struct il_priv *il, u32 ofs, u8 val)
 {
-       iowrite8(val, il->hw_base + ofs);
+       writeb(val, il->hw_base + ofs);
 }
 #define il_write8(il, ofs, val) _il_write8(il, ofs, val)
 
 static inline void
 _il_wr(struct il_priv *il, u32 ofs, u32 val)
 {
-       iowrite32(val, il->hw_base + ofs);
+       writel(val, il->hw_base + ofs);
 }
 
 static inline u32
 _il_rd(struct il_priv *il, u32 ofs)
 {
-       return ioread32(il->hw_base + ofs);
+       return readl(il->hw_base + ofs);
 }
 
 static inline void
@@ -2146,6 +2025,13 @@ static inline void
 _il_release_nic_access(struct il_priv *il)
 {
        _il_clear_bit(il, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+       /*
+        * In above we are reading CSR_GP_CNTRL register, what will flush any
+        * previous writes, but still want write, which clear MAC_ACCESS_REQ
+        * bit, be performed on PCI bus before any other writes scheduled on
+        * different CPUs (after we drop reg_lock).
+        */
+       mmiowb();
 }
 
 static inline u32
@@ -2168,7 +2054,7 @@ il_wr(struct il_priv *il, u32 reg, u32 value)
        unsigned long reg_flags;
 
        spin_lock_irqsave(&il->reg_lock, reg_flags);
-       if (!_il_grab_nic_access(il)) {
+       if (likely(_il_grab_nic_access(il))) {
                _il_wr(il, reg, value);
                _il_release_nic_access(il);
        }
@@ -2179,7 +2065,6 @@ static inline u32
 _il_rd_prph(struct il_priv *il, u32 reg)
 {
        _il_wr(il, HBUS_TARG_PRPH_RADDR, reg | (3 << 24));
-       rmb();
        return _il_rd(il, HBUS_TARG_PRPH_RDAT);
 }
 
@@ -2187,7 +2072,6 @@ static inline void
 _il_wr_prph(struct il_priv *il, u32 addr, u32 val)
 {
        _il_wr(il, HBUS_TARG_PRPH_WADDR, ((addr & 0x0000FFFF) | (3 << 24)));
-       wmb();
        _il_wr(il, HBUS_TARG_PRPH_WDAT, val);
 }
 
@@ -2197,9 +2081,10 @@ il_set_bits_prph(struct il_priv *il, u32 reg, u32 mask)
        unsigned long reg_flags;
 
        spin_lock_irqsave(&il->reg_lock, reg_flags);
-       _il_grab_nic_access(il);
-       _il_wr_prph(il, reg, (_il_rd_prph(il, reg) | mask));
-       _il_release_nic_access(il);
+       if (likely(_il_grab_nic_access(il))) {
+               _il_wr_prph(il, reg, (_il_rd_prph(il, reg) | mask));
+               _il_release_nic_access(il);
+       }
        spin_unlock_irqrestore(&il->reg_lock, reg_flags);
 }
 
@@ -2209,9 +2094,10 @@ il_set_bits_mask_prph(struct il_priv *il, u32 reg, u32 bits, u32 mask)
        unsigned long reg_flags;
 
        spin_lock_irqsave(&il->reg_lock, reg_flags);
-       _il_grab_nic_access(il);
-       _il_wr_prph(il, reg, ((_il_rd_prph(il, reg) & mask) | bits));
-       _il_release_nic_access(il);
+       if (likely(_il_grab_nic_access(il))) {
+               _il_wr_prph(il, reg, ((_il_rd_prph(il, reg) & mask) | bits));
+               _il_release_nic_access(il);
+       }
        spin_unlock_irqrestore(&il->reg_lock, reg_flags);
 }
 
@@ -2222,10 +2108,11 @@ il_clear_bits_prph(struct il_priv *il, u32 reg, u32 mask)
        u32 val;
 
        spin_lock_irqsave(&il->reg_lock, reg_flags);
-       _il_grab_nic_access(il);
-       val = _il_rd_prph(il, reg);
-       _il_wr_prph(il, reg, (val & ~mask));
-       _il_release_nic_access(il);
+       if (likely(_il_grab_nic_access(il))) {
+               val = _il_rd_prph(il, reg);
+               _il_wr_prph(il, reg, (val & ~mask));
+               _il_release_nic_access(il);
+       }
        spin_unlock_irqrestore(&il->reg_lock, reg_flags);
 }
 
@@ -2487,10 +2374,10 @@ struct il_rb_status {
        __le32 __unused;        /* 3945 only */
 } __packed;
 
-#define TFD_QUEUE_SIZE_MAX      (256)
-#define TFD_QUEUE_SIZE_BC_DUP  (64)
+#define TFD_QUEUE_SIZE_MAX      256
+#define TFD_QUEUE_SIZE_BC_DUP  64
 #define TFD_QUEUE_BC_SIZE      (TFD_QUEUE_SIZE_MAX + TFD_QUEUE_SIZE_BC_DUP)
-#define IL_TX_DMA_MASK        DMA_BIT_MASK(36)
+#define IL_TX_DMA_MASK         DMA_BIT_MASK(36)
 #define IL_NUM_OF_TBS          20
 
 static inline u8
index bb7c95607a69636f5499d04bfdcfd2ea2341a806..229849150aac0bb20e152b6a79b0658ebf3b18bb 100644 (file)
 
 #include "common.h"
 
+void
+il_clear_traffic_stats(struct il_priv *il)
+{
+       memset(&il->tx_stats, 0, sizeof(struct traffic_stats));
+       memset(&il->rx_stats, 0, sizeof(struct traffic_stats));
+}
+
+/*
+ * il_update_stats function record all the MGMT, CTRL and DATA pkt for
+ * both TX and Rx . Use debugfs to display the rx/rx_stats
+ */
+void
+il_update_stats(struct il_priv *il, bool is_tx, __le16 fc, u16 len)
+{
+       struct traffic_stats *stats;
+
+       if (is_tx)
+               stats = &il->tx_stats;
+       else
+               stats = &il->rx_stats;
+
+       if (ieee80211_is_mgmt(fc)) {
+               switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
+               case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
+                       stats->mgmt[MANAGEMENT_ASSOC_REQ]++;
+                       break;
+               case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP):
+                       stats->mgmt[MANAGEMENT_ASSOC_RESP]++;
+                       break;
+               case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
+                       stats->mgmt[MANAGEMENT_REASSOC_REQ]++;
+                       break;
+               case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP):
+                       stats->mgmt[MANAGEMENT_REASSOC_RESP]++;
+                       break;
+               case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ):
+                       stats->mgmt[MANAGEMENT_PROBE_REQ]++;
+                       break;
+               case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP):
+                       stats->mgmt[MANAGEMENT_PROBE_RESP]++;
+                       break;
+               case cpu_to_le16(IEEE80211_STYPE_BEACON):
+                       stats->mgmt[MANAGEMENT_BEACON]++;
+                       break;
+               case cpu_to_le16(IEEE80211_STYPE_ATIM):
+                       stats->mgmt[MANAGEMENT_ATIM]++;
+                       break;
+               case cpu_to_le16(IEEE80211_STYPE_DISASSOC):
+                       stats->mgmt[MANAGEMENT_DISASSOC]++;
+                       break;
+               case cpu_to_le16(IEEE80211_STYPE_AUTH):
+                       stats->mgmt[MANAGEMENT_AUTH]++;
+                       break;
+               case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
+                       stats->mgmt[MANAGEMENT_DEAUTH]++;
+                       break;
+               case cpu_to_le16(IEEE80211_STYPE_ACTION):
+                       stats->mgmt[MANAGEMENT_ACTION]++;
+                       break;
+               }
+       } else if (ieee80211_is_ctl(fc)) {
+               switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
+               case cpu_to_le16(IEEE80211_STYPE_BACK_REQ):
+                       stats->ctrl[CONTROL_BACK_REQ]++;
+                       break;
+               case cpu_to_le16(IEEE80211_STYPE_BACK):
+                       stats->ctrl[CONTROL_BACK]++;
+                       break;
+               case cpu_to_le16(IEEE80211_STYPE_PSPOLL):
+                       stats->ctrl[CONTROL_PSPOLL]++;
+                       break;
+               case cpu_to_le16(IEEE80211_STYPE_RTS):
+                       stats->ctrl[CONTROL_RTS]++;
+                       break;
+               case cpu_to_le16(IEEE80211_STYPE_CTS):
+                       stats->ctrl[CONTROL_CTS]++;
+                       break;
+               case cpu_to_le16(IEEE80211_STYPE_ACK):
+                       stats->ctrl[CONTROL_ACK]++;
+                       break;
+               case cpu_to_le16(IEEE80211_STYPE_CFEND):
+                       stats->ctrl[CONTROL_CFEND]++;
+                       break;
+               case cpu_to_le16(IEEE80211_STYPE_CFENDACK):
+                       stats->ctrl[CONTROL_CFENDACK]++;
+                       break;
+               }
+       } else {
+               /* data */
+               stats->data_cnt++;
+               stats->data_bytes += len;
+       }
+}
+EXPORT_SYMBOL(il_update_stats);
+
 /* create and remove of files */
 #define DEBUGFS_ADD_FILE(name, parent, mode) do {                      \
        if (!debugfs_create_file(#name, mode, parent, il,               \
@@ -98,6 +193,46 @@ static const struct file_operations il_dbgfs_##name##_ops = {       \
        .llseek = generic_file_llseek,                          \
 };
 
+static const char *
+il_get_mgmt_string(int cmd)
+{
+       switch (cmd) {
+       IL_CMD(MANAGEMENT_ASSOC_REQ);
+       IL_CMD(MANAGEMENT_ASSOC_RESP);
+       IL_CMD(MANAGEMENT_REASSOC_REQ);
+       IL_CMD(MANAGEMENT_REASSOC_RESP);
+       IL_CMD(MANAGEMENT_PROBE_REQ);
+       IL_CMD(MANAGEMENT_PROBE_RESP);
+       IL_CMD(MANAGEMENT_BEACON);
+       IL_CMD(MANAGEMENT_ATIM);
+       IL_CMD(MANAGEMENT_DISASSOC);
+       IL_CMD(MANAGEMENT_AUTH);
+       IL_CMD(MANAGEMENT_DEAUTH);
+       IL_CMD(MANAGEMENT_ACTION);
+       default:
+               return "UNKNOWN";
+
+       }
+}
+
+static const char *
+il_get_ctrl_string(int cmd)
+{
+       switch (cmd) {
+       IL_CMD(CONTROL_BACK_REQ);
+       IL_CMD(CONTROL_BACK);
+       IL_CMD(CONTROL_PSPOLL);
+       IL_CMD(CONTROL_RTS);
+       IL_CMD(CONTROL_CTS);
+       IL_CMD(CONTROL_ACK);
+       IL_CMD(CONTROL_CFEND);
+       IL_CMD(CONTROL_CFENDACK);
+       default:
+               return "UNKNOWN";
+
+       }
+}
+
 static ssize_t
 il_dbgfs_tx_stats_read(struct file *file, char __user *user_buf, size_t count,
                       loff_t *ppos)
@@ -495,8 +630,8 @@ il_dbgfs_status_read(struct file *file, char __user *user_buf, size_t count,
            scnprintf(buf + pos, bufsz - pos, "S_INT_ENABLED:\t %d\n",
                      test_bit(S_INT_ENABLED, &il->status));
        pos +=
-           scnprintf(buf + pos, bufsz - pos, "S_RF_KILL_HW:\t %d\n",
-                     test_bit(S_RF_KILL_HW, &il->status));
+           scnprintf(buf + pos, bufsz - pos, "S_RFKILL:\t %d\n",
+                     test_bit(S_RFKILL, &il->status));
        pos +=
            scnprintf(buf + pos, bufsz - pos, "S_CT_KILL:\t\t %d\n",
                      test_bit(S_CT_KILL, &il->status));
@@ -714,112 +849,6 @@ DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
 DEBUGFS_READ_FILE_OPS(qos);
 DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40);
 
-static ssize_t
-il_dbgfs_traffic_log_read(struct file *file, char __user *user_buf,
-                         size_t count, loff_t *ppos)
-{
-       struct il_priv *il = file->private_data;
-       int pos = 0, ofs = 0;
-       int cnt = 0, entry;
-       struct il_tx_queue *txq;
-       struct il_queue *q;
-       struct il_rx_queue *rxq = &il->rxq;
-       char *buf;
-       int bufsz =
-           ((IL_TRAFFIC_ENTRIES * IL_TRAFFIC_ENTRY_SIZE * 64) * 2) +
-           (il->cfg->num_of_queues * 32 * 8) + 400;
-       const u8 *ptr;
-       ssize_t ret;
-
-       if (!il->txq) {
-               IL_ERR("txq not ready\n");
-               return -EAGAIN;
-       }
-       buf = kzalloc(bufsz, GFP_KERNEL);
-       if (!buf) {
-               IL_ERR("Can not allocate buffer\n");
-               return -ENOMEM;
-       }
-       pos += scnprintf(buf + pos, bufsz - pos, "Tx Queue\n");
-       for (cnt = 0; cnt < il->hw_params.max_txq_num; cnt++) {
-               txq = &il->txq[cnt];
-               q = &txq->q;
-               pos +=
-                   scnprintf(buf + pos, bufsz - pos,
-                             "q[%d]: read_ptr: %u, write_ptr: %u\n", cnt,
-                             q->read_ptr, q->write_ptr);
-       }
-       if (il->tx_traffic && (il_debug_level & IL_DL_TX)) {
-               ptr = il->tx_traffic;
-               pos +=
-                   scnprintf(buf + pos, bufsz - pos, "Tx Traffic idx: %u\n",
-                             il->tx_traffic_idx);
-               for (cnt = 0, ofs = 0; cnt < IL_TRAFFIC_ENTRIES; cnt++) {
-                       for (entry = 0; entry < IL_TRAFFIC_ENTRY_SIZE / 16;
-                            entry++, ofs += 16) {
-                               pos +=
-                                   scnprintf(buf + pos, bufsz - pos, "0x%.4x ",
-                                             ofs);
-                               hex_dump_to_buffer(ptr + ofs, 16, 16, 2,
-                                                  buf + pos, bufsz - pos, 0);
-                               pos += strlen(buf + pos);
-                               if (bufsz - pos > 0)
-                                       buf[pos++] = '\n';
-                       }
-               }
-       }
-
-       pos += scnprintf(buf + pos, bufsz - pos, "Rx Queue\n");
-       pos +=
-           scnprintf(buf + pos, bufsz - pos, "read: %u, write: %u\n",
-                     rxq->read, rxq->write);
-
-       if (il->rx_traffic && (il_debug_level & IL_DL_RX)) {
-               ptr = il->rx_traffic;
-               pos +=
-                   scnprintf(buf + pos, bufsz - pos, "Rx Traffic idx: %u\n",
-                             il->rx_traffic_idx);
-               for (cnt = 0, ofs = 0; cnt < IL_TRAFFIC_ENTRIES; cnt++) {
-                       for (entry = 0; entry < IL_TRAFFIC_ENTRY_SIZE / 16;
-                            entry++, ofs += 16) {
-                               pos +=
-                                   scnprintf(buf + pos, bufsz - pos, "0x%.4x ",
-                                             ofs);
-                               hex_dump_to_buffer(ptr + ofs, 16, 16, 2,
-                                                  buf + pos, bufsz - pos, 0);
-                               pos += strlen(buf + pos);
-                               if (bufsz - pos > 0)
-                                       buf[pos++] = '\n';
-                       }
-               }
-       }
-
-       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-       kfree(buf);
-       return ret;
-}
-
-static ssize_t
-il_dbgfs_traffic_log_write(struct file *file, const char __user *user_buf,
-                          size_t count, loff_t *ppos)
-{
-       struct il_priv *il = file->private_data;
-       char buf[8];
-       int buf_size;
-       int traffic_log;
-
-       memset(buf, 0, sizeof(buf));
-       buf_size = min(count, sizeof(buf) - 1);
-       if (copy_from_user(buf, user_buf, buf_size))
-               return -EFAULT;
-       if (sscanf(buf, "%d", &traffic_log) != 1)
-               return -EFAULT;
-       if (traffic_log == 0)
-               il_reset_traffic_log(il);
-
-       return count;
-}
-
 static ssize_t
 il_dbgfs_tx_queue_read(struct file *file, char __user *user_buf, size_t count,
                       loff_t *ppos)
@@ -901,7 +930,8 @@ il_dbgfs_ucode_rx_stats_read(struct file *file, char __user *user_buf,
                             size_t count, loff_t *ppos)
 {
        struct il_priv *il = file->private_data;
-       return il->ops->lib->debugfs_ops.rx_stats_read(file, user_buf, count, ppos);
+
+       return il->debugfs_ops->rx_stats_read(file, user_buf, count, ppos);
 }
 
 static ssize_t
@@ -909,7 +939,8 @@ il_dbgfs_ucode_tx_stats_read(struct file *file, char __user *user_buf,
                             size_t count, loff_t *ppos)
 {
        struct il_priv *il = file->private_data;
-       return il->ops->lib->debugfs_ops.tx_stats_read(file, user_buf, count, ppos);
+
+       return il->debugfs_ops->tx_stats_read(file, user_buf, count, ppos);
 }
 
 static ssize_t
@@ -917,7 +948,8 @@ il_dbgfs_ucode_general_stats_read(struct file *file, char __user *user_buf,
                                  size_t count, loff_t *ppos)
 {
        struct il_priv *il = file->private_data;
-       return il->ops->lib->debugfs_ops.general_stats_read(file, user_buf, count, ppos);
+
+       return il->debugfs_ops->general_stats_read(file, user_buf, count, ppos);
 }
 
 static ssize_t
@@ -1175,8 +1207,8 @@ il_dbgfs_fh_reg_read(struct file *file, char __user *user_buf, size_t count,
        int pos = 0;
        ssize_t ret = -EFAULT;
 
-       if (il->ops->lib->dump_fh) {
-               ret = pos = il->ops->lib->dump_fh(il, &buf, true);
+       if (il->ops->dump_fh) {
+               ret = pos = il->ops->dump_fh(il, &buf, true);
                if (buf) {
                        ret =
                            simple_read_from_buffer(user_buf, count, ppos, buf,
@@ -1300,7 +1332,6 @@ il_dbgfs_wd_timeout_write(struct file *file, const char __user *user_buf,
 
 DEBUGFS_READ_FILE_OPS(rx_stats);
 DEBUGFS_READ_FILE_OPS(tx_stats);
-DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
 DEBUGFS_READ_FILE_OPS(rx_queue);
 DEBUGFS_READ_FILE_OPS(tx_queue);
 DEBUGFS_READ_FILE_OPS(ucode_rx_stats);
@@ -1354,7 +1385,6 @@ il_dbgfs_register(struct il_priv *il, const char *name)
        DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR);
        DEBUGFS_ADD_FILE(rx_stats, dir_debug, S_IRUSR);
        DEBUGFS_ADD_FILE(tx_stats, dir_debug, S_IRUSR);
-       DEBUGFS_ADD_FILE(traffic_log, dir_debug, S_IWUSR | S_IRUSR);
        DEBUGFS_ADD_FILE(rx_queue, dir_debug, S_IRUSR);
        DEBUGFS_ADD_FILE(tx_queue, dir_debug, S_IRUSR);
        DEBUGFS_ADD_FILE(power_save_status, dir_debug, S_IRUSR);
index ae08498dfcad98a91311e128ab9569f0f7c9534b..2fe62730dddd158b66ac80dceb8b20f9150fa99d 100644 (file)
@@ -1,6 +1,6 @@
 config IWLWIFI
        tristate "Intel Wireless WiFi Next Gen AGN - Wireless-N/Advanced-N/Ultimate-N (iwlwifi) "
-       depends on PCI && MAC80211
+       depends on PCI && MAC80211 && HAS_IOMEM
        select FW_LOADER
        select NEW_LEDS
        select LEDS_CLASS
@@ -127,3 +127,12 @@ config IWLWIFI_P2P
          support when it is loaded.
 
          Say Y only if you want to experiment with P2P.
+
+config IWLWIFI_EXPERIMENTAL_MFP
+       bool "support MFP (802.11w) even if uCode doesn't advertise"
+       depends on IWLWIFI
+       help
+         This option enables experimental MFP (802.11W) support
+         even if the microcode doesn't advertise it.
+
+         Say Y only if you want to experiment with MFP.
index 9dc84a7354dbbde1cdec1560dc91d019039c5feb..85d163ed3db18dd224477231fc0d1728b157f261 100644 (file)
@@ -1,7 +1,7 @@
 # WIFI
 obj-$(CONFIG_IWLWIFI)  += iwlwifi.o
 iwlwifi-objs           := iwl-agn.o iwl-agn-rs.o iwl-mac80211.o
-iwlwifi-objs           += iwl-ucode.o iwl-agn-tx.o
+iwlwifi-objs           += iwl-ucode.o iwl-agn-tx.o iwl-debug.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
 
@@ -13,7 +13,8 @@ iwlwifi-objs          += iwl-6000.o
 iwlwifi-objs           += iwl-1000.o
 iwlwifi-objs           += iwl-2000.o
 iwlwifi-objs           += iwl-pci.o
-iwlwifi-objs           += iwl-trans.o
+iwlwifi-objs           += iwl-drv.o
+iwlwifi-objs           += iwl-notif-wait.o
 iwlwifi-objs           += iwl-trans-pcie.o iwl-trans-pcie-rx.o iwl-trans-pcie-tx.o
 
 iwlwifi-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
index 8c1466c907ff2b7cdf2a7af1ecb1029683248a1f..5b0d888f746bbc27ea492d6351458476aabdbd4d 100644 (file)
@@ -43,6 +43,7 @@
 #include "iwl-agn-hw.h"
 #include "iwl-shared.h"
 #include "iwl-cfg.h"
+#include "iwl-prph.h"
 
 /* Highest firmware API version supported */
 #define IWL1000_UCODE_API_MAX 6
@@ -95,9 +96,8 @@ static void iwl1000_nic_config(struct iwl_priv *priv)
                                ~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK);
 }
 
-static struct iwl_sensitivity_ranges iwl1000_sensitivity = {
+static const struct iwl_sensitivity_ranges iwl1000_sensitivity = {
        .min_nrg_cck = 95,
-       .max_nrg_cck = 0, /* not used, set to 0 */
        .auto_corr_min_ofdm = 90,
        .auto_corr_min_ofdm_mrc = 170,
        .auto_corr_min_ofdm_x1 = 120,
@@ -120,34 +120,22 @@ static struct iwl_sensitivity_ranges iwl1000_sensitivity = {
        .nrg_th_cca = 62,
 };
 
-static int iwl1000_hw_set_hw_params(struct iwl_priv *priv)
+static void iwl1000_hw_set_hw_params(struct iwl_priv *priv)
 {
-       if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES &&
-           iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES)
-               cfg(priv)->base_params->num_of_queues =
-                       iwlagn_mod_params.num_of_queues;
-
-       hw_params(priv).max_txq_num = cfg(priv)->base_params->num_of_queues;
-       hw_params(priv).max_data_size = IWLAGN_RTC_DATA_SIZE;
-       hw_params(priv).max_inst_size = IWLAGN_RTC_INST_SIZE;
-
        hw_params(priv).ht40_channel =  BIT(IEEE80211_BAND_2GHZ);
 
-       hw_params(priv).tx_chains_num = num_of_ant(cfg(priv)->valid_tx_ant);
+       hw_params(priv).tx_chains_num =
+               num_of_ant(hw_params(priv).valid_tx_ant);
        if (cfg(priv)->rx_with_siso_diversity)
                hw_params(priv).rx_chains_num = 1;
        else
                hw_params(priv).rx_chains_num =
-                       num_of_ant(cfg(priv)->valid_rx_ant);
-       hw_params(priv).valid_tx_ant = cfg(priv)->valid_tx_ant;
-       hw_params(priv).valid_rx_ant = cfg(priv)->valid_rx_ant;
+                       num_of_ant(hw_params(priv).valid_rx_ant);
 
        iwl1000_set_ct_threshold(priv);
 
        /* Set initial sensitivity parameters */
        hw_params(priv).sens = &iwl1000_sensitivity;
-
-       return 0;
 }
 
 static struct iwl_lib_ops iwl1000_lib = {
@@ -167,7 +155,7 @@ static struct iwl_lib_ops iwl1000_lib = {
        .temperature = iwlagn_temperature,
 };
 
-static struct iwl_base_params iwl1000_base_params = {
+static const struct iwl_base_params iwl1000_base_params = {
        .num_of_queues = IWLAGN_NUM_QUEUES,
        .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
        .eeprom_size = OTP_LOW_IMAGE_SIZE,
@@ -182,7 +170,8 @@ static struct iwl_base_params iwl1000_base_params = {
        .max_event_log_size = 128,
        .wd_disable = true,
 };
-static struct iwl_ht_params iwl1000_ht_params = {
+
+static const struct iwl_ht_params iwl1000_ht_params = {
        .ht_greenfield_support = true,
        .use_rts_for_aggregation = true, /* use rts/cts protection */
        .smps_mode = IEEE80211_SMPS_DYNAMIC,
@@ -193,19 +182,21 @@ static struct iwl_ht_params iwl1000_ht_params = {
        .ucode_api_max = IWL1000_UCODE_API_MAX,                 \
        .ucode_api_ok = IWL1000_UCODE_API_OK,                   \
        .ucode_api_min = IWL1000_UCODE_API_MIN,                 \
+       .max_inst_size = IWLAGN_RTC_INST_SIZE,                  \
+       .max_data_size = IWLAGN_RTC_DATA_SIZE,                  \
        .eeprom_ver = EEPROM_1000_EEPROM_VERSION,               \
        .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,       \
        .lib = &iwl1000_lib,                                    \
        .base_params = &iwl1000_base_params,                    \
        .led_mode = IWL_LED_BLINK
 
-struct iwl_cfg iwl1000_bgn_cfg = {
+const struct iwl_cfg iwl1000_bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 1000 BGN",
        IWL_DEVICE_1000,
        .ht_params = &iwl1000_ht_params,
 };
 
-struct iwl_cfg iwl1000_bg_cfg = {
+const struct iwl_cfg iwl1000_bg_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 1000 BG",
        IWL_DEVICE_1000,
 };
@@ -215,6 +206,8 @@ struct iwl_cfg iwl1000_bg_cfg = {
        .ucode_api_max = IWL100_UCODE_API_MAX,                  \
        .ucode_api_ok = IWL100_UCODE_API_OK,                    \
        .ucode_api_min = IWL100_UCODE_API_MIN,                  \
+       .max_inst_size = IWLAGN_RTC_INST_SIZE,                  \
+       .max_data_size = IWLAGN_RTC_DATA_SIZE,                  \
        .eeprom_ver = EEPROM_1000_EEPROM_VERSION,               \
        .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,       \
        .lib = &iwl1000_lib,                                    \
@@ -222,13 +215,13 @@ struct iwl_cfg iwl1000_bg_cfg = {
        .led_mode = IWL_LED_RF_STATE,                           \
        .rx_with_siso_diversity = true
 
-struct iwl_cfg iwl100_bgn_cfg = {
+const struct iwl_cfg iwl100_bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 100 BGN",
        IWL_DEVICE_100,
        .ht_params = &iwl1000_ht_params,
 };
 
-struct iwl_cfg iwl100_bg_cfg = {
+const struct iwl_cfg iwl100_bg_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 100 BG",
        IWL_DEVICE_100,
 };
index d4f5f3b8757885109ca6299be342a19aea0fd871..5635b9e2c69e6b4e27e9337d88f97095ac71029d 100644 (file)
@@ -91,9 +91,8 @@ static void iwl2000_nic_config(struct iwl_priv *priv)
                            CSR_GP_DRIVER_REG_BIT_RADIO_IQ_INVER);
 }
 
-static struct iwl_sensitivity_ranges iwl2000_sensitivity = {
+static const struct iwl_sensitivity_ranges iwl2000_sensitivity = {
        .min_nrg_cck = 97,
-       .max_nrg_cck = 0, /* not used, set to 0 */
        .auto_corr_min_ofdm = 80,
        .auto_corr_min_ofdm_mrc = 128,
        .auto_corr_min_ofdm_x1 = 105,
@@ -116,34 +115,22 @@ static struct iwl_sensitivity_ranges iwl2000_sensitivity = {
        .nrg_th_cca = 62,
 };
 
-static int iwl2000_hw_set_hw_params(struct iwl_priv *priv)
+static void iwl2000_hw_set_hw_params(struct iwl_priv *priv)
 {
-       if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES &&
-           iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES)
-               cfg(priv)->base_params->num_of_queues =
-                       iwlagn_mod_params.num_of_queues;
-
-       hw_params(priv).max_txq_num = cfg(priv)->base_params->num_of_queues;
-       hw_params(priv).max_data_size = IWL60_RTC_DATA_SIZE;
-       hw_params(priv).max_inst_size = IWL60_RTC_INST_SIZE;
-
        hw_params(priv).ht40_channel =  BIT(IEEE80211_BAND_2GHZ);
 
-       hw_params(priv).tx_chains_num = num_of_ant(cfg(priv)->valid_tx_ant);
+       hw_params(priv).tx_chains_num =
+               num_of_ant(hw_params(priv).valid_tx_ant);
        if (cfg(priv)->rx_with_siso_diversity)
                hw_params(priv).rx_chains_num = 1;
        else
                hw_params(priv).rx_chains_num =
-                       num_of_ant(cfg(priv)->valid_rx_ant);
-       hw_params(priv).valid_tx_ant = cfg(priv)->valid_tx_ant;
-       hw_params(priv).valid_rx_ant = cfg(priv)->valid_rx_ant;
+                       num_of_ant(hw_params(priv).valid_rx_ant);
 
        iwl2000_set_ct_threshold(priv);
 
        /* Set initial sensitivity parameters */
        hw_params(priv).sens = &iwl2000_sensitivity;
-
-       return 0;
 }
 
 static struct iwl_lib_ops iwl2000_lib = {
@@ -159,16 +146,13 @@ static struct iwl_lib_ops iwl2000_lib = {
                        EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
                        EEPROM_REGULATORY_BAND_NO_HT40,
                },
-               .update_enhanced_txpower = iwl_eeprom_enhanced_txpower,
+               .enhanced_txpower = true,
        },
        .temperature = iwlagn_temperature,
 };
 
 static struct iwl_lib_ops iwl2030_lib = {
        .set_hw_params = iwl2000_hw_set_hw_params,
-       .bt_rx_handler_setup = iwlagn_bt_rx_handler_setup,
-       .bt_setup_deferred_work = iwlagn_bt_setup_deferred_work,
-       .cancel_deferred_work = iwlagn_bt_cancel_deferred_work,
        .nic_config = iwl2000_nic_config,
        .eeprom_ops = {
                .regulatory_bands = {
@@ -180,12 +164,12 @@ static struct iwl_lib_ops iwl2030_lib = {
                        EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
                        EEPROM_REGULATORY_BAND_NO_HT40,
                },
-               .update_enhanced_txpower = iwl_eeprom_enhanced_txpower,
+               .enhanced_txpower = true,
        },
        .temperature = iwlagn_temperature,
 };
 
-static struct iwl_base_params iwl2000_base_params = {
+static const struct iwl_base_params iwl2000_base_params = {
        .eeprom_size = OTP_LOW_IMAGE_SIZE,
        .num_of_queues = IWLAGN_NUM_QUEUES,
        .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
@@ -204,7 +188,7 @@ static struct iwl_base_params iwl2000_base_params = {
 };
 
 
-static struct iwl_base_params iwl2030_base_params = {
+static const struct iwl_base_params iwl2030_base_params = {
        .eeprom_size = OTP_LOW_IMAGE_SIZE,
        .num_of_queues = IWLAGN_NUM_QUEUES,
        .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
@@ -222,12 +206,12 @@ static struct iwl_base_params iwl2030_base_params = {
        .hd_v2 = true,
 };
 
-static struct iwl_ht_params iwl2000_ht_params = {
+static const struct iwl_ht_params iwl2000_ht_params = {
        .ht_greenfield_support = true,
        .use_rts_for_aggregation = true, /* use rts/cts protection */
 };
 
-static struct iwl_bt_params iwl2030_bt_params = {
+static const struct iwl_bt_params iwl2030_bt_params = {
        /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
        .advanced_bt_coexist = true,
        .agg_time_limit = BT_AGG_THRESHOLD_DEF,
@@ -242,6 +226,8 @@ static struct iwl_bt_params iwl2030_bt_params = {
        .ucode_api_max = IWL2000_UCODE_API_MAX,                 \
        .ucode_api_ok = IWL2000_UCODE_API_OK,                   \
        .ucode_api_min = IWL2000_UCODE_API_MIN,                 \
+       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
+       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
        .eeprom_ver = EEPROM_2000_EEPROM_VERSION,               \
        .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION,       \
        .lib = &iwl2000_lib,                                    \
@@ -251,13 +237,13 @@ static struct iwl_bt_params iwl2030_bt_params = {
        .led_mode = IWL_LED_RF_STATE,                           \
        .iq_invert = true                                       \
 
-struct iwl_cfg iwl2000_2bgn_cfg = {
+const struct iwl_cfg iwl2000_2bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 2200 BGN",
        IWL_DEVICE_2000,
        .ht_params = &iwl2000_ht_params,
 };
 
-struct iwl_cfg iwl2000_2bgn_d_cfg = {
+const struct iwl_cfg iwl2000_2bgn_d_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 2200D BGN",
        IWL_DEVICE_2000,
        .ht_params = &iwl2000_ht_params,
@@ -268,6 +254,8 @@ struct iwl_cfg iwl2000_2bgn_d_cfg = {
        .ucode_api_max = IWL2030_UCODE_API_MAX,                 \
        .ucode_api_ok = IWL2030_UCODE_API_OK,                   \
        .ucode_api_min = IWL2030_UCODE_API_MIN,                 \
+       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
+       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
        .eeprom_ver = EEPROM_2000_EEPROM_VERSION,               \
        .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION,       \
        .lib = &iwl2030_lib,                                    \
@@ -279,7 +267,7 @@ struct iwl_cfg iwl2000_2bgn_d_cfg = {
        .adv_pm = true,                                         \
        .iq_invert = true                                       \
 
-struct iwl_cfg iwl2030_2bgn_cfg = {
+const struct iwl_cfg iwl2030_2bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 2230 BGN",
        IWL_DEVICE_2030,
        .ht_params = &iwl2000_ht_params,
@@ -290,6 +278,8 @@ struct iwl_cfg iwl2030_2bgn_cfg = {
        .ucode_api_max = IWL105_UCODE_API_MAX,                  \
        .ucode_api_ok = IWL105_UCODE_API_OK,                    \
        .ucode_api_min = IWL105_UCODE_API_MIN,                  \
+       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
+       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
        .eeprom_ver = EEPROM_2000_EEPROM_VERSION,               \
        .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION,       \
        .lib = &iwl2000_lib,                                    \
@@ -301,13 +291,13 @@ struct iwl_cfg iwl2030_2bgn_cfg = {
        .rx_with_siso_diversity = true,                         \
        .iq_invert = true                                       \
 
-struct iwl_cfg iwl105_bgn_cfg = {
+const struct iwl_cfg iwl105_bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 105 BGN",
        IWL_DEVICE_105,
        .ht_params = &iwl2000_ht_params,
 };
 
-struct iwl_cfg iwl105_bgn_d_cfg = {
+const struct iwl_cfg iwl105_bgn_d_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 105D BGN",
        IWL_DEVICE_105,
        .ht_params = &iwl2000_ht_params,
@@ -318,6 +308,8 @@ struct iwl_cfg iwl105_bgn_d_cfg = {
        .ucode_api_max = IWL135_UCODE_API_MAX,                  \
        .ucode_api_ok = IWL135_UCODE_API_OK,                    \
        .ucode_api_min = IWL135_UCODE_API_MIN,                  \
+       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
+       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
        .eeprom_ver = EEPROM_2000_EEPROM_VERSION,               \
        .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION,       \
        .lib = &iwl2030_lib,                                    \
@@ -330,7 +322,7 @@ struct iwl_cfg iwl105_bgn_d_cfg = {
        .rx_with_siso_diversity = true,                         \
        .iq_invert = true                                       \
 
-struct iwl_cfg iwl135_bgn_cfg = {
+const struct iwl_cfg iwl135_bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 135 BGN",
        IWL_DEVICE_135,
        .ht_params = &iwl2000_ht_params,
index dc9317d0343e05659ae64af720b0011c9afea664..a805e97b89af85cb1a066c156cc1899dde7034c7 100644 (file)
@@ -45,6 +45,7 @@
 #include "iwl-trans.h"
 #include "iwl-shared.h"
 #include "iwl-cfg.h"
+#include "iwl-prph.h"
 
 /* Highest firmware API version supported */
 #define IWL5000_UCODE_API_MAX 5
 /* NIC configuration for 5000 series */
 static void iwl5000_nic_config(struct iwl_priv *priv)
 {
-       unsigned long flags;
-
        iwl_rf_config(priv);
 
-       spin_lock_irqsave(&priv->shrd->lock, flags);
-
        /* W/A : NIC is stuck in a reset state after Early PCIe power off
         * (PCIe power is lost before PERST# is asserted),
         * causing ME FW to lose ownership and not being able to obtain it back.
@@ -76,14 +73,10 @@ static void iwl5000_nic_config(struct iwl_priv *priv)
        iwl_set_bits_mask_prph(trans(priv), APMG_PS_CTRL_REG,
                                APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS,
                                ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS);
-
-
-       spin_unlock_irqrestore(&priv->shrd->lock, flags);
 }
 
-static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
+static const struct iwl_sensitivity_ranges iwl5000_sensitivity = {
        .min_nrg_cck = 100,
-       .max_nrg_cck = 0, /* not used, set to 0 */
        .auto_corr_min_ofdm = 90,
        .auto_corr_min_ofdm_mrc = 170,
        .auto_corr_min_ofdm_x1 = 105,
@@ -108,7 +101,6 @@ static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
 
 static struct iwl_sensitivity_ranges iwl5150_sensitivity = {
        .min_nrg_cck = 95,
-       .max_nrg_cck = 0, /* not used, set to 0 */
        .auto_corr_min_ofdm = 90,
        .auto_corr_min_ofdm_mrc = 170,
        .auto_corr_min_ofdm_x1 = 105,
@@ -162,58 +154,36 @@ static void iwl5000_set_ct_threshold(struct iwl_priv *priv)
        hw_params(priv).ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY;
 }
 
-static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
+static void iwl5000_hw_set_hw_params(struct iwl_priv *priv)
 {
-       if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES &&
-           iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES)
-               cfg(priv)->base_params->num_of_queues =
-                       iwlagn_mod_params.num_of_queues;
-
-       hw_params(priv).max_txq_num = cfg(priv)->base_params->num_of_queues;
-       hw_params(priv).max_data_size = IWLAGN_RTC_DATA_SIZE;
-       hw_params(priv).max_inst_size = IWLAGN_RTC_INST_SIZE;
-
        hw_params(priv).ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
                                        BIT(IEEE80211_BAND_5GHZ);
 
-       hw_params(priv).tx_chains_num = num_of_ant(cfg(priv)->valid_tx_ant);
-       hw_params(priv).rx_chains_num = num_of_ant(cfg(priv)->valid_rx_ant);
-       hw_params(priv).valid_tx_ant = cfg(priv)->valid_tx_ant;
-       hw_params(priv).valid_rx_ant = cfg(priv)->valid_rx_ant;
+       hw_params(priv).tx_chains_num =
+               num_of_ant(hw_params(priv).valid_tx_ant);
+       hw_params(priv).rx_chains_num =
+               num_of_ant(hw_params(priv).valid_rx_ant);
 
        iwl5000_set_ct_threshold(priv);
 
        /* Set initial sensitivity parameters */
        hw_params(priv).sens = &iwl5000_sensitivity;
-
-       return 0;
 }
 
-static int iwl5150_hw_set_hw_params(struct iwl_priv *priv)
+static void iwl5150_hw_set_hw_params(struct iwl_priv *priv)
 {
-       if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES &&
-           iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES)
-               cfg(priv)->base_params->num_of_queues =
-                       iwlagn_mod_params.num_of_queues;
-
-       hw_params(priv).max_txq_num = cfg(priv)->base_params->num_of_queues;
-       hw_params(priv).max_data_size = IWLAGN_RTC_DATA_SIZE;
-       hw_params(priv).max_inst_size = IWLAGN_RTC_INST_SIZE;
-
        hw_params(priv).ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
                                        BIT(IEEE80211_BAND_5GHZ);
 
-       hw_params(priv).tx_chains_num = num_of_ant(cfg(priv)->valid_tx_ant);
-       hw_params(priv).rx_chains_num = num_of_ant(cfg(priv)->valid_rx_ant);
-       hw_params(priv).valid_tx_ant = cfg(priv)->valid_tx_ant;
-       hw_params(priv).valid_rx_ant = cfg(priv)->valid_rx_ant;
+       hw_params(priv).tx_chains_num =
+               num_of_ant(hw_params(priv).valid_tx_ant);
+       hw_params(priv).rx_chains_num =
+               num_of_ant(hw_params(priv).valid_rx_ant);
 
        iwl5150_set_ct_threshold(priv);
 
        /* Set initial sensitivity parameters */
        hw_params(priv).sens = &iwl5150_sensitivity;
-
-       return 0;
 }
 
 static void iwl5150_temperature(struct iwl_priv *priv)
@@ -296,7 +266,7 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
                return -EFAULT;
        }
 
-       return iwl_trans_send_cmd(trans(priv), &hcmd);
+       return iwl_dvm_send_cmd(priv, &hcmd);
 }
 
 static struct iwl_lib_ops iwl5000_lib = {
@@ -335,7 +305,7 @@ static struct iwl_lib_ops iwl5150_lib = {
        .temperature = iwl5150_temperature,
 };
 
-static struct iwl_base_params iwl5000_base_params = {
+static const struct iwl_base_params iwl5000_base_params = {
        .eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
        .num_of_queues = IWLAGN_NUM_QUEUES,
        .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
@@ -348,7 +318,8 @@ static struct iwl_base_params iwl5000_base_params = {
        .no_idle_support = true,
        .wd_disable = true,
 };
-static struct iwl_ht_params iwl5000_ht_params = {
+
+static const struct iwl_ht_params iwl5000_ht_params = {
        .ht_greenfield_support = true,
 };
 
@@ -356,13 +327,15 @@ static struct iwl_ht_params iwl5000_ht_params = {
        .fw_name_pre = IWL5000_FW_PRE,                          \
        .ucode_api_max = IWL5000_UCODE_API_MAX,                 \
        .ucode_api_min = IWL5000_UCODE_API_MIN,                 \
+       .max_inst_size = IWLAGN_RTC_INST_SIZE,                  \
+       .max_data_size = IWLAGN_RTC_DATA_SIZE,                  \
        .eeprom_ver = EEPROM_5000_EEPROM_VERSION,               \
        .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,       \
        .lib = &iwl5000_lib,                                    \
        .base_params = &iwl5000_base_params,                    \
        .led_mode = IWL_LED_BLINK
 
-struct iwl_cfg iwl5300_agn_cfg = {
+const struct iwl_cfg iwl5300_agn_cfg = {
        .name = "Intel(R) Ultimate N WiFi Link 5300 AGN",
        IWL_DEVICE_5000,
        /* at least EEPROM 0x11A has wrong info */
@@ -371,7 +344,7 @@ struct iwl_cfg iwl5300_agn_cfg = {
        .ht_params = &iwl5000_ht_params,
 };
 
-struct iwl_cfg iwl5100_bgn_cfg = {
+const struct iwl_cfg iwl5100_bgn_cfg = {
        .name = "Intel(R) WiFi Link 5100 BGN",
        IWL_DEVICE_5000,
        .valid_tx_ant = ANT_B,          /* .cfg overwrite */
@@ -379,14 +352,14 @@ struct iwl_cfg iwl5100_bgn_cfg = {
        .ht_params = &iwl5000_ht_params,
 };
 
-struct iwl_cfg iwl5100_abg_cfg = {
+const struct iwl_cfg iwl5100_abg_cfg = {
        .name = "Intel(R) WiFi Link 5100 ABG",
        IWL_DEVICE_5000,
        .valid_tx_ant = ANT_B,          /* .cfg overwrite */
        .valid_rx_ant = ANT_AB,         /* .cfg overwrite */
 };
 
-struct iwl_cfg iwl5100_agn_cfg = {
+const struct iwl_cfg iwl5100_agn_cfg = {
        .name = "Intel(R) WiFi Link 5100 AGN",
        IWL_DEVICE_5000,
        .valid_tx_ant = ANT_B,          /* .cfg overwrite */
@@ -394,11 +367,13 @@ struct iwl_cfg iwl5100_agn_cfg = {
        .ht_params = &iwl5000_ht_params,
 };
 
-struct iwl_cfg iwl5350_agn_cfg = {
+const struct iwl_cfg iwl5350_agn_cfg = {
        .name = "Intel(R) WiMAX/WiFi Link 5350 AGN",
        .fw_name_pre = IWL5000_FW_PRE,
        .ucode_api_max = IWL5000_UCODE_API_MAX,
        .ucode_api_min = IWL5000_UCODE_API_MIN,
+       .max_inst_size = IWLAGN_RTC_INST_SIZE,
+       .max_data_size = IWLAGN_RTC_DATA_SIZE,
        .eeprom_ver = EEPROM_5050_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
        .lib = &iwl5000_lib,
@@ -412,6 +387,8 @@ struct iwl_cfg iwl5350_agn_cfg = {
        .fw_name_pre = IWL5150_FW_PRE,                          \
        .ucode_api_max = IWL5150_UCODE_API_MAX,                 \
        .ucode_api_min = IWL5150_UCODE_API_MIN,                 \
+       .max_inst_size = IWLAGN_RTC_INST_SIZE,                  \
+       .max_data_size = IWLAGN_RTC_DATA_SIZE,                  \
        .eeprom_ver = EEPROM_5050_EEPROM_VERSION,               \
        .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,       \
        .lib = &iwl5150_lib,                                    \
@@ -420,14 +397,14 @@ struct iwl_cfg iwl5350_agn_cfg = {
        .led_mode = IWL_LED_BLINK,                              \
        .internal_wimax_coex = true
 
-struct iwl_cfg iwl5150_agn_cfg = {
+const struct iwl_cfg iwl5150_agn_cfg = {
        .name = "Intel(R) WiMAX/WiFi Link 5150 AGN",
        IWL_DEVICE_5150,
        .ht_params = &iwl5000_ht_params,
 
 };
 
-struct iwl_cfg iwl5150_abg_cfg = {
+const struct iwl_cfg iwl5150_abg_cfg = {
        .name = "Intel(R) WiMAX/WiFi Link 5150 ABG",
        IWL_DEVICE_5150,
 };
index c36fb858a45bfe7ead8dc7722c17facaba6f24ac..64060cd738b5d90b069a8289eba923842365a023 100644 (file)
@@ -96,25 +96,25 @@ static void iwl6150_additional_nic_config(struct iwl_priv *priv)
                    CSR_GP_DRIVER_REG_BIT_6050_1x2);
 }
 
+static void iwl6000i_additional_nic_config(struct iwl_priv *priv)
+{
+       /* 2x2 IPA phy type */
+       iwl_write32(trans(priv), CSR_GP_DRIVER_REG,
+                    CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA);
+}
+
 /* NIC configuration for 6000 series */
 static void iwl6000_nic_config(struct iwl_priv *priv)
 {
        iwl_rf_config(priv);
 
-       /* no locking required for register write */
-       if (cfg(priv)->pa_type == IWL_PA_INTERNAL) {
-               /* 2x2 IPA phy type */
-               iwl_write32(trans(priv), CSR_GP_DRIVER_REG,
-                            CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA);
-       }
        /* do additional nic configuration if needed */
        if (cfg(priv)->additional_nic_config)
-                       cfg(priv)->additional_nic_config(priv);
+               cfg(priv)->additional_nic_config(priv);
 }
 
-static struct iwl_sensitivity_ranges iwl6000_sensitivity = {
+static const struct iwl_sensitivity_ranges iwl6000_sensitivity = {
        .min_nrg_cck = 110,
-       .max_nrg_cck = 0, /* not used, set to 0 */
        .auto_corr_min_ofdm = 80,
        .auto_corr_min_ofdm_mrc = 128,
        .auto_corr_min_ofdm_x1 = 105,
@@ -137,35 +137,24 @@ static struct iwl_sensitivity_ranges iwl6000_sensitivity = {
        .nrg_th_cca = 62,
 };
 
-static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
+static void iwl6000_hw_set_hw_params(struct iwl_priv *priv)
 {
-       if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES &&
-           iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES)
-               cfg(priv)->base_params->num_of_queues =
-                       iwlagn_mod_params.num_of_queues;
-
-       hw_params(priv).max_txq_num = cfg(priv)->base_params->num_of_queues;
-       hw_params(priv).max_data_size = IWL60_RTC_DATA_SIZE;
-       hw_params(priv).max_inst_size = IWL60_RTC_INST_SIZE;
-
        hw_params(priv).ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
                                        BIT(IEEE80211_BAND_5GHZ);
 
-       hw_params(priv).tx_chains_num = num_of_ant(cfg(priv)->valid_tx_ant);
+       hw_params(priv).tx_chains_num =
+               num_of_ant(hw_params(priv).valid_tx_ant);
        if (cfg(priv)->rx_with_siso_diversity)
                hw_params(priv).rx_chains_num = 1;
        else
                hw_params(priv).rx_chains_num =
-                       num_of_ant(cfg(priv)->valid_rx_ant);
-       hw_params(priv).valid_tx_ant = cfg(priv)->valid_tx_ant;
-       hw_params(priv).valid_rx_ant = cfg(priv)->valid_rx_ant;
+                       num_of_ant(hw_params(priv).valid_rx_ant);
 
        iwl6000_set_ct_threshold(priv);
 
        /* Set initial sensitivity parameters */
        hw_params(priv).sens = &iwl6000_sensitivity;
 
-       return 0;
 }
 
 static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
@@ -236,7 +225,7 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
                return -EFAULT;
        }
 
-       return iwl_trans_send_cmd(trans(priv), &hcmd);
+       return iwl_dvm_send_cmd(priv, &hcmd);
 }
 
 static struct iwl_lib_ops iwl6000_lib = {
@@ -253,16 +242,13 @@ static struct iwl_lib_ops iwl6000_lib = {
                        EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
                        EEPROM_REG_BAND_52_HT40_CHANNELS
                },
-               .update_enhanced_txpower = iwl_eeprom_enhanced_txpower,
+               .enhanced_txpower = true,
        },
        .temperature = iwlagn_temperature,
 };
 
 static struct iwl_lib_ops iwl6030_lib = {
        .set_hw_params = iwl6000_hw_set_hw_params,
-       .bt_rx_handler_setup = iwlagn_bt_rx_handler_setup,
-       .bt_setup_deferred_work = iwlagn_bt_setup_deferred_work,
-       .cancel_deferred_work = iwlagn_bt_cancel_deferred_work,
        .set_channel_switch = iwl6000_hw_channel_switch,
        .nic_config = iwl6000_nic_config,
        .eeprom_ops = {
@@ -275,12 +261,12 @@ static struct iwl_lib_ops iwl6030_lib = {
                        EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
                        EEPROM_REG_BAND_52_HT40_CHANNELS
                },
-               .update_enhanced_txpower = iwl_eeprom_enhanced_txpower,
+               .enhanced_txpower = true,
        },
        .temperature = iwlagn_temperature,
 };
 
-static struct iwl_base_params iwl6000_base_params = {
+static const struct iwl_base_params iwl6000_base_params = {
        .eeprom_size = OTP_LOW_IMAGE_SIZE,
        .num_of_queues = IWLAGN_NUM_QUEUES,
        .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
@@ -297,7 +283,7 @@ static struct iwl_base_params iwl6000_base_params = {
        .shadow_reg_enable = true,
 };
 
-static struct iwl_base_params iwl6050_base_params = {
+static const struct iwl_base_params iwl6050_base_params = {
        .eeprom_size = OTP_LOW_IMAGE_SIZE,
        .num_of_queues = IWLAGN_NUM_QUEUES,
        .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
@@ -313,7 +299,8 @@ static struct iwl_base_params iwl6050_base_params = {
        .max_event_log_size = 1024,
        .shadow_reg_enable = true,
 };
-static struct iwl_base_params iwl6000_g2_base_params = {
+
+static const struct iwl_base_params iwl6000_g2_base_params = {
        .eeprom_size = OTP_LOW_IMAGE_SIZE,
        .num_of_queues = IWLAGN_NUM_QUEUES,
        .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
@@ -330,12 +317,12 @@ static struct iwl_base_params iwl6000_g2_base_params = {
        .shadow_reg_enable = true,
 };
 
-static struct iwl_ht_params iwl6000_ht_params = {
+static const struct iwl_ht_params iwl6000_ht_params = {
        .ht_greenfield_support = true,
        .use_rts_for_aggregation = true, /* use rts/cts protection */
 };
 
-static struct iwl_bt_params iwl6000_bt_params = {
+static const struct iwl_bt_params iwl6000_bt_params = {
        /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
        .advanced_bt_coexist = true,
        .agg_time_limit = BT_AGG_THRESHOLD_DEF,
@@ -349,6 +336,8 @@ static struct iwl_bt_params iwl6000_bt_params = {
        .ucode_api_max = IWL6000G2_UCODE_API_MAX,               \
        .ucode_api_ok = IWL6000G2_UCODE_API_OK,                 \
        .ucode_api_min = IWL6000G2_UCODE_API_MIN,               \
+       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
+       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
        .eeprom_ver = EEPROM_6005_EEPROM_VERSION,               \
        .eeprom_calib_ver = EEPROM_6005_TX_POWER_VERSION,       \
        .lib = &iwl6000_lib,                                    \
@@ -356,39 +345,53 @@ static struct iwl_bt_params iwl6000_bt_params = {
        .need_temp_offset_calib = true,                         \
        .led_mode = IWL_LED_RF_STATE
 
-struct iwl_cfg iwl6005_2agn_cfg = {
+const struct iwl_cfg iwl6005_2agn_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N 6205 AGN",
        IWL_DEVICE_6005,
        .ht_params = &iwl6000_ht_params,
 };
 
-struct iwl_cfg iwl6005_2abg_cfg = {
+const struct iwl_cfg iwl6005_2abg_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N 6205 ABG",
        IWL_DEVICE_6005,
 };
 
-struct iwl_cfg iwl6005_2bg_cfg = {
+const struct iwl_cfg iwl6005_2bg_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N 6205 BG",
        IWL_DEVICE_6005,
 };
 
-struct iwl_cfg iwl6005_2agn_sff_cfg = {
+const struct iwl_cfg iwl6005_2agn_sff_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N 6205S AGN",
        IWL_DEVICE_6005,
        .ht_params = &iwl6000_ht_params,
 };
 
-struct iwl_cfg iwl6005_2agn_d_cfg = {
+const struct iwl_cfg iwl6005_2agn_d_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N 6205D AGN",
        IWL_DEVICE_6005,
        .ht_params = &iwl6000_ht_params,
 };
 
+const struct iwl_cfg iwl6005_2agn_mow1_cfg = {
+       .name = "Intel(R) Centrino(R) Advanced-N 6206 AGN",
+       IWL_DEVICE_6005,
+       .ht_params = &iwl6000_ht_params,
+};
+
+const struct iwl_cfg iwl6005_2agn_mow2_cfg = {
+       .name = "Intel(R) Centrino(R) Advanced-N 6207 AGN",
+       IWL_DEVICE_6005,
+       .ht_params = &iwl6000_ht_params,
+};
+
 #define IWL_DEVICE_6030                                                \
        .fw_name_pre = IWL6030_FW_PRE,                          \
        .ucode_api_max = IWL6000G2_UCODE_API_MAX,               \
        .ucode_api_ok = IWL6000G2_UCODE_API_OK,                 \
        .ucode_api_min = IWL6000G2_UCODE_API_MIN,               \
+       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
+       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
        .eeprom_ver = EEPROM_6030_EEPROM_VERSION,               \
        .eeprom_calib_ver = EEPROM_6030_TX_POWER_VERSION,       \
        .lib = &iwl6030_lib,                                    \
@@ -398,53 +401,53 @@ struct iwl_cfg iwl6005_2agn_d_cfg = {
        .led_mode = IWL_LED_RF_STATE,                           \
        .adv_pm = true                                          \
 
-struct iwl_cfg iwl6030_2agn_cfg = {
+const struct iwl_cfg iwl6030_2agn_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N 6230 AGN",
        IWL_DEVICE_6030,
        .ht_params = &iwl6000_ht_params,
 };
 
-struct iwl_cfg iwl6030_2abg_cfg = {
+const struct iwl_cfg iwl6030_2abg_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N 6230 ABG",
        IWL_DEVICE_6030,
 };
 
-struct iwl_cfg iwl6030_2bgn_cfg = {
+const struct iwl_cfg iwl6030_2bgn_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N 6230 BGN",
        IWL_DEVICE_6030,
        .ht_params = &iwl6000_ht_params,
 };
 
-struct iwl_cfg iwl6030_2bg_cfg = {
+const struct iwl_cfg iwl6030_2bg_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N 6230 BG",
        IWL_DEVICE_6030,
 };
 
-struct iwl_cfg iwl6035_2agn_cfg = {
+const struct iwl_cfg iwl6035_2agn_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N 6235 AGN",
        IWL_DEVICE_6030,
        .ht_params = &iwl6000_ht_params,
 };
 
-struct iwl_cfg iwl1030_bgn_cfg = {
+const struct iwl_cfg iwl1030_bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 1030 BGN",
        IWL_DEVICE_6030,
        .ht_params = &iwl6000_ht_params,
 };
 
-struct iwl_cfg iwl1030_bg_cfg = {
+const struct iwl_cfg iwl1030_bg_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 1030 BG",
        IWL_DEVICE_6030,
 };
 
-struct iwl_cfg iwl130_bgn_cfg = {
+const struct iwl_cfg iwl130_bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 130 BGN",
        IWL_DEVICE_6030,
        .ht_params = &iwl6000_ht_params,
        .rx_with_siso_diversity = true,
 };
 
-struct iwl_cfg iwl130_bg_cfg = {
+const struct iwl_cfg iwl130_bg_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 130 BG",
        IWL_DEVICE_6030,
        .rx_with_siso_diversity = true,
@@ -458,27 +461,29 @@ struct iwl_cfg iwl130_bg_cfg = {
        .ucode_api_max = IWL6000_UCODE_API_MAX,                 \
        .ucode_api_ok = IWL6000_UCODE_API_OK,                   \
        .ucode_api_min = IWL6000_UCODE_API_MIN,                 \
+       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
+       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
        .valid_tx_ant = ANT_BC,         /* .cfg overwrite */    \
        .valid_rx_ant = ANT_BC,         /* .cfg overwrite */    \
        .eeprom_ver = EEPROM_6000_EEPROM_VERSION,               \
        .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,       \
        .lib = &iwl6000_lib,                                    \
+       .additional_nic_config = iwl6000i_additional_nic_config,\
        .base_params = &iwl6000_base_params,                    \
-       .pa_type = IWL_PA_INTERNAL,                             \
        .led_mode = IWL_LED_BLINK
 
-struct iwl_cfg iwl6000i_2agn_cfg = {
+const struct iwl_cfg iwl6000i_2agn_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N 6200 AGN",
        IWL_DEVICE_6000i,
        .ht_params = &iwl6000_ht_params,
 };
 
-struct iwl_cfg iwl6000i_2abg_cfg = {
+const struct iwl_cfg iwl6000i_2abg_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N 6200 ABG",
        IWL_DEVICE_6000i,
 };
 
-struct iwl_cfg iwl6000i_2bg_cfg = {
+const struct iwl_cfg iwl6000i_2bg_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N 6200 BG",
        IWL_DEVICE_6000i,
 };
@@ -487,6 +492,8 @@ struct iwl_cfg iwl6000i_2bg_cfg = {
        .fw_name_pre = IWL6050_FW_PRE,                          \
        .ucode_api_max = IWL6050_UCODE_API_MAX,                 \
        .ucode_api_min = IWL6050_UCODE_API_MIN,                 \
+       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
+       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
        .valid_tx_ant = ANT_AB,         /* .cfg overwrite */    \
        .valid_rx_ant = ANT_AB,         /* .cfg overwrite */    \
        .lib = &iwl6000_lib,                                    \
@@ -497,13 +504,13 @@ struct iwl_cfg iwl6000i_2bg_cfg = {
        .led_mode = IWL_LED_BLINK,                              \
        .internal_wimax_coex = true
 
-struct iwl_cfg iwl6050_2agn_cfg = {
+const struct iwl_cfg iwl6050_2agn_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N + WiMAX 6250 AGN",
        IWL_DEVICE_6050,
        .ht_params = &iwl6000_ht_params,
 };
 
-struct iwl_cfg iwl6050_2abg_cfg = {
+const struct iwl_cfg iwl6050_2abg_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N + WiMAX 6250 ABG",
        IWL_DEVICE_6050,
 };
@@ -512,6 +519,8 @@ struct iwl_cfg iwl6050_2abg_cfg = {
        .fw_name_pre = IWL6050_FW_PRE,                          \
        .ucode_api_max = IWL6050_UCODE_API_MAX,                 \
        .ucode_api_min = IWL6050_UCODE_API_MIN,                 \
+       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
+       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
        .lib = &iwl6000_lib,                                    \
        .additional_nic_config = iwl6150_additional_nic_config, \
        .eeprom_ver = EEPROM_6150_EEPROM_VERSION,               \
@@ -520,23 +529,25 @@ struct iwl_cfg iwl6050_2abg_cfg = {
        .led_mode = IWL_LED_BLINK,                              \
        .internal_wimax_coex = true
 
-struct iwl_cfg iwl6150_bgn_cfg = {
+const struct iwl_cfg iwl6150_bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N + WiMAX 6150 BGN",
        IWL_DEVICE_6150,
        .ht_params = &iwl6000_ht_params,
 };
 
-struct iwl_cfg iwl6150_bg_cfg = {
+const struct iwl_cfg iwl6150_bg_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N + WiMAX 6150 BG",
        IWL_DEVICE_6150,
 };
 
-struct iwl_cfg iwl6000_3agn_cfg = {
+const struct iwl_cfg iwl6000_3agn_cfg = {
        .name = "Intel(R) Centrino(R) Ultimate-N 6300 AGN",
        .fw_name_pre = IWL6000_FW_PRE,
        .ucode_api_max = IWL6000_UCODE_API_MAX,
        .ucode_api_ok = IWL6000_UCODE_API_OK,
        .ucode_api_min = IWL6000_UCODE_API_MIN,
+       .max_inst_size = IWL60_RTC_INST_SIZE,
+       .max_data_size = IWL60_RTC_DATA_SIZE,
        .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,
        .lib = &iwl6000_lib,
index 6aa009827865d677dfd512bafb23038ecc00ae8f..84cbe7bb504cad1c3cfdb68cb9bcc1270c4d80ad 100644 (file)
  * INIT calibrations framework
  *****************************************************************************/
 
+/* Opaque calibration results */
+struct iwl_calib_result {
+       struct list_head list;
+       size_t cmd_len;
+       struct iwl_calib_hdr hdr;
+       /* data follows */
+};
+
 struct statistics_general_data {
        u32 beacon_silence_rssi_a;
        u32 beacon_silence_rssi_b;
@@ -82,7 +90,7 @@ struct statistics_general_data {
        u32 beacon_energy_c;
 };
 
-int iwl_send_calib_results(struct iwl_trans *trans)
+int iwl_send_calib_results(struct iwl_priv *priv)
 {
        struct iwl_host_cmd hcmd = {
                .id = REPLY_PHY_CALIBRATION_CMD,
@@ -90,15 +98,15 @@ int iwl_send_calib_results(struct iwl_trans *trans)
        };
        struct iwl_calib_result *res;
 
-       list_for_each_entry(res, &trans->calib_results, list) {
+       list_for_each_entry(res, &priv->calib_results, list) {
                int ret;
 
                hcmd.len[0] = res->cmd_len;
                hcmd.data[0] = &res->hdr;
                hcmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
-               ret = iwl_trans_send_cmd(trans, &hcmd);
+               ret = iwl_dvm_send_cmd(priv, &hcmd);
                if (ret) {
-                       IWL_ERR(trans, "Error %d on calib cmd %d\n",
+                       IWL_ERR(priv, "Error %d on calib cmd %d\n",
                                ret, res->hdr.op_code);
                        return ret;
                }
@@ -107,7 +115,7 @@ int iwl_send_calib_results(struct iwl_trans *trans)
        return 0;
 }
 
-int iwl_calib_set(struct iwl_trans *trans,
+int iwl_calib_set(struct iwl_priv *priv,
                  const struct iwl_calib_hdr *cmd, int len)
 {
        struct iwl_calib_result *res, *tmp;
@@ -119,7 +127,7 @@ int iwl_calib_set(struct iwl_trans *trans,
        memcpy(&res->hdr, cmd, len);
        res->cmd_len = len;
 
-       list_for_each_entry(tmp, &trans->calib_results, list) {
+       list_for_each_entry(tmp, &priv->calib_results, list) {
                if (tmp->hdr.op_code == res->hdr.op_code) {
                        list_replace(&tmp->list, &res->list);
                        kfree(tmp);
@@ -128,16 +136,16 @@ int iwl_calib_set(struct iwl_trans *trans,
        }
 
        /* wasn't in list already */
-       list_add_tail(&res->list, &trans->calib_results);
+       list_add_tail(&res->list, &priv->calib_results);
 
        return 0;
 }
 
-void iwl_calib_free_results(struct iwl_trans *trans)
+void iwl_calib_free_results(struct iwl_priv *priv)
 {
        struct iwl_calib_result *res, *tmp;
 
-       list_for_each_entry_safe(res, tmp, &trans->calib_results, list) {
+       list_for_each_entry_safe(res, tmp, &priv->calib_results, list) {
                list_del(&res->list);
                kfree(res);
        }
@@ -492,7 +500,7 @@ static int iwl_sensitivity_write(struct iwl_priv *priv)
        memcpy(&(priv->sensitivity_tbl[0]), &(cmd.table[0]),
               sizeof(u16)*HD_TABLE_SIZE);
 
-       return iwl_trans_send_cmd(trans(priv), &cmd_out);
+       return iwl_dvm_send_cmd(priv, &cmd_out);
 }
 
 /* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */
@@ -581,7 +589,7 @@ static int iwl_enhance_sensitivity_write(struct iwl_priv *priv)
               &(cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX]),
               sizeof(u16)*ENHANCE_HD_TABLE_ENTRIES);
 
-       return iwl_trans_send_cmd(trans(priv), &cmd_out);
+       return iwl_dvm_send_cmd(priv, &cmd_out);
 }
 
 void iwl_init_sensitivity(struct iwl_priv *priv)
@@ -634,7 +642,7 @@ void iwl_init_sensitivity(struct iwl_priv *priv)
        data->last_bad_plcp_cnt_cck = 0;
        data->last_fa_cnt_cck = 0;
 
-       if (priv->enhance_sensitivity_table)
+       if (priv->fw->enhance_sensitivity_table)
                ret |= iwl_enhance_sensitivity_write(priv);
        else
                ret |= iwl_sensitivity_write(priv);
@@ -653,7 +661,6 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv)
        struct iwl_sensitivity_data *data = NULL;
        struct statistics_rx_non_phy *rx_info;
        struct statistics_rx_phy *ofdm, *cck;
-       unsigned long flags;
        struct statistics_general_data statis;
 
        if (priv->disable_sens_cal)
@@ -666,13 +673,13 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv)
                return;
        }
 
-       spin_lock_irqsave(&priv->shrd->lock, flags);
+       spin_lock_bh(&priv->statistics.lock);
        rx_info = &priv->statistics.rx_non_phy;
        ofdm = &priv->statistics.rx_ofdm;
        cck = &priv->statistics.rx_cck;
        if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
                IWL_DEBUG_CALIB(priv, "<< invalid data.\n");
-               spin_unlock_irqrestore(&priv->shrd->lock, flags);
+               spin_unlock_bh(&priv->statistics.lock);
                return;
        }
 
@@ -696,7 +703,7 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv)
        statis.beacon_energy_c =
                        le32_to_cpu(rx_info->beacon_energy_c);
 
-       spin_unlock_irqrestore(&priv->shrd->lock, flags);
+       spin_unlock_bh(&priv->statistics.lock);
 
        IWL_DEBUG_CALIB(priv, "rx_enable_time = %u usecs\n", rx_enable_time);
 
@@ -745,7 +752,7 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv)
 
        iwl_sens_auto_corr_ofdm(priv, norm_fa_ofdm, rx_enable_time);
        iwl_sens_energy_cck(priv, norm_fa_cck, rx_enable_time, &statis);
-       if (priv->enhance_sensitivity_table)
+       if (priv->fw->enhance_sensitivity_table)
                iwl_enhance_sensitivity_write(priv);
        else
                iwl_sensitivity_write(priv);
@@ -847,7 +854,7 @@ static void iwl_find_disconn_antenna(struct iwl_priv *priv, u32* average_sig,
                         * connect the first valid tx chain
                         */
                        first_chain =
-                               find_first_chain(cfg(priv)->valid_tx_ant);
+                               find_first_chain(hw_params(priv).valid_tx_ant);
                        data->disconn_array[first_chain] = 0;
                        active_chains |= BIT(first_chain);
                        IWL_DEBUG_CALIB(priv,
@@ -872,10 +879,8 @@ static void iwl_find_disconn_antenna(struct iwl_priv *priv, u32* average_sig,
 }
 
 static void iwlagn_gain_computation(struct iwl_priv *priv,
-               u32 average_noise[NUM_RX_CHAINS],
-               u16 min_average_noise_antenna_i,
-               u32 min_average_noise,
-               u8 default_chain)
+                                   u32 average_noise[NUM_RX_CHAINS],
+                                   u8 default_chain)
 {
        int i;
        s32 delta_g;
@@ -923,7 +928,7 @@ static void iwlagn_gain_computation(struct iwl_priv *priv,
                        priv->phy_calib_chain_noise_gain_cmd);
                cmd.delta_gain_1 = data->delta_gain_code[1];
                cmd.delta_gain_2 = data->delta_gain_code[2];
-               iwl_trans_send_cmd_pdu(trans(priv), REPLY_PHY_CALIBRATION_CMD,
+               iwl_dvm_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
                        CMD_ASYNC, sizeof(cmd), &cmd);
 
                data->radio_write = 1;
@@ -956,7 +961,6 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv)
        u16 stat_chnum = INITIALIZATION_VALUE;
        u8 rxon_band24;
        u8 stat_band24;
-       unsigned long flags;
        struct statistics_rx_non_phy *rx_info;
 
        /*
@@ -981,13 +985,13 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv)
                return;
        }
 
-       spin_lock_irqsave(&priv->shrd->lock, flags);
+       spin_lock_bh(&priv->statistics.lock);
 
        rx_info = &priv->statistics.rx_non_phy;
 
        if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
                IWL_DEBUG_CALIB(priv, " << Interference data unavailable\n");
-               spin_unlock_irqrestore(&priv->shrd->lock, flags);
+               spin_unlock_bh(&priv->statistics.lock);
                return;
        }
 
@@ -1002,7 +1006,7 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv)
        if ((rxon_chnum != stat_chnum) || (rxon_band24 != stat_band24)) {
                IWL_DEBUG_CALIB(priv, "Stats not from chan=%d, band24=%d\n",
                                rxon_chnum, rxon_band24);
-               spin_unlock_irqrestore(&priv->shrd->lock, flags);
+               spin_unlock_bh(&priv->statistics.lock);
                return;
        }
 
@@ -1021,7 +1025,7 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv)
        chain_sig_b = le32_to_cpu(rx_info->beacon_rssi_b) & IN_BAND_FILTER;
        chain_sig_c = le32_to_cpu(rx_info->beacon_rssi_c) & IN_BAND_FILTER;
 
-       spin_unlock_irqrestore(&priv->shrd->lock, flags);
+       spin_unlock_bh(&priv->statistics.lock);
 
        data->beacon_count++;
 
@@ -1081,8 +1085,7 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv)
                        min_average_noise, min_average_noise_antenna_i);
 
        iwlagn_gain_computation(priv, average_noise,
-                               min_average_noise_antenna_i, min_average_noise,
-                               find_first_chain(cfg(priv)->valid_rx_ant));
+                               find_first_chain(hw_params(priv).valid_rx_ant));
 
        /* Some power changes may have been made during the calibration.
         * Update and commit the RXON
index a8f7689aaacfb91049941c736ff46660c4830313..f98baaba0c2a219c859f933309f3bd960e6c81e5 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 
-#include "iwl-wifi.h"
 #include "iwl-dev.h"
 #include "iwl-core.h"
 #include "iwl-io.h"
@@ -52,7 +51,7 @@ int iwlagn_send_tx_power(struct iwl_priv *priv)
        struct iwlagn_tx_power_dbm_cmd tx_power_cmd;
        u8 tx_ant_cfg_cmd;
 
-       if (WARN_ONCE(test_bit(STATUS_SCAN_HW, &priv->shrd->status),
+       if (WARN_ONCE(test_bit(STATUS_SCAN_HW, &priv->status),
                      "TX Power requested while scanning!\n"))
                return -EAGAIN;
 
@@ -77,17 +76,19 @@ int iwlagn_send_tx_power(struct iwl_priv *priv)
        tx_power_cmd.flags = IWLAGN_TX_POWER_NO_CLOSED;
        tx_power_cmd.srv_chan_lmt = IWLAGN_TX_POWER_AUTO;
 
-       if (IWL_UCODE_API(priv->ucode_ver) == 1)
+       if (IWL_UCODE_API(priv->fw->ucode_ver) == 1)
                tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD_V1;
        else
                tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD;
 
-       return iwl_trans_send_cmd_pdu(trans(priv), tx_ant_cfg_cmd, CMD_SYNC,
+       return iwl_dvm_send_cmd_pdu(priv, tx_ant_cfg_cmd, CMD_SYNC,
                        sizeof(tx_power_cmd), &tx_power_cmd);
 }
 
 void iwlagn_temperature(struct iwl_priv *priv)
 {
+       lockdep_assert_held(&priv->statistics.lock);
+
        /* store temperature from correct statistics (in Celsius) */
        priv->temperature = le32_to_cpu(priv->statistics.common.temperature);
        iwl_tt_handler(priv);
@@ -233,19 +234,19 @@ int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control)
                                IWL_PAN_SCD_BK_MSK | IWL_PAN_SCD_MGMT_MSK |
                                IWL_PAN_SCD_MULTICAST_MSK;
 
-       if (cfg(priv)->sku & EEPROM_SKU_CAP_11N_ENABLE)
+       if (hw_params(priv).sku & EEPROM_SKU_CAP_11N_ENABLE)
                flush_cmd.fifo_control |= IWL_AGG_TX_QUEUE_MSK;
 
        IWL_DEBUG_INFO(priv, "fifo queue control: 0X%x\n",
                       flush_cmd.fifo_control);
        flush_cmd.flush_control = cpu_to_le16(flush_control);
 
-       return iwl_trans_send_cmd(trans(priv), &cmd);
+       return iwl_dvm_send_cmd(priv, &cmd);
 }
 
 void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control)
 {
-       mutex_lock(&priv->shrd->mutex);
+       mutex_lock(&priv->mutex);
        ieee80211_stop_queues(priv->hw);
        if (iwlagn_txfifo_flush(priv, IWL_DROP_ALL)) {
                IWL_ERR(priv, "flush request fail\n");
@@ -255,7 +256,7 @@ void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control)
        iwl_trans_wait_tx_queue_empty(trans(priv));
 done:
        ieee80211_wake_queues(priv->hw);
-       mutex_unlock(&priv->shrd->mutex);
+       mutex_unlock(&priv->mutex);
 }
 
 /*
@@ -434,12 +435,12 @@ void iwlagn_send_advance_bt_config(struct iwl_priv *priv)
        if (cfg(priv)->bt_params->bt_session_2) {
                memcpy(&bt_cmd_2000.basic, &basic,
                        sizeof(basic));
-               ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_BT_CONFIG,
+               ret = iwl_dvm_send_cmd_pdu(priv, REPLY_BT_CONFIG,
                        CMD_SYNC, sizeof(bt_cmd_2000), &bt_cmd_2000);
        } else {
                memcpy(&bt_cmd_6000.basic, &basic,
                        sizeof(basic));
-               ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_BT_CONFIG,
+               ret = iwl_dvm_send_cmd_pdu(priv, REPLY_BT_CONFIG,
                        CMD_SYNC, sizeof(bt_cmd_6000), &bt_cmd_6000);
        }
        if (ret)
@@ -452,7 +453,7 @@ void iwlagn_bt_adjust_rssi_monitor(struct iwl_priv *priv, bool rssi_ena)
        struct iwl_rxon_context *ctx, *found_ctx = NULL;
        bool found_ap = false;
 
-       lockdep_assert_held(&priv->shrd->mutex);
+       lockdep_assert_held(&priv->mutex);
 
        /* Check whether AP or GO mode is active. */
        if (rssi_ena) {
@@ -565,7 +566,7 @@ static void iwlagn_bt_traffic_change_work(struct work_struct *work)
                break;
        }
 
-       mutex_lock(&priv->shrd->mutex);
+       mutex_lock(&priv->mutex);
 
        /*
         * We can not send command to firmware while scanning. When the scan
@@ -574,7 +575,7 @@ static void iwlagn_bt_traffic_change_work(struct work_struct *work)
         * STATUS_SCANNING to avoid race when queue_work two times from
         * different notifications, but quit and not perform any work at all.
         */
-       if (test_bit(STATUS_SCAN_HW, &priv->shrd->status))
+       if (test_bit(STATUS_SCAN_HW, &priv->status))
                goto out;
 
        iwl_update_chain_flags(priv);
@@ -593,7 +594,7 @@ static void iwlagn_bt_traffic_change_work(struct work_struct *work)
         */
        iwlagn_bt_coex_rssi_monitor(priv);
 out:
-       mutex_unlock(&priv->shrd->mutex);
+       mutex_unlock(&priv->mutex);
 }
 
 /*
@@ -700,17 +701,16 @@ static void iwlagn_set_kill_msk(struct iwl_priv *priv,
                priv->kill_cts_mask = bt_kill_cts_msg[kill_msk];
 
                /* schedule to send runtime bt_config */
-               queue_work(priv->shrd->workqueue, &priv->bt_runtime_config);
+               queue_work(priv->workqueue, &priv->bt_runtime_config);
        }
 }
 
 int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
-                                 struct iwl_rx_mem_buffer *rxb,
+                                 struct iwl_rx_cmd_buffer *rxb,
                                  struct iwl_device_cmd *cmd)
 {
-       unsigned long flags;
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_bt_coex_profile_notif *coex = &pkt->u.bt_coex_profile_notif;
+       struct iwl_bt_coex_profile_notif *coex = (void *)pkt->data;
        struct iwl_bt_uart_msg *uart_msg = &coex->last_bt_uart_msg;
 
        if (priv->bt_enable_flag == IWLAGN_BT_FLAG_COEX_MODE_DISABLED) {
@@ -745,7 +745,7 @@ int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
                                        IWL_BT_COEX_TRAFFIC_LOAD_NONE;
                        }
                        priv->bt_status = coex->bt_status;
-                       queue_work(priv->shrd->workqueue,
+                       queue_work(priv->workqueue,
                                   &priv->bt_traffic_change_work);
                }
        }
@@ -754,9 +754,7 @@ int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
 
        /* FIXME: based on notification, adjust the prio_boost */
 
-       spin_lock_irqsave(&priv->shrd->lock, flags);
        priv->bt_ci_compliance = coex->bt_ci_compliance;
-       spin_unlock_irqrestore(&priv->shrd->lock, flags);
        return 0;
 }
 
@@ -959,7 +957,7 @@ static void iwlagn_wowlan_program_keys(struct ieee80211_hw *hw,
                               struct ieee80211_key_conf *key,
                               void *_data)
 {
-       struct iwl_priv *priv = hw->priv;
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
        struct wowlan_key_data *data = _data;
        struct iwl_rxon_context *ctx = data->ctx;
        struct aes_sc *aes_sc, *aes_tx_sc = NULL;
@@ -971,7 +969,7 @@ static void iwlagn_wowlan_program_keys(struct ieee80211_hw *hw,
        u16 p1k[IWLAGN_P1K_SIZE];
        int ret, i;
 
-       mutex_lock(&priv->shrd->mutex);
+       mutex_lock(&priv->mutex);
 
        if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
             key->cipher == WLAN_CIPHER_SUITE_WEP104) &&
@@ -1077,7 +1075,7 @@ static void iwlagn_wowlan_program_keys(struct ieee80211_hw *hw,
                break;
        }
 
-       mutex_unlock(&priv->shrd->mutex);
+       mutex_unlock(&priv->mutex);
 }
 
 int iwlagn_send_patterns(struct iwl_priv *priv,
@@ -1117,13 +1115,12 @@ int iwlagn_send_patterns(struct iwl_priv *priv,
        }
 
        cmd.data[0] = pattern_cmd;
-       err = iwl_trans_send_cmd(trans(priv), &cmd);
+       err = iwl_dvm_send_cmd(priv, &cmd);
        kfree(pattern_cmd);
        return err;
 }
 
-int iwlagn_suspend(struct iwl_priv *priv,
-               struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
+int iwlagn_suspend(struct iwl_priv *priv, struct cfg80211_wowlan *wowlan)
 {
        struct iwlagn_wowlan_wakeup_filter_cmd wakeup_filter_cmd;
        struct iwl_rxon_cmd rxon;
@@ -1194,9 +1191,9 @@ int iwlagn_suspend(struct iwl_priv *priv,
 
        iwl_trans_stop_device(trans(priv));
 
-       priv->shrd->wowlan = true;
+       priv->wowlan = true;
 
-       ret = iwl_load_ucode_wait_alive(trans(priv), IWL_UCODE_WOWLAN);
+       ret = iwl_load_ucode_wait_alive(priv, IWL_UCODE_WOWLAN);
        if (ret)
                goto out;
 
@@ -1224,11 +1221,11 @@ int iwlagn_suspend(struct iwl_priv *priv,
                 * constraints. Since we're in the suspend path
                 * that isn't really a problem though.
                 */
-               mutex_unlock(&priv->shrd->mutex);
+               mutex_unlock(&priv->mutex);
                ieee80211_iter_keys(priv->hw, ctx->vif,
                                    iwlagn_wowlan_program_keys,
                                    &key_data);
-               mutex_lock(&priv->shrd->mutex);
+               mutex_lock(&priv->mutex);
                if (key_data.error) {
                        ret = -EIO;
                        goto out;
@@ -1240,16 +1237,16 @@ int iwlagn_suspend(struct iwl_priv *priv,
                                .flags = CMD_SYNC,
                                .data[0] = key_data.rsc_tsc,
                                .dataflags[0] = IWL_HCMD_DFL_NOCOPY,
-                               .len[0] = sizeof(key_data.rsc_tsc),
+                               .len[0] = sizeof(*key_data.rsc_tsc),
                        };
 
-                       ret = iwl_trans_send_cmd(trans(priv), &rsc_tsc_cmd);
+                       ret = iwl_dvm_send_cmd(priv, &rsc_tsc_cmd);
                        if (ret)
                                goto out;
                }
 
                if (key_data.use_tkip) {
-                       ret = iwl_trans_send_cmd_pdu(trans(priv),
+                       ret = iwl_dvm_send_cmd_pdu(priv,
                                                 REPLY_WOWLAN_TKIP_PARAMS,
                                                 CMD_SYNC, sizeof(tkip_cmd),
                                                 &tkip_cmd);
@@ -1265,7 +1262,7 @@ int iwlagn_suspend(struct iwl_priv *priv,
                        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),
+                       ret = iwl_dvm_send_cmd_pdu(priv,
                                                 REPLY_WOWLAN_KEK_KCK_MATERIAL,
                                                 CMD_SYNC, sizeof(kek_kck_cmd),
                                                 &kek_kck_cmd);
@@ -1274,12 +1271,12 @@ int iwlagn_suspend(struct iwl_priv *priv,
                }
        }
 
-       ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_D3_CONFIG, CMD_SYNC,
+       ret = iwl_dvm_send_cmd_pdu(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,
+       ret = iwl_dvm_send_cmd_pdu(priv, REPLY_WOWLAN_WAKEUP_FILTER,
                                 CMD_SYNC, sizeof(wakeup_filter_cmd),
                                 &wakeup_filter_cmd);
        if (ret)
@@ -1291,3 +1288,41 @@ int iwlagn_suspend(struct iwl_priv *priv,
        return ret;
 }
 #endif
+
+int iwl_dvm_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+{
+       if (iwl_is_rfkill(priv) || iwl_is_ctkill(priv)) {
+               IWL_WARN(priv, "Not sending command - %s KILL\n",
+                        iwl_is_rfkill(priv) ? "RF" : "CT");
+               return -EIO;
+       }
+
+       /*
+        * Synchronous commands from this op-mode must hold
+        * the mutex, this ensures we don't try to send two
+        * (or more) synchronous commands at a time.
+        */
+       if (cmd->flags & CMD_SYNC)
+               lockdep_assert_held(&priv->mutex);
+
+       if (priv->ucode_owner == IWL_OWNERSHIP_TM &&
+           !(cmd->flags & CMD_ON_DEMAND)) {
+               IWL_DEBUG_HC(priv, "tm own the uCode, no regular hcmd send\n");
+               return -EIO;
+       }
+
+       return iwl_trans_send_cmd(trans(priv), cmd);
+}
+
+int iwl_dvm_send_cmd_pdu(struct iwl_priv *priv, u8 id,
+                        u32 flags, u16 len, const void *data)
+{
+       struct iwl_host_cmd cmd = {
+               .id = id,
+               .len = { len, },
+               .data = { data, },
+               .flags = flags,
+       };
+
+       return iwl_dvm_send_cmd(priv, &cmd);
+}
index b9ba404d15c1cdd25271175e20848247571aa1de..53f8c51cfcdb021d292caf5f911694413df42d4c 100644 (file)
@@ -38,6 +38,7 @@
 #include "iwl-dev.h"
 #include "iwl-core.h"
 #include "iwl-agn.h"
+#include "iwl-op-mode.h"
 
 #define RS_NAME "iwl-agn-rs"
 
@@ -869,19 +870,16 @@ static void rs_bt_update_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
 {
        struct iwl_scale_tbl_info *tbl;
        bool full_concurrent = priv->bt_full_concurrent;
-       unsigned long flags;
 
        if (priv->bt_ant_couple_ok) {
                /*
                 * Is there a need to switch between
                 * full concurrency and 3-wire?
                 */
-               spin_lock_irqsave(&priv->shrd->lock, flags);
                if (priv->bt_ci_compliance && priv->bt_ant_couple_ok)
                        full_concurrent = true;
                else
                        full_concurrent = false;
-               spin_unlock_irqrestore(&priv->shrd->lock, flags);
        }
        if ((priv->bt_traffic_load != priv->last_bt_traffic_load) ||
            (priv->bt_full_concurrent != full_concurrent)) {
@@ -892,7 +890,7 @@ static void rs_bt_update_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
                rs_fill_link_cmd(priv, lq_sta, tbl->current_rate);
                iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_ASYNC, false);
 
-               queue_work(priv->shrd->workqueue, &priv->bt_full_concurrency);
+               queue_work(priv->workqueue, &priv->bt_full_concurrency);
        }
 }
 
@@ -909,7 +907,8 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
        struct iwl_lq_sta *lq_sta = priv_sta;
        struct iwl_link_quality_cmd *table;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-       struct iwl_priv *priv = (struct iwl_priv *)priv_r;
+       struct iwl_op_mode *op_mode = (struct iwl_op_mode *)priv_r;
+       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        enum mac80211_rate_control_flags mac_flags;
        u32 tx_rate;
@@ -2678,7 +2677,6 @@ out:
  *       which requires station table entry to exist).
  */
 static void rs_initialize_lq(struct iwl_priv *priv,
-                            struct ieee80211_conf *conf,
                             struct ieee80211_sta *sta,
                             struct iwl_lq_sta *lq_sta)
 {
@@ -2737,7 +2735,9 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
 
        struct sk_buff *skb = txrc->skb;
        struct ieee80211_supported_band *sband = txrc->sband;
-       struct iwl_priv *priv __maybe_unused = (struct iwl_priv *)priv_r;
+       struct iwl_op_mode *op_mode __maybe_unused =
+                       (struct iwl_op_mode *)priv_r;
+       struct iwl_priv *priv __maybe_unused = IWL_OP_MODE_GET_DVM(op_mode);
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct iwl_lq_sta *lq_sta = priv_sta;
        int rate_idx;
@@ -2805,9 +2805,10 @@ static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta,
                          gfp_t gfp)
 {
        struct iwl_station_priv *sta_priv = (struct iwl_station_priv *) sta->drv_priv;
-       struct iwl_priv *priv;
+       struct iwl_op_mode *op_mode __maybe_unused =
+                       (struct iwl_op_mode *)priv_rate;
+       struct iwl_priv *priv __maybe_unused = IWL_OP_MODE_GET_DVM(op_mode);
 
-       priv = (struct iwl_priv *)priv_rate;
        IWL_DEBUG_RATE(priv, "create station rate scale window\n");
 
        return &sta_priv->lq_sta;
@@ -2910,7 +2911,7 @@ void iwl_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 sta_i
        lq_sta->dbg_fixed_rate = 0;
 #endif
 
-       rs_initialize_lq(priv, conf, sta, lq_sta);
+       rs_initialize_lq(priv, sta, lq_sta);
 }
 
 static void rs_fill_link_cmd(struct iwl_priv *priv,
@@ -3074,7 +3075,8 @@ static void rs_free(void *priv_rate)
 static void rs_free_sta(void *priv_r, struct ieee80211_sta *sta,
                        void *priv_sta)
 {
-       struct iwl_priv *priv __maybe_unused = priv_r;
+       struct iwl_op_mode *op_mode __maybe_unused = priv_r;
+       struct iwl_priv *priv __maybe_unused = IWL_OP_MODE_GET_DVM(op_mode);
 
        IWL_DEBUG_RATE(priv, "enter\n");
        IWL_DEBUG_RATE(priv, "leave\n");
index a14ddab783ea6985907c3693cc131d77bcf60b51..cc0227c1f3525bb9cf45b9088c777741c4f7b933 100644 (file)
@@ -131,26 +131,27 @@ const char *get_cmd_string(u8 cmd)
  ******************************************************************************/
 
 static int iwlagn_rx_reply_error(struct iwl_priv *priv,
-                              struct iwl_rx_mem_buffer *rxb,
+                              struct iwl_rx_cmd_buffer *rxb,
                               struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_error_resp *err_resp = (void *)pkt->data;
 
        IWL_ERR(priv, "Error Reply type 0x%08X cmd %s (0x%02X) "
                "seq 0x%04X ser 0x%08X\n",
-               le32_to_cpu(pkt->u.err_resp.error_type),
-               get_cmd_string(pkt->u.err_resp.cmd_id),
-               pkt->u.err_resp.cmd_id,
-               le16_to_cpu(pkt->u.err_resp.bad_cmd_seq_num),
-               le32_to_cpu(pkt->u.err_resp.error_info));
+               le32_to_cpu(err_resp->error_type),
+               get_cmd_string(err_resp->cmd_id),
+               err_resp->cmd_id,
+               le16_to_cpu(err_resp->bad_cmd_seq_num),
+               le32_to_cpu(err_resp->error_info));
        return 0;
 }
 
-static int iwlagn_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
+static int iwlagn_rx_csa(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
                               struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_csa_notification *csa = &(pkt->u.csa_notif);
+       struct iwl_csa_notification *csa = (void *)pkt->data;
        /*
         * MULTI-FIXME
         * See iwlagn_mac_channel_switch.
@@ -158,7 +159,7 @@ static int iwlagn_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
        struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
        struct iwl_rxon_cmd *rxon = (void *)&ctx->active;
 
-       if (!test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status))
+       if (!test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
                return 0;
 
        if (!le32_to_cpu(csa->status) && csa->channel == priv->switch_channel) {
@@ -177,11 +178,11 @@ static int iwlagn_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
 
 
 static int iwlagn_rx_spectrum_measure_notif(struct iwl_priv *priv,
-                                         struct iwl_rx_mem_buffer *rxb,
+                                         struct iwl_rx_cmd_buffer *rxb,
                                          struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif);
+       struct iwl_spectrum_notification *report = (void *)pkt->data;
 
        if (!report->state) {
                IWL_DEBUG_11H(priv,
@@ -195,12 +196,12 @@ static int iwlagn_rx_spectrum_measure_notif(struct iwl_priv *priv,
 }
 
 static int iwlagn_rx_pm_sleep_notif(struct iwl_priv *priv,
-                                 struct iwl_rx_mem_buffer *rxb,
+                                 struct iwl_rx_cmd_buffer *rxb,
                                  struct iwl_device_cmd *cmd)
 {
 #ifdef CONFIG_IWLWIFI_DEBUG
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif);
+       struct iwl_sleep_notification *sleep = (void *)pkt->data;
        IWL_DEBUG_RX(priv, "sleep mode: %d, src: %d\n",
                     sleep->pm_sleep_mode, sleep->pm_wakeup_src);
 #endif
@@ -208,7 +209,7 @@ static int iwlagn_rx_pm_sleep_notif(struct iwl_priv *priv,
 }
 
 static int iwlagn_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
-                                            struct iwl_rx_mem_buffer *rxb,
+                                            struct iwl_rx_cmd_buffer *rxb,
                                             struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
@@ -217,16 +218,16 @@ static int iwlagn_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
        IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled "
                        "notification for %s:\n", len,
                        get_cmd_string(pkt->hdr.cmd));
-       iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, len);
+       iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->data, len);
        return 0;
 }
 
 static int iwlagn_rx_beacon_notif(struct iwl_priv *priv,
-                               struct iwl_rx_mem_buffer *rxb,
+                               struct iwl_rx_cmd_buffer *rxb,
                                struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwlagn_beacon_notif *beacon = (void *)pkt->u.raw;
+       struct iwlagn_beacon_notif *beacon = (void *)pkt->data;
 #ifdef CONFIG_IWLWIFI_DEBUG
        u16 status = le16_to_cpu(beacon->beacon_notify_hdr.status.status);
        u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags);
@@ -266,6 +267,8 @@ static bool iwlagn_good_ack_health(struct iwl_priv *priv,
        if (priv->agg_tids_count)
                return true;
 
+       lockdep_assert_held(&priv->statistics.lock);
+
        old = &priv->statistics.tx;
 
        actual_delta = le32_to_cpu(cur->actual_ack_cnt) -
@@ -318,7 +321,7 @@ static bool iwlagn_good_plcp_health(struct iwl_priv *priv,
                                 unsigned int msecs)
 {
        int delta;
-       int threshold = cfg(priv)->base_params->plcp_delta_threshold;
+       int threshold = priv->plcp_delta_threshold;
 
        if (threshold == IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE) {
                IWL_DEBUG_RADIO(priv, "plcp_err check disabled\n");
@@ -352,7 +355,7 @@ static void iwlagn_recover_from_statistics(struct iwl_priv *priv,
 {
        unsigned int msecs;
 
-       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
        msecs = jiffies_to_msecs(stamp - priv->rx_statistics_jiffies);
@@ -487,7 +490,7 @@ iwlagn_accumulative_statistics(struct iwl_priv *priv,
 #endif
 
 static int iwlagn_rx_statistics(struct iwl_priv *priv,
-                             struct iwl_rx_mem_buffer *rxb,
+                             struct iwl_rx_cmd_buffer *rxb,
                              struct iwl_device_cmd *cmd)
 {
        unsigned long stamp = jiffies;
@@ -509,9 +512,11 @@ static int iwlagn_rx_statistics(struct iwl_priv *priv,
        IWL_DEBUG_RX(priv, "Statistics notification received (%d bytes).\n",
                     len);
 
+       spin_lock(&priv->statistics.lock);
+
        if (len == sizeof(struct iwl_bt_notif_statistics)) {
                struct iwl_bt_notif_statistics *stats;
-               stats = &pkt->u.stats_bt;
+               stats = (void *)&pkt->data;
                flag = &stats->flag;
                common = &stats->general.common;
                rx_non_phy = &stats->rx.general.common;
@@ -529,7 +534,7 @@ static int iwlagn_rx_statistics(struct iwl_priv *priv,
 #endif
        } else if (len == sizeof(struct iwl_notif_statistics)) {
                struct iwl_notif_statistics *stats;
-               stats = &pkt->u.stats;
+               stats = (void *)&pkt->data;
                flag = &stats->flag;
                common = &stats->general.common;
                rx_non_phy = &stats->rx.general;
@@ -542,6 +547,7 @@ static int iwlagn_rx_statistics(struct iwl_priv *priv,
                WARN_ONCE(1, "len %d doesn't match BT (%zu) or normal (%zu)\n",
                          len, sizeof(struct iwl_bt_notif_statistics),
                          sizeof(struct iwl_notif_statistics));
+               spin_unlock(&priv->statistics.lock);
                return 0;
        }
 
@@ -569,7 +575,7 @@ static int iwlagn_rx_statistics(struct iwl_priv *priv,
 
        priv->rx_statistics_jiffies = stamp;
 
-       set_bit(STATUS_STATISTICS, &priv->shrd->status);
+       set_bit(STATUS_STATISTICS, &priv->status);
 
        /* Reschedule the statistics timer to occur in
         * reg_recalib_period seconds to ensure we get a
@@ -578,23 +584,27 @@ static int iwlagn_rx_statistics(struct iwl_priv *priv,
        mod_timer(&priv->statistics_periodic, jiffies +
                  msecs_to_jiffies(reg_recalib_period * 1000));
 
-       if (unlikely(!test_bit(STATUS_SCANNING, &priv->shrd->status)) &&
+       if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) &&
            (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) {
                iwlagn_rx_calc_noise(priv);
-               queue_work(priv->shrd->workqueue, &priv->run_time_calib_work);
+               queue_work(priv->workqueue, &priv->run_time_calib_work);
        }
        if (cfg(priv)->lib->temperature && change)
                cfg(priv)->lib->temperature(priv);
+
+       spin_unlock(&priv->statistics.lock);
+
        return 0;
 }
 
 static int iwlagn_rx_reply_statistics(struct iwl_priv *priv,
-                                   struct iwl_rx_mem_buffer *rxb,
+                                   struct iwl_rx_cmd_buffer *rxb,
                                    struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_notif_statistics *stats = (void *)pkt->data;
 
-       if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) {
+       if (le32_to_cpu(stats->flag) & UCODE_STATISTICS_CLEAR_MSK) {
 #ifdef CONFIG_IWLWIFI_DEBUGFS
                memset(&priv->accum_stats, 0,
                        sizeof(priv->accum_stats));
@@ -612,12 +622,13 @@ static int iwlagn_rx_reply_statistics(struct iwl_priv *priv,
 /* Handle notification from uCode that card's power state is changing
  * due to software, hardware, or critical temperature RFKILL */
 static int iwlagn_rx_card_state_notif(struct iwl_priv *priv,
-                                   struct iwl_rx_mem_buffer *rxb,
+                                   struct iwl_rx_cmd_buffer *rxb,
                                    struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
-       unsigned long status = priv->shrd->status;
+       struct iwl_card_state_notif *card_state_notif = (void *)pkt->data;
+       u32 flags = le32_to_cpu(card_state_notif->flags);
+       unsigned long status = priv->status;
 
        IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s CT:%s\n",
                          (flags & HW_CARD_DISABLED) ? "Kill" : "On",
@@ -647,32 +658,31 @@ static int iwlagn_rx_card_state_notif(struct iwl_priv *priv,
                iwl_tt_exit_ct_kill(priv);
 
        if (flags & HW_CARD_DISABLED)
-               set_bit(STATUS_RF_KILL_HW, &priv->shrd->status);
+               set_bit(STATUS_RF_KILL_HW, &priv->status);
        else
-               clear_bit(STATUS_RF_KILL_HW, &priv->shrd->status);
+               clear_bit(STATUS_RF_KILL_HW, &priv->status);
 
 
        if (!(flags & RXON_CARD_DISABLED))
                iwl_scan_cancel(priv);
 
        if ((test_bit(STATUS_RF_KILL_HW, &status) !=
-            test_bit(STATUS_RF_KILL_HW, &priv->shrd->status)))
+            test_bit(STATUS_RF_KILL_HW, &priv->status)))
                wiphy_rfkill_set_hw_state(priv->hw->wiphy,
-                       test_bit(STATUS_RF_KILL_HW, &priv->shrd->status));
+                       test_bit(STATUS_RF_KILL_HW, &priv->status));
        else
                wake_up(&priv->shrd->wait_command_queue);
        return 0;
 }
 
 static int iwlagn_rx_missed_beacon_notif(struct iwl_priv *priv,
-                                      struct iwl_rx_mem_buffer *rxb,
+                                      struct iwl_rx_cmd_buffer *rxb,
                                       struct iwl_device_cmd *cmd)
 
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_missed_beacon_notif *missed_beacon;
+       struct iwl_missed_beacon_notif *missed_beacon = (void *)pkt->data;
 
-       missed_beacon = &pkt->u.missed_beacon;
        if (le32_to_cpu(missed_beacon->consecutive_missed_beacons) >
            priv->missed_beacon_threshold) {
                IWL_DEBUG_CALIB(priv,
@@ -681,7 +691,7 @@ static int iwlagn_rx_missed_beacon_notif(struct iwl_priv *priv,
                    le32_to_cpu(missed_beacon->total_missed_becons),
                    le32_to_cpu(missed_beacon->num_recvd_beacons),
                    le32_to_cpu(missed_beacon->num_expected_beacons));
-               if (!test_bit(STATUS_SCANNING, &priv->shrd->status))
+               if (!test_bit(STATUS_SCANNING, &priv->status))
                        iwl_init_sensitivity(priv);
        }
        return 0;
@@ -690,13 +700,13 @@ static int iwlagn_rx_missed_beacon_notif(struct iwl_priv *priv,
 /* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD).
  * This will be used later in iwl_rx_reply_rx() for REPLY_RX_MPDU_CMD. */
 static int iwlagn_rx_reply_rx_phy(struct iwl_priv *priv,
-                               struct iwl_rx_mem_buffer *rxb,
+                               struct iwl_rx_cmd_buffer *rxb,
                                struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
 
        priv->last_phy_res_valid = true;
-       memcpy(&priv->last_phy_res, pkt->u.raw,
+       memcpy(&priv->last_phy_res, pkt->data,
               sizeof(struct iwl_rx_phy_res));
        return 0;
 }
@@ -757,12 +767,14 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv,
                                        struct ieee80211_hdr *hdr,
                                        u16 len,
                                        u32 ampdu_status,
-                                       struct iwl_rx_mem_buffer *rxb,
+                                       struct iwl_rx_cmd_buffer *rxb,
                                        struct ieee80211_rx_status *stats)
 {
        struct sk_buff *skb;
        __le16 fc = hdr->frame_control;
        struct iwl_rxon_context *ctx;
+       struct page *p;
+       int offset;
 
        /* We only process data packets if the interface is open */
        if (unlikely(!priv->is_open)) {
@@ -782,7 +794,9 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv,
                return;
        }
 
-       skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len);
+       offset = (void *)hdr - rxb_addr(rxb);
+       p = rxb_steal_page(rxb);
+       skb_add_rx_frag(skb, 0, p, offset, len);
 
        iwl_update_stats(priv, false, fc, len);
 
@@ -793,23 +807,18 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv,
        * sometimes even after already having transmitted frames for the
        * association because the new RXON may reset the information.
        */
-       if (unlikely(ieee80211_is_beacon(fc))) {
+       if (unlikely(ieee80211_is_beacon(fc) && priv->passive_no_rx)) {
                for_each_context(priv, ctx) {
-                       if (!ctx->last_tx_rejected)
-                               continue;
                        if (compare_ether_addr(hdr->addr3,
                                               ctx->active.bssid_addr))
                                continue;
-                       ctx->last_tx_rejected = false;
-                       iwl_trans_wake_any_queue(trans(priv), ctx->ctxid,
-                               "channel got active");
+                       iwlagn_lift_passive_no_rx(priv);
                }
        }
 
        memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
 
        ieee80211_rx(priv->hw, skb);
-       rxb->page = NULL;
 }
 
 static u32 iwlagn_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in)
@@ -915,7 +924,7 @@ static int iwlagn_calc_rssi(struct iwl_priv *priv,
 /* Called for REPLY_RX (legacy ABG frames), or
  * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */
 static int iwlagn_rx_reply_rx(struct iwl_priv *priv,
-                           struct iwl_rx_mem_buffer *rxb,
+                           struct iwl_rx_cmd_buffer *rxb,
                            struct iwl_device_cmd *cmd)
 {
        struct ieee80211_hdr *header;
@@ -938,12 +947,12 @@ static int iwlagn_rx_reply_rx(struct iwl_priv *priv,
         * received.
         */
        if (pkt->hdr.cmd == REPLY_RX) {
-               phy_res = (struct iwl_rx_phy_res *)pkt->u.raw;
-               header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*phy_res)
+               phy_res = (struct iwl_rx_phy_res *)pkt->data;
+               header = (struct ieee80211_hdr *)(pkt->data + sizeof(*phy_res)
                                + phy_res->cfg_phy_cnt);
 
                len = le16_to_cpu(phy_res->byte_count);
-               rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*phy_res) +
+               rx_pkt_status = *(__le32 *)(pkt->data + sizeof(*phy_res) +
                                phy_res->cfg_phy_cnt + len);
                ampdu_status = le32_to_cpu(rx_pkt_status);
        } else {
@@ -952,10 +961,10 @@ static int iwlagn_rx_reply_rx(struct iwl_priv *priv,
                        return 0;
                }
                phy_res = &priv->last_phy_res;
-               amsdu = (struct iwl_rx_mpdu_res_start *)pkt->u.raw;
-               header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*amsdu));
+               amsdu = (struct iwl_rx_mpdu_res_start *)pkt->data;
+               header = (struct ieee80211_hdr *)(pkt->data + sizeof(*amsdu));
                len = le16_to_cpu(amsdu->byte_count);
-               rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*amsdu) + len);
+               rx_pkt_status = *(__le32 *)(pkt->data + sizeof(*amsdu) + len);
                ampdu_status = iwlagn_translate_rx_status(priv,
                                                le32_to_cpu(rx_pkt_status));
        }
@@ -1035,12 +1044,12 @@ static int iwlagn_rx_reply_rx(struct iwl_priv *priv,
 }
 
 static int iwlagn_rx_noa_notification(struct iwl_priv *priv,
-                                     struct iwl_rx_mem_buffer *rxb,
+                                     struct iwl_rx_cmd_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;
+       struct iwl_wipan_noa_notification *noa_notif = (void *)pkt->data;
 
        /* no condition -- we're in softirq */
        old_data = rcu_dereference_protected(priv->noa_data, true);
@@ -1086,7 +1095,7 @@ static int iwlagn_rx_noa_notification(struct iwl_priv *priv,
  */
 void iwl_setup_rx_handlers(struct iwl_priv *priv)
 {
-       int (**handlers)(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
+       int (**handlers)(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
                               struct iwl_device_cmd *cmd);
 
        handlers = priv->rx_handlers;
@@ -1131,20 +1140,20 @@ void iwl_setup_rx_handlers(struct iwl_priv *priv)
        priv->rx_handlers[REPLY_TX] = iwlagn_rx_reply_tx;
 
        /* set up notification wait support */
-       spin_lock_init(&priv->shrd->notif_wait_lock);
-       INIT_LIST_HEAD(&priv->shrd->notif_waits);
-       init_waitqueue_head(&priv->shrd->notif_waitq);
+       iwl_notification_wait_init(&priv->notif_wait);
 
        /* Set up BT Rx handlers */
-       if (cfg(priv)->lib->bt_rx_handler_setup)
-               cfg(priv)->lib->bt_rx_handler_setup(priv);
-
+       if (cfg(priv)->bt_params)
+               iwlagn_bt_rx_handler_setup(priv);
 }
 
-int iwl_rx_dispatch(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
-                    struct iwl_device_cmd *cmd)
+int iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb,
+                   struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+       void (*pre_rx_handler)(struct iwl_priv *,
+                              struct iwl_rx_cmd_buffer *);
        int err = 0;
 
        /*
@@ -1152,30 +1161,22 @@ int iwl_rx_dispatch(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
         * even if the RX handler consumes the RXB we have
         * access to it in the notification wait entry.
         */
-       if (!list_empty(&priv->shrd->notif_waits)) {
-               struct iwl_notification_wait *w;
-
-               spin_lock(&priv->shrd->notif_wait_lock);
-               list_for_each_entry(w, &priv->shrd->notif_waits, list) {
-                       if (w->cmd != pkt->hdr.cmd)
-                               continue;
-                       IWL_DEBUG_RX(priv,
-                               "Notif: %s, 0x%02x - wake the callers up\n",
-                               get_cmd_string(pkt->hdr.cmd),
-                               pkt->hdr.cmd);
-                       w->triggered = true;
-                       if (w->fn)
-                               w->fn(trans(priv), pkt, w->fn_data);
-               }
-               spin_unlock(&priv->shrd->notif_wait_lock);
-
-               wake_up_all(&priv->shrd->notif_waitq);
-       }
-
-       if (priv->pre_rx_handler &&
-           priv->shrd->ucode_owner == IWL_OWNERSHIP_TM)
-               priv->pre_rx_handler(priv, rxb);
-       else {
+       iwl_notification_wait_notify(&priv->notif_wait, pkt);
+
+       /* RX data may be forwarded to userspace (using pre_rx_handler) in one
+        * of two cases: the first, that the user owns the uCode through
+        * testmode - in such case the pre_rx_handler is set and no further
+        * processing takes place. The other case is when the user want to
+        * monitor the rx w/o affecting the regular flow - the pre_rx_handler
+        * will be set but the ownership flag != IWL_OWNERSHIP_TM and the flow
+        * continues.
+        * We need to use ACCESS_ONCE to prevent a case where the handler
+        * changes between the check and the call.
+        */
+       pre_rx_handler = ACCESS_ONCE(priv->pre_rx_handler);
+       if (pre_rx_handler)
+               pre_rx_handler(priv, rxb);
+       if (priv->ucode_owner != IWL_OWNERSHIP_TM) {
                /* Based on type of command response or notification,
                 *   handle those that need handling via function in
                 *   rx_handlers table.  See iwl_setup_rx_handlers() */
index 8ca9570ec36539b7753e79783d452db6dd8fdec4..36909077f994917c72bbc80cad3ef5a5e613aaf3 100644 (file)
@@ -39,7 +39,7 @@ static int iwlagn_disable_bss(struct iwl_priv *priv,
        int ret;
 
        send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-       ret = iwl_trans_send_cmd_pdu(trans(priv), ctx->rxon_cmd,
+       ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_cmd,
                                CMD_SYNC, sizeof(*send), send);
 
        send->filter_flags = old_filter;
@@ -60,13 +60,13 @@ static int iwlagn_disable_pan(struct iwl_priv *priv,
        u8 old_dev_type = send->dev_type;
        int ret;
 
-       iwl_init_notification_wait(priv->shrd, &disable_wait,
-                                     REPLY_WIPAN_DEACTIVATION_COMPLETE,
-                                     NULL, NULL);
+       iwl_init_notification_wait(&priv->notif_wait, &disable_wait,
+                                  REPLY_WIPAN_DEACTIVATION_COMPLETE,
+                                  NULL, NULL);
 
        send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
        send->dev_type = RXON_DEV_TYPE_P2P;
-       ret = iwl_trans_send_cmd_pdu(trans(priv), ctx->rxon_cmd,
+       ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_cmd,
                                CMD_SYNC, sizeof(*send), send);
 
        send->filter_flags = old_filter;
@@ -74,9 +74,10 @@ static int iwlagn_disable_pan(struct iwl_priv *priv,
 
        if (ret) {
                IWL_ERR(priv, "Error disabling PAN (%d)\n", ret);
-               iwl_remove_notification(priv->shrd, &disable_wait);
+               iwl_remove_notification(&priv->notif_wait, &disable_wait);
        } else {
-               ret = iwl_wait_notification(priv->shrd, &disable_wait, HZ);
+               ret = iwl_wait_notification(&priv->notif_wait,
+                                           &disable_wait, HZ);
                if (ret)
                        IWL_ERR(priv, "Timed out waiting for PAN disable\n");
        }
@@ -92,7 +93,7 @@ static int iwlagn_disconn_pan(struct iwl_priv *priv,
        int ret;
 
        send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-       ret = iwl_trans_send_cmd_pdu(trans(priv), ctx->rxon_cmd, CMD_SYNC,
+       ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_cmd, CMD_SYNC,
                                sizeof(*send), send);
 
        send->filter_flags = old_filter;
@@ -121,7 +122,7 @@ static void iwlagn_update_qos(struct iwl_priv *priv,
                      ctx->qos_data.qos_active,
                      ctx->qos_data.def_qos_parm.qos_flags);
 
-       ret = iwl_trans_send_cmd_pdu(trans(priv), ctx->qos_cmd, CMD_SYNC,
+       ret = iwl_dvm_send_cmd_pdu(priv, ctx->qos_cmd, CMD_SYNC,
                               sizeof(struct iwl_qosparam_cmd),
                               &ctx->qos_data.def_qos_parm);
        if (ret)
@@ -131,7 +132,7 @@ static void iwlagn_update_qos(struct iwl_priv *priv,
 static int iwlagn_update_beacon(struct iwl_priv *priv,
                                struct ieee80211_vif *vif)
 {
-       lockdep_assert_held(&priv->shrd->mutex);
+       lockdep_assert_held(&priv->mutex);
 
        dev_kfree_skb(priv->beacon_skb);
        priv->beacon_skb = ieee80211_beacon_get(priv->hw, vif);
@@ -180,7 +181,7 @@ static int iwlagn_send_rxon_assoc(struct iwl_priv *priv,
                 ctx->staging.ofdm_ht_triple_stream_basic_rates;
        rxon_assoc.acquisition_data = ctx->staging.acquisition_data;
 
-       ret = iwl_trans_send_cmd_pdu(trans(priv), ctx->rxon_assoc_cmd,
+       ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_assoc_cmd,
                                CMD_ASYNC, sizeof(rxon_assoc), &rxon_assoc);
        return ret;
 }
@@ -266,7 +267,7 @@ static int iwlagn_rxon_connect(struct iwl_priv *priv,
         * Associated RXON doesn't clear the station table in uCode,
         * so we don't need to restore stations etc. after this.
         */
-       ret = iwl_trans_send_cmd_pdu(trans(priv), ctx->rxon_cmd, CMD_SYNC,
+       ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_cmd, CMD_SYNC,
                      sizeof(struct iwl_rxon_cmd), &ctx->staging);
        if (ret) {
                IWL_ERR(priv, "Error setting new RXON (%d)\n", ret);
@@ -274,8 +275,6 @@ static int iwlagn_rxon_connect(struct iwl_priv *priv,
        }
        memcpy(active, &ctx->staging, sizeof(*active));
 
-       iwl_reprogram_ap_sta(priv, ctx);
-
        /* IBSS beacon needs to be sent after setting assoc */
        if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_ADHOC))
                if (iwlagn_update_beacon(priv, ctx->vif))
@@ -315,7 +314,7 @@ int iwlagn_set_pan_params(struct iwl_priv *priv)
 
        BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
 
-       lockdep_assert_held(&priv->shrd->mutex);
+       lockdep_assert_held(&priv->mutex);
 
        ctx_bss = &priv->contexts[IWL_RXON_CTX_BSS];
        ctx_pan = &priv->contexts[IWL_RXON_CTX_PAN];
@@ -362,7 +361,7 @@ int iwlagn_set_pan_params(struct iwl_priv *priv)
                slot0 = bcnint / 2;
                slot1 = bcnint - slot0;
 
-               if (test_bit(STATUS_SCAN_HW, &priv->shrd->status) ||
+               if (test_bit(STATUS_SCAN_HW, &priv->status) ||
                    (!ctx_bss->vif->bss_conf.idle &&
                     !ctx_bss->vif->bss_conf.assoc)) {
                        slot0 = dtim * bcnint * 3 - IWL_MIN_SLOT_TIME;
@@ -378,7 +377,7 @@ int iwlagn_set_pan_params(struct iwl_priv *priv)
                                        ctx_pan->beacon_int;
                slot1 = max_t(int, DEFAULT_BEACON_INTERVAL, slot1);
 
-               if (test_bit(STATUS_SCAN_HW, &priv->shrd->status)) {
+               if (test_bit(STATUS_SCAN_HW, &priv->status)) {
                        slot0 = slot1 * 3 - IWL_MIN_SLOT_TIME;
                        slot1 = IWL_MIN_SLOT_TIME;
                }
@@ -387,7 +386,7 @@ int iwlagn_set_pan_params(struct iwl_priv *priv)
        cmd.slots[0].width = cpu_to_le16(slot0);
        cmd.slots[1].width = cpu_to_le16(slot1);
 
-       ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_WIPAN_PARAMS, CMD_SYNC,
+       ret = iwl_dvm_send_cmd_pdu(priv, REPLY_WIPAN_PARAMS, CMD_SYNC,
                        sizeof(cmd), &cmd);
        if (ret)
                IWL_ERR(priv, "Error setting PAN parameters (%d)\n", ret);
@@ -420,12 +419,9 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
        bool new_assoc = !!(ctx->staging.filter_flags & RXON_FILTER_ASSOC_MSK);
        int ret;
 
-       lockdep_assert_held(&priv->shrd->mutex);
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
-               return -EINVAL;
+       lockdep_assert_held(&priv->mutex);
 
-       if (!iwl_is_alive(priv->shrd))
+       if (!iwl_is_alive(priv))
                return -EBUSY;
 
        /* This function hardcodes a bunch of dual-mode assumptions */
@@ -434,10 +430,6 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
        if (!ctx->is_active)
                return 0;
 
-       /* override BSSID if necessary due to preauth */
-       if (ctx->preauth_bssid)
-               memcpy(ctx->staging.bssid_addr, ctx->bssid, ETH_ALEN);
-
        /* always get timestamp with Rx frame */
        ctx->staging.flags |= RXON_FLG_TSF2HOST_MSK;
 
@@ -445,8 +437,7 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
         * force CTS-to-self frames protection if RTS-CTS is not preferred
         * one aggregation protection method
         */
-       if (!(cfg(priv)->ht_params &&
-             cfg(priv)->ht_params->use_rts_for_aggregation))
+       if (!hw_params(priv).use_rts_for_aggregation)
                ctx->staging.flags |= RXON_FLG_SELF_CTS_EN;
 
        if ((ctx->vif && ctx->vif->bss_conf.use_short_slot) ||
@@ -466,7 +457,7 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
         * receive commit_rxon request
         * abort any previous channel switch if still in process
         */
-       if (test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status) &&
+       if (test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status) &&
            (priv->switch_channel != ctx->staging.channel)) {
                IWL_DEBUG_11H(priv, "abort channel switch on %d\n",
                              le16_to_cpu(priv->switch_channel));
@@ -549,7 +540,7 @@ void iwlagn_config_ht40(struct ieee80211_conf *conf,
 
 int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
 {
-       struct iwl_priv *priv = hw->priv;
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
        struct iwl_rxon_context *ctx;
        struct ieee80211_conf *conf = &hw->conf;
        struct ieee80211_channel *channel = conf->channel;
@@ -558,17 +549,14 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
 
        IWL_DEBUG_MAC80211(priv, "enter: changed %#x", changed);
 
-       mutex_lock(&priv->shrd->mutex);
+       mutex_lock(&priv->mutex);
 
-       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
-               goto out;
-
-       if (unlikely(test_bit(STATUS_SCANNING, &priv->shrd->status))) {
+       if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) {
                IWL_DEBUG_MAC80211(priv, "leave - scanning\n");
                goto out;
        }
 
-       if (!iwl_is_ready(priv->shrd)) {
+       if (!iwl_is_ready(priv)) {
                IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
                goto out;
        }
@@ -590,8 +578,6 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
        }
 
        if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
-               unsigned long flags;
-
                ch_info = iwl_get_channel_info(priv, channel->band,
                                               channel->hw_value);
                if (!is_channel_valid(ch_info)) {
@@ -600,8 +586,6 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
                        goto out;
                }
 
-               spin_lock_irqsave(&priv->shrd->lock, flags);
-
                for_each_context(priv, ctx) {
                        /* Configure HT40 channels */
                        if (ctx->ht.enabled != conf_is_ht(conf))
@@ -636,8 +620,6 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
                                               ctx->vif);
                }
 
-               spin_unlock_irqrestore(&priv->shrd->lock, flags);
-
                iwl_update_bcast_stations(priv);
 
                /*
@@ -668,7 +650,7 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
                iwlagn_commit_rxon(priv, ctx);
        }
  out:
-       mutex_unlock(&priv->shrd->mutex);
+       mutex_unlock(&priv->mutex);
        IWL_DEBUG_MAC80211(priv, "leave\n");
 
        return ret;
@@ -685,7 +667,7 @@ static void iwlagn_check_needed_chains(struct iwl_priv *priv,
        struct ieee80211_sta_ht_cap *ht_cap;
        bool need_multiple;
 
-       lockdep_assert_held(&priv->shrd->mutex);
+       lockdep_assert_held(&priv->mutex);
 
        switch (vif->type) {
        case NL80211_IFTYPE_STATION:
@@ -789,7 +771,7 @@ static void iwlagn_chain_noise_reset(struct iwl_priv *priv)
                memset(&cmd, 0, sizeof(cmd));
                iwl_set_calib_hdr(&cmd.hdr,
                        priv->phy_calib_chain_noise_reset_cmd);
-               ret = iwl_trans_send_cmd_pdu(trans(priv),
+               ret = iwl_dvm_send_cmd_pdu(priv,
                                        REPLY_PHY_CALIBRATION_CMD,
                                        CMD_SYNC, sizeof(cmd), &cmd);
                if (ret)
@@ -805,22 +787,22 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
                             struct ieee80211_bss_conf *bss_conf,
                             u32 changes)
 {
-       struct iwl_priv *priv = hw->priv;
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
        struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
        int ret;
        bool force = false;
 
-       mutex_lock(&priv->shrd->mutex);
+       mutex_lock(&priv->mutex);
 
-       if (unlikely(!iwl_is_ready(priv->shrd))) {
+       if (unlikely(!iwl_is_ready(priv))) {
                IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
-               mutex_unlock(&priv->shrd->mutex);
+               mutex_unlock(&priv->mutex);
                return;
         }
 
        if (unlikely(!ctx->vif)) {
                IWL_DEBUG_MAC80211(priv, "leave - vif is NULL\n");
-               mutex_unlock(&priv->shrd->mutex);
+               mutex_unlock(&priv->mutex);
                return;
        }
 
@@ -851,12 +833,8 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
                         * not get stuck in this case either since it
                         * can happen if userspace gets confused.
                         */
-                       if (ctx->last_tx_rejected) {
-                               ctx->last_tx_rejected = false;
-                               iwl_trans_wake_any_queue(trans(priv),
-                                                        ctx->ctxid,
-                                                        "Disassoc: flush queue");
-                       }
+                       iwlagn_lift_passive_no_rx(priv);
+
                        ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 
                        if (ctx->ctxid == IWL_RXON_CTX_BSS)
@@ -900,6 +878,22 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
                }
        }
 
+       /*
+        * If the ucode decides to do beacon filtering before
+        * association, it will lose beacons that are needed
+        * before sending frames out on passive channels. This
+        * causes association failures on those channels. Enable
+        * receiving beacons in such cases.
+        */
+
+       if (vif->type == NL80211_IFTYPE_STATION) {
+               if (!bss_conf->assoc)
+                       ctx->staging.filter_flags |= RXON_FILTER_BCON_AWARE_MSK;
+               else
+                       ctx->staging.filter_flags &=
+                                                   ~RXON_FILTER_BCON_AWARE_MSK;
+       }
+
        if (force || memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging)))
                iwlagn_commit_rxon(priv, ctx);
 
@@ -916,7 +910,6 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
                if (!priv->disable_chain_noise_cal)
                        iwlagn_chain_noise_reset(priv);
                priv->start_calib = 1;
-               WARN_ON(ctx->preauth_bssid);
        }
 
        if (changes & BSS_CHANGED_IBSS) {
@@ -934,7 +927,7 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
                        IWL_ERR(priv, "Error sending IBSS beacon\n");
        }
 
-       mutex_unlock(&priv->shrd->mutex);
+       mutex_unlock(&priv->mutex);
 }
 
 void iwlagn_post_scan(struct iwl_priv *priv)
index f1298cd6a19a9dfb817e1a5fb1b9c120db715d36..c4175603864b24f195cd0aa9dda554783a67a80f 100644 (file)
@@ -26,7 +26,7 @@
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
-
+#include <linux/etherdevice.h>
 #include <net/mac80211.h>
 
 #include "iwl-dev.h"
 #include "iwl-agn.h"
 #include "iwl-trans.h"
 
-/* priv->shrd->sta_lock must be held */
 static int iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
 {
+       lockdep_assert_held(&priv->sta_lock);
+
        if (sta_id >= IWLAGN_STATION_COUNT) {
                IWL_ERR(priv, "invalid sta_id %u", sta_id);
                return -EINVAL;
@@ -63,8 +64,8 @@ static int iwl_process_add_sta_resp(struct iwl_priv *priv,
                                    struct iwl_addsta_cmd *addsta,
                                    struct iwl_rx_packet *pkt)
 {
+       struct iwl_add_sta_resp *add_sta_resp = (void *)pkt->data;
        u8 sta_id = addsta->sta.sta_id;
-       unsigned long flags;
        int ret = -EIO;
 
        if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
@@ -76,9 +77,9 @@ static int iwl_process_add_sta_resp(struct iwl_priv *priv,
        IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n",
                       sta_id);
 
-       spin_lock_irqsave(&priv->shrd->sta_lock, flags);
+       spin_lock(&priv->sta_lock);
 
-       switch (pkt->u.add_sta.status) {
+       switch (add_sta_resp->status) {
        case ADD_STA_SUCCESS_MSK:
                IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n");
                ret = iwl_sta_ucode_activate(priv, sta_id);
@@ -97,7 +98,7 @@ static int iwl_process_add_sta_resp(struct iwl_priv *priv,
                break;
        default:
                IWL_DEBUG_ASSOC(priv, "Received REPLY_ADD_STA:(0x%08X)\n",
-                               pkt->u.add_sta.status);
+                               add_sta_resp->status);
                break;
        }
 
@@ -118,12 +119,12 @@ static int iwl_process_add_sta_resp(struct iwl_priv *priv,
                       priv->stations[sta_id].sta.mode ==
                       STA_CONTROL_MODIFY_MSK ? "Modified" : "Added",
                       addsta->sta.addr);
-       spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
+       spin_unlock(&priv->sta_lock);
 
        return ret;
 }
 
-int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
+int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
                               struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
@@ -153,14 +154,14 @@ int iwl_send_add_sta(struct iwl_priv *priv,
                might_sleep();
        }
 
-       ret = iwl_trans_send_cmd(trans(priv), &cmd);
+       ret = iwl_dvm_send_cmd(priv, &cmd);
 
        if (ret || (flags & CMD_ASYNC))
                return ret;
        /*else the command was successfully sent in SYNC mode, need to free
         * the reply page */
 
-       iwl_free_pages(priv->shrd, cmd.reply_page);
+       iwl_free_resp(&cmd);
 
        if (cmd.handler_status)
                IWL_ERR(priv, "%s - error in the CMD response %d", __func__,
@@ -169,34 +170,38 @@ int iwl_send_add_sta(struct iwl_priv *priv,
        return cmd.handler_status;
 }
 
-static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
-                                  struct ieee80211_sta *sta,
-                                  struct iwl_rxon_context *ctx)
+static void iwl_sta_calc_ht_flags(struct iwl_priv *priv,
+                                 struct ieee80211_sta *sta,
+                                 struct iwl_rxon_context *ctx,
+                                 __le32 *flags, __le32 *mask)
 {
        struct ieee80211_sta_ht_cap *sta_ht_inf = &sta->ht_cap;
-       __le32 sta_flags;
        u8 mimo_ps_mode;
 
+       *mask = STA_FLG_RTS_MIMO_PROT_MSK |
+               STA_FLG_MIMO_DIS_MSK |
+               STA_FLG_HT40_EN_MSK |
+               STA_FLG_MAX_AGG_SIZE_MSK |
+               STA_FLG_AGG_MPDU_DENSITY_MSK;
+       *flags = 0;
+
        if (!sta || !sta_ht_inf->ht_supported)
-               goto done;
+               return;
 
        mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2;
-       IWL_DEBUG_ASSOC(priv, "spatial multiplexing power save mode: %s\n",
+
+       IWL_DEBUG_INFO(priv, "STA %pM SM PS mode: %s\n",
                        (mimo_ps_mode == WLAN_HT_CAP_SM_PS_STATIC) ?
                        "static" :
                        (mimo_ps_mode == WLAN_HT_CAP_SM_PS_DYNAMIC) ?
                        "dynamic" : "disabled");
 
-       sta_flags = priv->stations[index].sta.station_flags;
-
-       sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK);
-
        switch (mimo_ps_mode) {
        case WLAN_HT_CAP_SM_PS_STATIC:
-               sta_flags |= STA_FLG_MIMO_DIS_MSK;
+               *flags |= STA_FLG_MIMO_DIS_MSK;
                break;
        case WLAN_HT_CAP_SM_PS_DYNAMIC:
-               sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK;
+               *flags |= STA_FLG_RTS_MIMO_PROT_MSK;
                break;
        case WLAN_HT_CAP_SM_PS_DISABLED:
                break;
@@ -205,20 +210,53 @@ static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
                break;
        }
 
-       sta_flags |= cpu_to_le32(
-             (u32)sta_ht_inf->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS);
+       *flags |= cpu_to_le32(
+               (u32)sta_ht_inf->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS);
 
-       sta_flags |= cpu_to_le32(
-             (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS);
+       *flags |= cpu_to_le32(
+               (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS);
 
        if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
-               sta_flags |= STA_FLG_HT40_EN_MSK;
-       else
-               sta_flags &= ~STA_FLG_HT40_EN_MSK;
+               *flags |= STA_FLG_HT40_EN_MSK;
+}
 
-       priv->stations[index].sta.station_flags = sta_flags;
- done:
-       return;
+int iwl_sta_update_ht(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                     struct ieee80211_sta *sta)
+{
+       u8 sta_id = iwl_sta_id(sta);
+       __le32 flags, mask;
+       struct iwl_addsta_cmd cmd;
+
+       if (WARN_ON_ONCE(sta_id == IWL_INVALID_STATION))
+               return -EINVAL;
+
+       iwl_sta_calc_ht_flags(priv, sta, ctx, &flags, &mask);
+
+       spin_lock_bh(&priv->sta_lock);
+       priv->stations[sta_id].sta.station_flags &= ~mask;
+       priv->stations[sta_id].sta.station_flags |= flags;
+       spin_unlock_bh(&priv->sta_lock);
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.mode = STA_CONTROL_MODIFY_MSK;
+       cmd.station_flags_msk = mask;
+       cmd.station_flags = flags;
+       cmd.sta.sta_id = sta_id;
+
+       return iwl_send_add_sta(priv, &cmd, CMD_SYNC);
+}
+
+static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
+                                  struct ieee80211_sta *sta,
+                                  struct iwl_rxon_context *ctx)
+{
+       __le32 flags, mask;
+
+       iwl_sta_calc_ht_flags(priv, sta, ctx, &flags, &mask);
+
+       lockdep_assert_held(&priv->sta_lock);
+       priv->stations[index].sta.station_flags &= ~mask;
+       priv->stations[index].sta.station_flags |= flags;
 }
 
 /**
@@ -317,18 +355,17 @@ int iwl_add_station_common(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
                           const u8 *addr, bool is_ap,
                           struct ieee80211_sta *sta, u8 *sta_id_r)
 {
-       unsigned long flags_spin;
        int ret = 0;
        u8 sta_id;
        struct iwl_addsta_cmd sta_cmd;
 
        *sta_id_r = 0;
-       spin_lock_irqsave(&priv->shrd->sta_lock, flags_spin);
+       spin_lock_bh(&priv->sta_lock);
        sta_id = iwl_prep_station(priv, ctx, addr, is_ap, sta);
        if (sta_id == IWL_INVALID_STATION) {
                IWL_ERR(priv, "Unable to prepare station %pM for addition\n",
                        addr);
-               spin_unlock_irqrestore(&priv->shrd->sta_lock, flags_spin);
+               spin_unlock_bh(&priv->sta_lock);
                return -EINVAL;
        }
 
@@ -340,7 +377,7 @@ int iwl_add_station_common(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
        if (priv->stations[sta_id].used & IWL_STA_UCODE_INPROGRESS) {
                IWL_DEBUG_INFO(priv, "STA %d already in process of being "
                               "added.\n", sta_id);
-               spin_unlock_irqrestore(&priv->shrd->sta_lock, flags_spin);
+               spin_unlock_bh(&priv->sta_lock);
                return -EEXIST;
        }
 
@@ -348,24 +385,24 @@ int iwl_add_station_common(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
            (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) {
                IWL_DEBUG_ASSOC(priv, "STA %d (%pM) already added, not "
                                "adding again.\n", sta_id, addr);
-               spin_unlock_irqrestore(&priv->shrd->sta_lock, flags_spin);
+               spin_unlock_bh(&priv->sta_lock);
                return -EEXIST;
        }
 
        priv->stations[sta_id].used |= IWL_STA_UCODE_INPROGRESS;
        memcpy(&sta_cmd, &priv->stations[sta_id].sta,
               sizeof(struct iwl_addsta_cmd));
-       spin_unlock_irqrestore(&priv->shrd->sta_lock, flags_spin);
+       spin_unlock_bh(&priv->sta_lock);
 
        /* Add station to device's station table */
        ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
        if (ret) {
-               spin_lock_irqsave(&priv->shrd->sta_lock, flags_spin);
+               spin_lock_bh(&priv->sta_lock);
                IWL_ERR(priv, "Adding station %pM failed.\n",
                        priv->stations[sta_id].sta.sta.addr);
                priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
                priv->stations[sta_id].used &= ~IWL_STA_UCODE_INPROGRESS;
-               spin_unlock_irqrestore(&priv->shrd->sta_lock, flags_spin);
+               spin_unlock_bh(&priv->sta_lock);
        }
        *sta_id_r = sta_id;
        return ret;
@@ -373,11 +410,11 @@ int iwl_add_station_common(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
 
 /**
  * iwl_sta_ucode_deactivate - deactivate ucode status for a station
- *
- * priv->shrd->sta_lock must be held
  */
 static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, u8 sta_id)
 {
+       lockdep_assert_held(&priv->sta_lock);
+
        /* Ucode must be active and driver must be non active */
        if ((priv->stations[sta_id].used &
             (IWL_STA_UCODE_ACTIVE | IWL_STA_DRIVER_ACTIVE)) !=
@@ -396,8 +433,6 @@ static int iwl_send_remove_station(struct iwl_priv *priv,
 {
        struct iwl_rx_packet *pkt;
        int ret;
-
-       unsigned long flags_spin;
        struct iwl_rem_sta_cmd rm_sta_cmd;
 
        struct iwl_host_cmd cmd = {
@@ -413,12 +448,12 @@ static int iwl_send_remove_station(struct iwl_priv *priv,
 
        cmd.flags |= CMD_WANT_SKB;
 
-       ret = iwl_trans_send_cmd(trans(priv), &cmd);
+       ret = iwl_dvm_send_cmd(priv, &cmd);
 
        if (ret)
                return ret;
 
-       pkt = (struct iwl_rx_packet *)cmd.reply_page;
+       pkt = cmd.resp_pkt;
        if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
                IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n",
                          pkt->hdr.flags);
@@ -426,14 +461,13 @@ static int iwl_send_remove_station(struct iwl_priv *priv,
        }
 
        if (!ret) {
-               switch (pkt->u.rem_sta.status) {
+               struct iwl_rem_sta_resp *rem_sta_resp = (void *)pkt->data;
+               switch (rem_sta_resp->status) {
                case REM_STA_SUCCESS_MSK:
                        if (!temporary) {
-                               spin_lock_irqsave(&priv->shrd->sta_lock,
-                                       flags_spin);
+                               spin_lock_bh(&priv->sta_lock);
                                iwl_sta_ucode_deactivate(priv, sta_id);
-                               spin_unlock_irqrestore(&priv->shrd->sta_lock,
-                                       flags_spin);
+                               spin_unlock_bh(&priv->sta_lock);
                        }
                        IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n");
                        break;
@@ -443,7 +477,7 @@ static int iwl_send_remove_station(struct iwl_priv *priv,
                        break;
                }
        }
-       iwl_free_pages(priv->shrd, cmd.reply_page);
+       iwl_free_resp(&cmd);
 
        return ret;
 }
@@ -454,10 +488,9 @@ static int iwl_send_remove_station(struct iwl_priv *priv,
 int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
                       const u8 *addr)
 {
-       unsigned long flags;
        u8 tid;
 
-       if (!iwl_is_ready(priv->shrd)) {
+       if (!iwl_is_ready(priv)) {
                IWL_DEBUG_INFO(priv,
                        "Unable to remove station %pM, device not ready.\n",
                        addr);
@@ -475,7 +508,7 @@ int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
        if (WARN_ON(sta_id == IWL_INVALID_STATION))
                return -EINVAL;
 
-       spin_lock_irqsave(&priv->shrd->sta_lock, flags);
+       spin_lock_bh(&priv->sta_lock);
 
        if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) {
                IWL_DEBUG_INFO(priv, "Removing %pM but non DRIVER active\n",
@@ -505,14 +538,49 @@ int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
        if (WARN_ON(priv->num_stations < 0))
                priv->num_stations = 0;
 
-       spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
+       spin_unlock_bh(&priv->sta_lock);
 
        return iwl_send_remove_station(priv, addr, sta_id, false);
 out_err:
-       spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
+       spin_unlock_bh(&priv->sta_lock);
        return -EINVAL;
 }
 
+void iwl_deactivate_station(struct iwl_priv *priv, const u8 sta_id,
+                           const u8 *addr)
+{
+       u8 tid;
+
+       if (!iwl_is_ready(priv)) {
+               IWL_DEBUG_INFO(priv,
+                       "Unable to remove station %pM, device not ready.\n",
+                       addr);
+               return;
+       }
+
+       IWL_DEBUG_ASSOC(priv, "Deactivating STA: %pM (%d)\n", addr, sta_id);
+
+       if (WARN_ON_ONCE(sta_id == IWL_INVALID_STATION))
+               return;
+
+       spin_lock_bh(&priv->sta_lock);
+
+       WARN_ON_ONCE(!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE));
+
+       for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++)
+               memset(&priv->tid_data[sta_id][tid], 0,
+                       sizeof(priv->tid_data[sta_id][tid]));
+
+       priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
+
+       priv->num_stations--;
+
+       if (WARN_ON_ONCE(priv->num_stations < 0))
+               priv->num_stations = 0;
+
+       spin_unlock_bh(&priv->sta_lock);
+}
+
 /**
  * iwl_clear_ucode_stations - clear ucode station table bits
  *
@@ -525,12 +593,11 @@ void iwl_clear_ucode_stations(struct iwl_priv *priv,
                              struct iwl_rxon_context *ctx)
 {
        int i;
-       unsigned long flags_spin;
        bool cleared = false;
 
        IWL_DEBUG_INFO(priv, "Clearing ucode stations in driver\n");
 
-       spin_lock_irqsave(&priv->shrd->sta_lock, flags_spin);
+       spin_lock_bh(&priv->sta_lock);
        for (i = 0; i < IWLAGN_STATION_COUNT; i++) {
                if (ctx && ctx->ctxid != priv->stations[i].ctxid)
                        continue;
@@ -542,7 +609,7 @@ void iwl_clear_ucode_stations(struct iwl_priv *priv,
                        cleared = true;
                }
        }
-       spin_unlock_irqrestore(&priv->shrd->sta_lock, flags_spin);
+       spin_unlock_bh(&priv->sta_lock);
 
        if (!cleared)
                IWL_DEBUG_INFO(priv,
@@ -561,20 +628,19 @@ void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
 {
        struct iwl_addsta_cmd sta_cmd;
        struct iwl_link_quality_cmd lq;
-       unsigned long flags_spin;
        int i;
        bool found = false;
        int ret;
        bool send_lq;
 
-       if (!iwl_is_ready(priv->shrd)) {
+       if (!iwl_is_ready(priv)) {
                IWL_DEBUG_INFO(priv,
                               "Not ready yet, not restoring any stations.\n");
                return;
        }
 
        IWL_DEBUG_ASSOC(priv, "Restoring all known stations ... start.\n");
-       spin_lock_irqsave(&priv->shrd->sta_lock, flags_spin);
+       spin_lock_bh(&priv->sta_lock);
        for (i = 0; i < IWLAGN_STATION_COUNT; i++) {
                if (ctx->ctxid != priv->stations[i].ctxid)
                        continue;
@@ -594,27 +660,24 @@ void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
                               sizeof(struct iwl_addsta_cmd));
                        send_lq = false;
                        if (priv->stations[i].lq) {
-                               if (priv->shrd->wowlan)
+                               if (priv->wowlan)
                                        iwl_sta_fill_lq(priv, ctx, i, &lq);
                                else
                                        memcpy(&lq, priv->stations[i].lq,
                                               sizeof(struct iwl_link_quality_cmd));
                                send_lq = true;
                        }
-                       spin_unlock_irqrestore(&priv->shrd->sta_lock,
-                                              flags_spin);
+                       spin_unlock_bh(&priv->sta_lock);
                        ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
                        if (ret) {
-                               spin_lock_irqsave(&priv->shrd->sta_lock,
-                                                 flags_spin);
+                               spin_lock_bh(&priv->sta_lock);
                                IWL_ERR(priv, "Adding station %pM failed.\n",
                                        priv->stations[i].sta.sta.addr);
                                priv->stations[i].used &=
                                                ~IWL_STA_DRIVER_ACTIVE;
                                priv->stations[i].used &=
                                                ~IWL_STA_UCODE_INPROGRESS;
-                               spin_unlock_irqrestore(&priv->shrd->sta_lock,
-                                                      flags_spin);
+                               spin_unlock_bh(&priv->sta_lock);
                        }
                        /*
                         * Rate scaling has already been initialized, send
@@ -623,12 +686,12 @@ void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
                        if (send_lq)
                                iwl_send_lq_cmd(priv, ctx, &lq,
                                                CMD_SYNC, true);
-                       spin_lock_irqsave(&priv->shrd->sta_lock, flags_spin);
+                       spin_lock_bh(&priv->sta_lock);
                        priv->stations[i].used &= ~IWL_STA_UCODE_INPROGRESS;
                }
        }
 
-       spin_unlock_irqrestore(&priv->shrd->sta_lock, flags_spin);
+       spin_unlock_bh(&priv->sta_lock);
        if (!found)
                IWL_DEBUG_INFO(priv, "Restoring all known stations .... "
                        "no stations to be restored.\n");
@@ -637,52 +700,6 @@ void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
                        "complete.\n");
 }
 
-void iwl_reprogram_ap_sta(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
-{
-       unsigned long flags;
-       int sta_id = ctx->ap_sta_id;
-       int ret;
-       struct iwl_addsta_cmd sta_cmd;
-       struct iwl_link_quality_cmd lq;
-       bool active, have_lq = false;
-
-       spin_lock_irqsave(&priv->shrd->sta_lock, flags);
-       if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) {
-               spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
-               return;
-       }
-
-       memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(sta_cmd));
-       sta_cmd.mode = 0;
-       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;
-       spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
-
-       if (active) {
-               ret = iwl_send_remove_station(
-                       priv, priv->stations[sta_id].sta.sta.addr,
-                       sta_id, true);
-               if (ret)
-                       IWL_ERR(priv, "failed to remove STA %pM (%d)\n",
-                               priv->stations[sta_id].sta.sta.addr, ret);
-       }
-       spin_lock_irqsave(&priv->shrd->sta_lock, flags);
-       priv->stations[sta_id].used |= IWL_STA_DRIVER_ACTIVE;
-       spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
-
-       ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
-       if (ret)
-               IWL_ERR(priv, "failed to re-add STA %pM (%d)\n",
-                       priv->stations[sta_id].sta.sta.addr, ret);
-       if (have_lq)
-               iwl_send_lq_cmd(priv, ctx, &lq, CMD_SYNC, true);
-}
-
 int iwl_get_free_ucode_key_offset(struct iwl_priv *priv)
 {
        int i;
@@ -696,10 +713,9 @@ int iwl_get_free_ucode_key_offset(struct iwl_priv *priv)
 
 void iwl_dealloc_bcast_stations(struct iwl_priv *priv)
 {
-       unsigned long flags;
        int i;
 
-       spin_lock_irqsave(&priv->shrd->sta_lock, flags);
+       spin_lock_bh(&priv->sta_lock);
        for (i = 0; i < IWLAGN_STATION_COUNT; i++) {
                if (!(priv->stations[i].used & IWL_STA_BCAST))
                        continue;
@@ -711,7 +727,7 @@ void iwl_dealloc_bcast_stations(struct iwl_priv *priv)
                kfree(priv->stations[i].lq);
                priv->stations[i].lq = NULL;
        }
-       spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
+       spin_unlock_bh(&priv->sta_lock);
 }
 
 #ifdef CONFIG_IWLWIFI_DEBUG
@@ -783,8 +799,6 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
                    struct iwl_link_quality_cmd *lq, u8 flags, bool init)
 {
        int ret = 0;
-       unsigned long flags_spin;
-
        struct iwl_host_cmd cmd = {
                .id = REPLY_TX_LINK_QUALITY_CMD,
                .len = { sizeof(struct iwl_link_quality_cmd), },
@@ -796,19 +810,19 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
                return -EINVAL;
 
 
-       spin_lock_irqsave(&priv->shrd->sta_lock, flags_spin);
+       spin_lock_bh(&priv->sta_lock);
        if (!(priv->stations[lq->sta_id].used & IWL_STA_DRIVER_ACTIVE)) {
-               spin_unlock_irqrestore(&priv->shrd->sta_lock, flags_spin);
+               spin_unlock_bh(&priv->sta_lock);
                return -EINVAL;
        }
-       spin_unlock_irqrestore(&priv->shrd->sta_lock, flags_spin);
+       spin_unlock_bh(&priv->sta_lock);
 
        iwl_dump_lq_cmd(priv, lq);
        if (WARN_ON(init && (cmd.flags & CMD_ASYNC)))
                return -EINVAL;
 
        if (is_lq_table_valid(priv, ctx, lq))
-               ret = iwl_trans_send_cmd(trans(priv), &cmd);
+               ret = iwl_dvm_send_cmd(priv, &cmd);
        else
                ret = -EINVAL;
 
@@ -819,9 +833,9 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
                IWL_DEBUG_INFO(priv, "init LQ command complete, "
                               "clearing sta addition status for sta %d\n",
                               lq->sta_id);
-               spin_lock_irqsave(&priv->shrd->sta_lock, flags_spin);
+               spin_lock_bh(&priv->sta_lock);
                priv->stations[lq->sta_id].used &= ~IWL_STA_UCODE_INPROGRESS;
-               spin_unlock_irqrestore(&priv->shrd->sta_lock, flags_spin);
+               spin_unlock_bh(&priv->sta_lock);
        }
        return ret;
 }
@@ -834,7 +848,7 @@ void iwl_sta_fill_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
        u32 rate_flags = 0;
        __le32 rate_n_flags;
 
-       lockdep_assert_held(&priv->shrd->mutex);
+       lockdep_assert_held(&priv->mutex);
 
        memset(link_cmd, 0, sizeof(*link_cmd));
 
@@ -906,7 +920,6 @@ int iwlagn_add_bssid_station(struct iwl_priv *priv,
        int ret;
        u8 sta_id;
        struct iwl_link_quality_cmd *link_cmd;
-       unsigned long flags;
 
        if (sta_id_r)
                *sta_id_r = IWL_INVALID_STATION;
@@ -920,9 +933,9 @@ int iwlagn_add_bssid_station(struct iwl_priv *priv,
        if (sta_id_r)
                *sta_id_r = sta_id;
 
-       spin_lock_irqsave(&priv->shrd->sta_lock, flags);
+       spin_lock_bh(&priv->sta_lock);
        priv->stations[sta_id].used |= IWL_STA_LOCAL;
-       spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
+       spin_unlock_bh(&priv->sta_lock);
 
        /* Set up default rate scaling table in device's station table */
        link_cmd = iwl_sta_alloc_lq(priv, ctx, sta_id);
@@ -937,9 +950,9 @@ int iwlagn_add_bssid_station(struct iwl_priv *priv,
        if (ret)
                IWL_ERR(priv, "Link quality command failed (%d)\n", ret);
 
-       spin_lock_irqsave(&priv->shrd->sta_lock, flags);
+       spin_lock_bh(&priv->sta_lock);
        priv->stations[sta_id].lq = link_cmd;
-       spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
+       spin_unlock_bh(&priv->sta_lock);
 
        return 0;
 }
@@ -994,7 +1007,7 @@ static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv,
        cmd.len[0] = cmd_size;
 
        if (not_empty || send_if_empty)
-               return iwl_trans_send_cmd(trans(priv), &cmd);
+               return iwl_dvm_send_cmd(priv, &cmd);
        else
                return 0;
 }
@@ -1002,7 +1015,7 @@ static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv,
 int iwl_restore_default_wep_keys(struct iwl_priv *priv,
                                 struct iwl_rxon_context *ctx)
 {
-       lockdep_assert_held(&priv->shrd->mutex);
+       lockdep_assert_held(&priv->mutex);
 
        return iwl_send_static_wepkey_cmd(priv, ctx, false);
 }
@@ -1013,13 +1026,13 @@ int iwl_remove_default_wep_key(struct iwl_priv *priv,
 {
        int ret;
 
-       lockdep_assert_held(&priv->shrd->mutex);
+       lockdep_assert_held(&priv->mutex);
 
        IWL_DEBUG_WEP(priv, "Removing default WEP key: idx=%d\n",
                      keyconf->keyidx);
 
        memset(&ctx->wep_keys[keyconf->keyidx], 0, sizeof(ctx->wep_keys[0]));
-       if (iwl_is_rfkill(priv->shrd)) {
+       if (iwl_is_rfkill(priv)) {
                IWL_DEBUG_WEP(priv,
                        "Not sending REPLY_WEPKEY command due to RFKILL.\n");
                /* but keys in device are clear anyway so return success */
@@ -1038,7 +1051,7 @@ int iwl_set_default_wep_key(struct iwl_priv *priv,
 {
        int ret;
 
-       lockdep_assert_held(&priv->shrd->mutex);
+       lockdep_assert_held(&priv->mutex);
 
        if (keyconf->keylen != WEP_KEY_LEN_128 &&
            keyconf->keylen != WEP_KEY_LEN_64) {
@@ -1080,32 +1093,19 @@ static u8 iwlagn_key_sta_id(struct iwl_priv *priv,
                            struct ieee80211_sta *sta)
 {
        struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
-       u8 sta_id = IWL_INVALID_STATION;
 
        if (sta)
-               sta_id = iwl_sta_id(sta);
+               return iwl_sta_id(sta);
 
        /*
         * The device expects GTKs for station interfaces to be
         * installed as GTKs for the AP station. If we have no
         * station ID, then use the ap_sta_id in that case.
         */
-       if (!sta && vif && vif_priv->ctx) {
-               switch (vif->type) {
-               case NL80211_IFTYPE_STATION:
-                       sta_id = vif_priv->ctx->ap_sta_id;
-                       break;
-               default:
-                       /*
-                        * In all other cases, the key will be
-                        * used either for TX only or is bound
-                        * to a station already.
-                        */
-                       break;
-               }
-       }
+       if (vif->type == NL80211_IFTYPE_STATION && vif_priv->ctx)
+               return vif_priv->ctx->ap_sta_id;
 
-       return sta_id;
+       return IWL_INVALID_STATION;
 }
 
 static int iwlagn_send_sta_key(struct iwl_priv *priv,
@@ -1113,14 +1113,13 @@ static int iwlagn_send_sta_key(struct iwl_priv *priv,
                               u8 sta_id, u32 tkip_iv32, u16 *tkip_p1k,
                               u32 cmd_flags)
 {
-       unsigned long flags;
        __le16 key_flags;
        struct iwl_addsta_cmd sta_cmd;
        int i;
 
-       spin_lock_irqsave(&priv->shrd->sta_lock, flags);
+       spin_lock_bh(&priv->sta_lock);
        memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(sta_cmd));
-       spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
+       spin_unlock_bh(&priv->sta_lock);
 
        key_flags = cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
        key_flags |= STA_KEY_FLG_MAP_KEY_MSK;
@@ -1187,7 +1186,6 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv,
                           struct ieee80211_key_conf *keyconf,
                           struct ieee80211_sta *sta)
 {
-       unsigned long flags;
        struct iwl_addsta_cmd sta_cmd;
        u8 sta_id = iwlagn_key_sta_id(priv, ctx->vif, sta);
        __le16 key_flags;
@@ -1196,16 +1194,16 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv,
        if (sta_id == IWL_INVALID_STATION)
                return -ENOENT;
 
-       spin_lock_irqsave(&priv->shrd->sta_lock, flags);
+       spin_lock_bh(&priv->sta_lock);
        memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(sta_cmd));
        if (!(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE))
                sta_id = IWL_INVALID_STATION;
-       spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
+       spin_unlock_bh(&priv->sta_lock);
 
        if (sta_id == IWL_INVALID_STATION)
                return 0;
 
-       lockdep_assert_held(&priv->shrd->mutex);
+       lockdep_assert_held(&priv->mutex);
 
        ctx->key_mapping_keys--;
 
@@ -1245,7 +1243,7 @@ int iwl_set_dynamic_key(struct iwl_priv *priv,
        if (sta_id == IWL_INVALID_STATION)
                return -EINVAL;
 
-       lockdep_assert_held(&priv->shrd->mutex);
+       lockdep_assert_held(&priv->mutex);
 
        keyconf->hw_key_idx = iwl_get_free_ucode_key_offset(priv);
        if (keyconf->hw_key_idx == WEP_INVALID_OFFSET)
@@ -1300,21 +1298,20 @@ int iwlagn_alloc_bcast_station(struct iwl_priv *priv,
                               struct iwl_rxon_context *ctx)
 {
        struct iwl_link_quality_cmd *link_cmd;
-       unsigned long flags;
        u8 sta_id;
 
-       spin_lock_irqsave(&priv->shrd->sta_lock, flags);
+       spin_lock_bh(&priv->sta_lock);
        sta_id = iwl_prep_station(priv, ctx, iwl_bcast_addr, false, NULL);
        if (sta_id == IWL_INVALID_STATION) {
                IWL_ERR(priv, "Unable to prepare broadcast station\n");
-               spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
+               spin_unlock_bh(&priv->sta_lock);
 
                return -EINVAL;
        }
 
        priv->stations[sta_id].used |= IWL_STA_DRIVER_ACTIVE;
        priv->stations[sta_id].used |= IWL_STA_BCAST;
-       spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
+       spin_unlock_bh(&priv->sta_lock);
 
        link_cmd = iwl_sta_alloc_lq(priv, ctx, sta_id);
        if (!link_cmd) {
@@ -1323,9 +1320,9 @@ int iwlagn_alloc_bcast_station(struct iwl_priv *priv,
                return -ENOMEM;
        }
 
-       spin_lock_irqsave(&priv->shrd->sta_lock, flags);
+       spin_lock_bh(&priv->sta_lock);
        priv->stations[sta_id].lq = link_cmd;
-       spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
+       spin_unlock_bh(&priv->sta_lock);
 
        return 0;
 }
@@ -1339,7 +1336,6 @@ int iwlagn_alloc_bcast_station(struct iwl_priv *priv,
 int iwl_update_bcast_station(struct iwl_priv *priv,
                             struct iwl_rxon_context *ctx)
 {
-       unsigned long flags;
        struct iwl_link_quality_cmd *link_cmd;
        u8 sta_id = ctx->bcast_sta_id;
 
@@ -1349,13 +1345,13 @@ int iwl_update_bcast_station(struct iwl_priv *priv,
                return -ENOMEM;
        }
 
-       spin_lock_irqsave(&priv->shrd->sta_lock, flags);
+       spin_lock_bh(&priv->sta_lock);
        if (priv->stations[sta_id].lq)
                kfree(priv->stations[sta_id].lq);
        else
                IWL_DEBUG_INFO(priv, "Bcast station rate scaling has not been initialized yet.\n");
        priv->stations[sta_id].lq = link_cmd;
-       spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
+       spin_unlock_bh(&priv->sta_lock);
 
        return 0;
 }
@@ -1379,18 +1375,17 @@ int iwl_update_bcast_stations(struct iwl_priv *priv)
  */
 int iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid)
 {
-       unsigned long flags;
        struct iwl_addsta_cmd sta_cmd;
 
-       lockdep_assert_held(&priv->shrd->mutex);
+       lockdep_assert_held(&priv->mutex);
 
        /* Remove "disable" flag, to enable Tx for this TID */
-       spin_lock_irqsave(&priv->shrd->sta_lock, flags);
+       spin_lock_bh(&priv->sta_lock);
        priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX;
        priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid));
        priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
        memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
-       spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
+       spin_unlock_bh(&priv->sta_lock);
 
        return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
 }
@@ -1398,24 +1393,23 @@ int iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid)
 int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta,
                         int tid, u16 ssn)
 {
-       unsigned long flags;
        int sta_id;
        struct iwl_addsta_cmd sta_cmd;
 
-       lockdep_assert_held(&priv->shrd->mutex);
+       lockdep_assert_held(&priv->mutex);
 
        sta_id = iwl_sta_id(sta);
        if (sta_id == IWL_INVALID_STATION)
                return -ENXIO;
 
-       spin_lock_irqsave(&priv->shrd->sta_lock, flags);
+       spin_lock_bh(&priv->sta_lock);
        priv->stations[sta_id].sta.station_flags_msk = 0;
        priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK;
        priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid;
        priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn);
        priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
        memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
-       spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
+       spin_unlock_bh(&priv->sta_lock);
 
        return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
 }
@@ -1423,11 +1417,10 @@ int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta,
 int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta,
                        int tid)
 {
-       unsigned long flags;
        int sta_id;
        struct iwl_addsta_cmd sta_cmd;
 
-       lockdep_assert_held(&priv->shrd->mutex);
+       lockdep_assert_held(&priv->mutex);
 
        sta_id = iwl_sta_id(sta);
        if (sta_id == IWL_INVALID_STATION) {
@@ -1435,13 +1428,13 @@ int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta,
                return -ENXIO;
        }
 
-       spin_lock_irqsave(&priv->shrd->sta_lock, flags);
+       spin_lock_bh(&priv->sta_lock);
        priv->stations[sta_id].sta.station_flags_msk = 0;
        priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK;
        priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid;
        priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
        memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
-       spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
+       spin_unlock_bh(&priv->sta_lock);
 
        return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
 }
@@ -1450,16 +1443,14 @@ int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta,
 
 void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt)
 {
-       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 =
-                                       STA_MODIFY_SLEEP_TX_COUNT_MSK;
-       priv->stations[sta_id].sta.sleep_tx_count = cpu_to_le16(cnt);
-       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);
+       struct iwl_addsta_cmd cmd = {
+               .mode = STA_CONTROL_MODIFY_MSK,
+               .station_flags = STA_FLG_PWR_SAVE_MSK,
+               .station_flags_msk = STA_FLG_PWR_SAVE_MSK,
+               .sta.sta_id = sta_id,
+               .sta.modify_mask = STA_MODIFY_SLEEP_TX_COUNT_MSK,
+               .sleep_tx_count = cpu_to_le16(cnt),
+       };
 
+       iwl_send_add_sta(priv, &cmd, CMD_ASYNC);
 }
index c728ed75584e0dad2eecfedb40bf1cb9a8bfd2c6..baaf5ba2fc38b79e818e8e2ef19b469a89bf72d1 100644 (file)
@@ -34,6 +34,7 @@
 
 #include <net/mac80211.h>
 
+#include "iwl-agn.h"
 #include "iwl-eeprom.h"
 #include "iwl-dev.h"
 #include "iwl-core.h"
@@ -173,7 +174,7 @@ static void iwl_tt_check_exit_ct_kill(unsigned long data)
        struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
        unsigned long flags;
 
-       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
        if (tt->state == IWL_TI_CT_KILL) {
@@ -188,7 +189,7 @@ static void iwl_tt_check_exit_ct_kill(unsigned long data)
                }
                iwl_read32(trans(priv), CSR_UCODE_DRV_GP1);
                spin_lock_irqsave(&trans(priv)->reg_lock, flags);
-               if (!iwl_grab_nic_access(trans(priv)))
+               if (likely(iwl_grab_nic_access(trans(priv))))
                        iwl_release_nic_access(trans(priv));
                spin_unlock_irqrestore(&trans(priv)->reg_lock, flags);
 
@@ -224,7 +225,7 @@ static void iwl_tt_ready_for_ct_kill(unsigned long data)
        struct iwl_priv *priv = (struct iwl_priv *)data;
        struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
 
-       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
        /* temperature timer expired, ready to go into CT_KILL state */
@@ -232,7 +233,7 @@ static void iwl_tt_ready_for_ct_kill(unsigned long data)
                IWL_DEBUG_TEMP(priv, "entering CT_KILL state when "
                                "temperature timer expired\n");
                tt->state = IWL_TI_CT_KILL;
-               set_bit(STATUS_CT_KILL, &priv->shrd->status);
+               set_bit(STATUS_CT_KILL, &priv->status);
                iwl_perform_ct_kill_task(priv, true);
        }
 }
@@ -310,24 +311,23 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
                        tt->tt_power_mode = IWL_POWER_INDEX_5;
                        break;
                }
-               mutex_lock(&priv->shrd->mutex);
+               mutex_lock(&priv->mutex);
                if (old_state == IWL_TI_CT_KILL)
-                       clear_bit(STATUS_CT_KILL, &priv->shrd->status);
+                       clear_bit(STATUS_CT_KILL, &priv->status);
                if (tt->state != IWL_TI_CT_KILL &&
                    iwl_power_update_mode(priv, true)) {
                        /* TT state not updated
                         * try again during next temperature read
                         */
                        if (old_state == IWL_TI_CT_KILL)
-                               set_bit(STATUS_CT_KILL, &priv->shrd->status);
+                               set_bit(STATUS_CT_KILL, &priv->status);
                        tt->state = old_state;
                        IWL_ERR(priv, "Cannot update power mode, "
                                        "TT state not updated\n");
                } else {
                        if (tt->state == IWL_TI_CT_KILL) {
                                if (force) {
-                                       set_bit(STATUS_CT_KILL,
-                                               &priv->shrd->status);
+                                       set_bit(STATUS_CT_KILL, &priv->status);
                                        iwl_perform_ct_kill_task(priv, true);
                                } else {
                                        iwl_prepare_ct_kill_task(priv);
@@ -341,7 +341,7 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
                        IWL_DEBUG_TEMP(priv, "Power Index change to %u\n",
                                        tt->tt_power_mode);
                }
-               mutex_unlock(&priv->shrd->mutex);
+               mutex_unlock(&priv->mutex);
        }
 }
 
@@ -451,9 +451,9 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
                         * in case get disabled before */
                        iwl_set_rxon_ht(priv, &priv->current_ht_config);
                }
-               mutex_lock(&priv->shrd->mutex);
+               mutex_lock(&priv->mutex);
                if (old_state == IWL_TI_CT_KILL)
-                       clear_bit(STATUS_CT_KILL, &priv->shrd->status);
+                       clear_bit(STATUS_CT_KILL, &priv->status);
                if (tt->state != IWL_TI_CT_KILL &&
                    iwl_power_update_mode(priv, true)) {
                        /* TT state not updated
@@ -462,7 +462,7 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
                        IWL_ERR(priv, "Cannot update power mode, "
                                        "TT state not updated\n");
                        if (old_state == IWL_TI_CT_KILL)
-                               set_bit(STATUS_CT_KILL, &priv->shrd->status);
+                               set_bit(STATUS_CT_KILL, &priv->status);
                        tt->state = old_state;
                } else {
                        IWL_DEBUG_TEMP(priv,
@@ -473,8 +473,7 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
                                if (force) {
                                        IWL_DEBUG_TEMP(priv,
                                                "Enter IWL_TI_CT_KILL\n");
-                                       set_bit(STATUS_CT_KILL,
-                                               &priv->shrd->status);
+                                       set_bit(STATUS_CT_KILL, &priv->status);
                                        iwl_perform_ct_kill_task(priv, true);
                                } else {
                                        iwl_prepare_ct_kill_task(priv);
@@ -486,7 +485,7 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
                                iwl_perform_ct_kill_task(priv, false);
                        }
                }
-               mutex_unlock(&priv->shrd->mutex);
+               mutex_unlock(&priv->mutex);
        }
 }
 
@@ -505,10 +504,10 @@ static void iwl_bg_ct_enter(struct work_struct *work)
        struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_enter);
        struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
 
-       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
-       if (!iwl_is_ready(priv->shrd))
+       if (!iwl_is_ready(priv))
                return;
 
        if (tt->state != IWL_TI_CT_KILL) {
@@ -534,10 +533,10 @@ static void iwl_bg_ct_exit(struct work_struct *work)
        struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_exit);
        struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
 
-       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
-       if (!iwl_is_ready(priv->shrd))
+       if (!iwl_is_ready(priv))
                return;
 
        /* stop ct_kill_exit_tm timer */
@@ -564,20 +563,20 @@ static void iwl_bg_ct_exit(struct work_struct *work)
 
 void iwl_tt_enter_ct_kill(struct iwl_priv *priv)
 {
-       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
        IWL_DEBUG_TEMP(priv, "Queueing critical temperature enter.\n");
-       queue_work(priv->shrd->workqueue, &priv->ct_enter);
+       queue_work(priv->workqueue, &priv->ct_enter);
 }
 
 void iwl_tt_exit_ct_kill(struct iwl_priv *priv)
 {
-       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
        IWL_DEBUG_TEMP(priv, "Queueing critical temperature exit.\n");
-       queue_work(priv->shrd->workqueue, &priv->ct_exit);
+       queue_work(priv->workqueue, &priv->ct_exit);
 }
 
 static void iwl_bg_tt_work(struct work_struct *work)
@@ -585,7 +584,7 @@ static void iwl_bg_tt_work(struct work_struct *work)
        struct iwl_priv *priv = container_of(work, struct iwl_priv, tt_work);
        s32 temp = priv->temperature; /* degrees CELSIUS except specified */
 
-       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
        if (!priv->thermal_throttle.advanced_tt)
@@ -596,11 +595,11 @@ static void iwl_bg_tt_work(struct work_struct *work)
 
 void iwl_tt_handler(struct iwl_priv *priv)
 {
-       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
        IWL_DEBUG_TEMP(priv, "Queueing thermal throttling work.\n");
-       queue_work(priv->shrd->workqueue, &priv->tt_work);
+       queue_work(priv->workqueue, &priv->tt_work);
 }
 
 /* Thermal throttling initialization
index 64f8db685dc50fbdf72a5927331fc93d344a9f10..34adedc74d35a5a4308e07cbb6ad9491d9c88d66 100644 (file)
@@ -126,7 +126,7 @@ static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv,
        u8 data_retry_limit;
        u8 rate_plcp;
 
-       if (priv->shrd->wowlan) {
+       if (priv->wowlan) {
                rts_retry_limit = IWLAGN_LOW_RETRY_LIMIT;
                data_retry_limit = IWLAGN_LOW_RETRY_LIMIT;
        } else {
@@ -208,10 +208,9 @@ static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv,
 }
 
 static void iwlagn_tx_cmd_build_hwcrypto(struct iwl_priv *priv,
-                                     struct ieee80211_tx_info *info,
-                                     struct iwl_tx_cmd *tx_cmd,
-                                     struct sk_buff *skb_frag,
-                                     int sta_id)
+                                        struct ieee80211_tx_info *info,
+                                        struct iwl_tx_cmd *tx_cmd,
+                                        struct sk_buff *skb_frag)
 {
        struct ieee80211_key_conf *keyconf = info->control.hw_key;
 
@@ -249,6 +248,35 @@ static void iwlagn_tx_cmd_build_hwcrypto(struct iwl_priv *priv,
        }
 }
 
+/**
+ * iwl_sta_id_or_broadcast - return sta_id or broadcast sta
+ * @context: the current context
+ * @sta: mac80211 station
+ *
+ * In certain circumstances mac80211 passes a station pointer
+ * that may be %NULL, for example during TX or key setup. In
+ * that case, we need to use the broadcast station, so this
+ * inline wraps that pattern.
+ */
+static int iwl_sta_id_or_broadcast(struct iwl_rxon_context *context,
+                                  struct ieee80211_sta *sta)
+{
+       int sta_id;
+
+       if (!sta)
+               return context->bcast_sta_id;
+
+       sta_id = iwl_sta_id(sta);
+
+       /*
+        * mac80211 should not be passing a partially
+        * initialised station!
+        */
+       WARN_ON(sta_id == IWL_INVALID_STATION);
+
+       return sta_id;
+}
+
 /*
  * start REPLY_TX command process
  */
@@ -260,19 +288,16 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
        struct iwl_device_cmd *dev_cmd = NULL;
        struct iwl_tx_cmd *tx_cmd;
-
        __le16 fc;
        u8 hdr_len;
        u16 len, seq_number = 0;
        u8 sta_id, tid = IWL_MAX_TID_COUNT;
-       unsigned long flags;
        bool is_agg = false;
 
        if (info->control.vif)
                ctx = iwl_rxon_ctx_from_vif(info->control.vif);
 
-       spin_lock_irqsave(&priv->shrd->lock, flags);
-       if (iwl_is_rfkill(priv->shrd)) {
+       if (iwl_is_rfkill(priv)) {
                IWL_DEBUG_DROP(priv, "Dropping - RF KILL\n");
                goto drop_unlock_priv;
        }
@@ -308,7 +333,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
                sta_id = ctx->bcast_sta_id;
        else {
                /* Find index into station table for destination station */
-               sta_id = iwl_sta_id_or_broadcast(priv, ctx, info->control.sta);
+               sta_id = iwl_sta_id_or_broadcast(ctx, info->control.sta);
                if (sta_id == IWL_INVALID_STATION) {
                        IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
                                       hdr->addr1);
@@ -322,7 +347,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
                sta_priv = (void *)info->control.sta->drv_priv;
 
        if (sta_priv && sta_priv->asleep &&
-           (info->flags & IEEE80211_TX_CTL_POLL_RESPONSE)) {
+           (info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER)) {
                /*
                 * This sends an asynchronous command to the device,
                 * but we can rely on it being processed before the
@@ -331,6 +356,10 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
                 * counter.
                 * For now set the counter to just 1 since we do not
                 * support uAPSD yet.
+                *
+                * FIXME: If we get two non-bufferable frames one
+                * after the other, we might only send out one of
+                * them because this is racy.
                 */
                iwl_sta_modify_sleep_tx_count(priv, sta_id, 1);
        }
@@ -338,13 +367,10 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        if (info->flags & IEEE80211_TX_CTL_AMPDU)
                is_agg = true;
 
-       /* irqs already disabled/saved above when locking priv->shrd->lock */
-       spin_lock(&priv->shrd->sta_lock);
-
-       dev_cmd = kmem_cache_alloc(priv->tx_cmd_pool, GFP_ATOMIC);
+       dev_cmd = kmem_cache_alloc(iwl_tx_cmd_pool, GFP_ATOMIC);
 
        if (unlikely(!dev_cmd))
-               goto drop_unlock_sta;
+               goto drop_unlock_priv;
 
        memset(dev_cmd, 0, sizeof(*dev_cmd));
        tx_cmd = (struct iwl_tx_cmd *) dev_cmd->payload;
@@ -354,7 +380,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        tx_cmd->len = cpu_to_le16(len);
 
        if (info->control.hw_key)
-               iwlagn_tx_cmd_build_hwcrypto(priv, info, tx_cmd, skb, sta_id);
+               iwlagn_tx_cmd_build_hwcrypto(priv, info, tx_cmd, skb);
 
        /* TODO need this for burst mode later on */
        iwlagn_tx_cmd_build_basic(priv, skb, tx_cmd, info, hdr, sta_id);
@@ -369,6 +395,8 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        info->driver_data[0] = ctx;
        info->driver_data[1] = dev_cmd;
 
+       spin_lock(&priv->sta_lock);
+
        if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc)) {
                u8 *qc = NULL;
                struct iwl_tid_data *tid_data;
@@ -414,8 +442,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
            !ieee80211_has_morefrags(fc))
                priv->tid_data[sta_id][tid].seq_number = seq_number;
 
-       spin_unlock(&priv->shrd->sta_lock);
-       spin_unlock_irqrestore(&priv->shrd->lock, flags);
+       spin_unlock(&priv->sta_lock);
 
        /*
         * Avoid atomic ops if it isn't an associated client.
@@ -431,10 +458,9 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 
 drop_unlock_sta:
        if (dev_cmd)
-               kmem_cache_free(priv->tx_cmd_pool, dev_cmd);
-       spin_unlock(&priv->shrd->sta_lock);
+               kmem_cache_free(iwl_tx_cmd_pool, dev_cmd);
+       spin_unlock(&priv->sta_lock);
 drop_unlock_priv:
-       spin_unlock_irqrestore(&priv->shrd->lock, flags);
        return -1;
 }
 
@@ -442,7 +468,6 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
                        struct ieee80211_sta *sta, u16 tid)
 {
        struct iwl_tid_data *tid_data;
-       unsigned long flags;
        int sta_id;
 
        sta_id = iwl_sta_id(sta);
@@ -452,7 +477,7 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
                return -ENXIO;
        }
 
-       spin_lock_irqsave(&priv->shrd->sta_lock, flags);
+       spin_lock_bh(&priv->sta_lock);
 
        tid_data = &priv->tid_data[sta_id][tid];
 
@@ -472,7 +497,7 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
                IWL_WARN(priv, "Stopping AGG while state not ON "
                         "or starting for %d on %d (%d)\n", sta_id, tid,
                         priv->tid_data[sta_id][tid].agg.state);
-               spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
+               spin_unlock_bh(&priv->sta_lock);
                return 0;
        }
 
@@ -486,7 +511,7 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
                                    tid_data->next_reclaimed);
                priv->tid_data[sta_id][tid].agg.state =
                        IWL_EMPTYING_HW_QUEUE_DELBA;
-               spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
+               spin_unlock_bh(&priv->sta_lock);
                return 0;
        }
 
@@ -495,14 +520,10 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
 turn_off:
        priv->tid_data[sta_id][tid].agg.state = IWL_AGG_OFF;
 
-       /* do not restore/save irqs */
-       spin_unlock(&priv->shrd->sta_lock);
-       spin_lock(&priv->shrd->lock);
+       spin_unlock_bh(&priv->sta_lock);
 
        iwl_trans_tx_agg_disable(trans(priv), sta_id, tid);
 
-       spin_unlock_irqrestore(&priv->shrd->lock, flags);
-
        ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
 
        return 0;
@@ -512,7 +533,6 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
                        struct ieee80211_sta *sta, u16 tid, u16 *ssn)
 {
        struct iwl_tid_data *tid_data;
-       unsigned long flags;
        int sta_id;
        int ret;
 
@@ -536,7 +556,7 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
        if (ret)
                return ret;
 
-       spin_lock_irqsave(&priv->shrd->sta_lock, flags);
+       spin_lock_bh(&priv->sta_lock);
 
        tid_data = &priv->tid_data[sta_id][tid];
        tid_data->agg.ssn = SEQ_TO_SN(tid_data->seq_number);
@@ -545,7 +565,7 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
 
        ret = iwl_trans_tx_agg_alloc(trans(priv), sta_id, tid);
        if (ret) {
-               spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
+               spin_unlock_bh(&priv->sta_lock);
                return ret;
        }
 
@@ -562,7 +582,7 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
                tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA;
        }
 
-       spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
+       spin_unlock_bh(&priv->sta_lock);
 
        return ret;
 }
@@ -572,14 +592,13 @@ int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif,
 {
        struct iwl_station_priv *sta_priv = (void *) sta->drv_priv;
        struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
-       unsigned long flags;
        u16 ssn;
 
        buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF);
 
-       spin_lock_irqsave(&priv->shrd->sta_lock, flags);
+       spin_lock_bh(&priv->sta_lock);
        ssn = priv->tid_data[sta_priv->sta_id][tid].agg.ssn;
-       spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
+       spin_unlock_bh(&priv->sta_lock);
 
        iwl_trans_tx_agg_setup(trans(priv), ctx->ctxid, sta_priv->sta_id, tid,
                               buf_size, ssn);
@@ -604,8 +623,7 @@ int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif,
        sta_priv->max_agg_bufsize =
                min(sta_priv->max_agg_bufsize, buf_size);
 
-       if (cfg(priv)->ht_params &&
-           cfg(priv)->ht_params->use_rts_for_aggregation) {
+       if (hw_params(priv).use_rts_for_aggregation) {
                /*
                 * switch to RTS/CTS if it is the prefer protection
                 * method for HT traffic
@@ -635,7 +653,7 @@ static void iwlagn_check_ratid_empty(struct iwl_priv *priv, int sta_id, u8 tid)
        struct ieee80211_vif *vif;
        u8 *addr;
 
-       lockdep_assert_held(&priv->shrd->sta_lock);
+       lockdep_assert_held(&priv->sta_lock);
 
        addr = priv->stations[sta_id].sta.sta.addr;
        ctx = priv->stations[sta_id].ctxid;
@@ -982,19 +1000,19 @@ static void iwl_check_abort_status(struct iwl_priv *priv,
 {
        if (frame_count == 1 && status == TX_STATUS_FAIL_RFKILL_FLUSH) {
                IWL_ERR(priv, "Tx flush command to flush out all frames\n");
-               if (!test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
-                       queue_work(priv->shrd->workqueue, &priv->tx_flush);
+               if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
+                       queue_work(priv->workqueue, &priv->tx_flush);
        }
 }
 
-int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
+int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
                               struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        u16 sequence = le16_to_cpu(pkt->hdr.sequence);
        int txq_id = SEQ_TO_QUEUE(sequence);
        int cmd_index __maybe_unused = SEQ_TO_INDEX(sequence);
-       struct iwlagn_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
+       struct iwlagn_tx_resp *tx_resp = (void *)pkt->data;
        struct ieee80211_hdr *hdr;
        u32 status = le16_to_cpu(tx_resp->status.status);
        u16 ssn = iwlagn_get_scd_ssn(tx_resp);
@@ -1002,7 +1020,6 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
        int sta_id;
        int freed;
        struct ieee80211_tx_info *info;
-       unsigned long flags;
        struct sk_buff_head skbs;
        struct sk_buff *skb;
        struct iwl_rxon_context *ctx;
@@ -1013,11 +1030,13 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
        sta_id = (tx_resp->ra_tid & IWLAGN_TX_RES_RA_MSK) >>
                IWLAGN_TX_RES_RA_POS;
 
-       spin_lock_irqsave(&priv->shrd->sta_lock, flags);
+       spin_lock(&priv->sta_lock);
 
        if (is_agg)
                iwl_rx_reply_tx_agg(priv, tx_resp);
 
+       __skb_queue_head_init(&skbs);
+
        if (tx_resp->frame_count == 1) {
                u16 next_reclaimed = le16_to_cpu(tx_resp->seq_ctl);
                next_reclaimed = SEQ_TO_SN(next_reclaimed + 0x10);
@@ -1037,8 +1056,6 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
                        next_reclaimed = ssn;
                }
 
-               __skb_queue_head_init(&skbs);
-
                if (tid != IWL_TID_NON_QOS) {
                        priv->tid_data[sta_id][tid].next_reclaimed =
                                next_reclaimed;
@@ -1047,12 +1064,13 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
                }
 
                /*we can free until ssn % q.n_bd not inclusive */
-               WARN_ON(iwl_trans_reclaim(trans(priv), sta_id, tid, txq_id,
-                                 ssn, status, &skbs));
+               WARN_ON(iwl_trans_reclaim(trans(priv), sta_id, tid,
+                                         txq_id, ssn, &skbs));
                iwlagn_check_ratid_empty(priv, sta_id, tid);
                freed = 0;
-               while (!skb_queue_empty(&skbs)) {
-                       skb = __skb_dequeue(&skbs);
+
+               /* process frames */
+               skb_queue_walk(&skbs, skb) {
                        hdr = (struct ieee80211_hdr *)skb->data;
 
                        if (!ieee80211_is_data_qos(hdr->frame_control))
@@ -1060,7 +1078,7 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
 
                        info = IEEE80211_SKB_CB(skb);
                        ctx = info->driver_data[0];
-                       kmem_cache_free(priv->tx_cmd_pool,
+                       kmem_cache_free(iwl_tx_cmd_pool,
                                        (info->driver_data[1]));
 
                        memset(&info->status, 0, sizeof(info->status));
@@ -1068,9 +1086,11 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
                        if (status == TX_STATUS_FAIL_PASSIVE_NO_RX &&
                            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,
-                                       "Tx on passive channel");
+                               /* block and stop all queues */
+                               priv->passive_no_rx = true;
+                               IWL_DEBUG_TX_QUEUES(priv, "stop all queues: "
+                                                   "passive channel");
+                               ieee80211_stop_queues(priv->hw);
 
                                IWL_DEBUG_TX_REPLY(priv,
                                           "TXQ %d status %s (0x%08x) "
@@ -1094,8 +1114,6 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
                        if (!is_agg)
                                iwlagn_non_agg_tx_status(priv, ctx, hdr->addr1);
 
-                       ieee80211_tx_status_irqsafe(priv->hw, skb);
-
                        freed++;
                }
 
@@ -1103,7 +1121,13 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
        }
 
        iwl_check_abort_status(priv, tx_resp->frame_count, status);
-       spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
+       spin_unlock(&priv->sta_lock);
+
+       while (!skb_queue_empty(&skbs)) {
+               skb = __skb_dequeue(&skbs);
+               ieee80211_tx_status(priv->hw, skb);
+       }
+
        return 0;
 }
 
@@ -1114,17 +1138,16 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
  * of frames sent via aggregation.
  */
 int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
-                                  struct iwl_rx_mem_buffer *rxb,
+                                  struct iwl_rx_cmd_buffer *rxb,
                                   struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba;
+       struct iwl_compressed_ba_resp *ba_resp = (void *)pkt->data;
        struct iwl_ht_agg *agg;
        struct sk_buff_head reclaimed_skbs;
        struct ieee80211_tx_info *info;
        struct ieee80211_hdr *hdr;
        struct sk_buff *skb;
-       unsigned long flags;
        int sta_id;
        int tid;
        int freed;
@@ -1136,7 +1159,7 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
         * (in Tx queue's circular buffer) of first TFD/frame in window */
        u16 ba_resp_scd_ssn = le16_to_cpu(ba_resp->scd_ssn);
 
-       if (scd_flow >= hw_params(priv).max_txq_num) {
+       if (scd_flow >= cfg(priv)->base_params->num_of_queues) {
                IWL_ERR(priv,
                        "BUG_ON scd_flow is bigger than number of queues\n");
                return 0;
@@ -1146,12 +1169,12 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
        tid = ba_resp->tid;
        agg = &priv->tid_data[sta_id][tid].agg;
 
-       spin_lock_irqsave(&priv->shrd->sta_lock, flags);
+       spin_lock(&priv->sta_lock);
 
        if (unlikely(!agg->wait_for_ba)) {
                if (unlikely(ba_resp->bitmap))
                        IWL_ERR(priv, "Received BA when not expected\n");
-               spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
+               spin_unlock(&priv->sta_lock);
                return 0;
        }
 
@@ -1161,8 +1184,8 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
         * block-ack window (we assume that they've been successfully
         * transmitted ... if not, it's too late anyway). */
        if (iwl_trans_reclaim(trans(priv), sta_id, tid, scd_flow,
-                             ba_resp_scd_ssn, 0, &reclaimed_skbs)) {
-               spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
+                             ba_resp_scd_ssn, &reclaimed_skbs)) {
+               spin_unlock(&priv->sta_lock);
                return 0;
        }
 
@@ -1198,9 +1221,8 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
 
        iwlagn_check_ratid_empty(priv, sta_id, tid);
        freed = 0;
-       while (!skb_queue_empty(&reclaimed_skbs)) {
 
-               skb = __skb_dequeue(&reclaimed_skbs);
+       skb_queue_walk(&reclaimed_skbs, skb) {
                hdr = (struct ieee80211_hdr *)skb->data;
 
                if (ieee80211_is_data_qos(hdr->frame_control))
@@ -1209,7 +1231,7 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
                        WARN_ON_ONCE(1);
 
                info = IEEE80211_SKB_CB(skb);
-               kmem_cache_free(priv->tx_cmd_pool, (info->driver_data[1]));
+               kmem_cache_free(iwl_tx_cmd_pool, (info->driver_data[1]));
 
                if (freed == 1) {
                        /* this is the first skb we deliver in this batch */
@@ -1223,10 +1245,14 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
                        iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags,
                                                    info);
                }
+       }
+
+       spin_unlock(&priv->sta_lock);
 
-               ieee80211_tx_status_irqsafe(priv->hw, skb);
+       while (!skb_queue_empty(&reclaimed_skbs)) {
+               skb = __skb_dequeue(&reclaimed_skbs);
+               ieee80211_tx_status(priv->hw, skb);
        }
 
-       spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
        return 0;
 }
index 8837171ad55301af44eb72873beed8b5536b20f5..28422c03d6730c13280d972735ef54da19711ac8 100644 (file)
 
 #include <asm/div64.h>
 
-#include "iwl-ucode.h"
 #include "iwl-eeprom.h"
-#include "iwl-wifi.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"
+#include "iwl-op-mode.h"
 
 /******************************************************************************
  *
@@ -134,7 +132,7 @@ int iwlagn_send_beacon_cmd(struct iwl_priv *priv)
         * beacon contents.
         */
 
-       lockdep_assert_held(&priv->shrd->mutex);
+       lockdep_assert_held(&priv->mutex);
 
        if (!priv->beacon_ctx) {
                IWL_ERR(priv, "trying to build beacon w/o beacon context!\n");
@@ -199,7 +197,7 @@ int iwlagn_send_beacon_cmd(struct iwl_priv *priv)
        cmd.data[1] = priv->beacon_skb->data;
        cmd.dataflags[1] = IWL_HCMD_DFL_NOCOPY;
 
-       return iwl_trans_send_cmd(trans(priv), &cmd);
+       return iwl_dvm_send_cmd(priv, &cmd);
 }
 
 static void iwl_bg_beacon_update(struct work_struct *work)
@@ -208,7 +206,7 @@ static void iwl_bg_beacon_update(struct work_struct *work)
                container_of(work, struct iwl_priv, beacon_update);
        struct sk_buff *beacon;
 
-       mutex_lock(&priv->shrd->mutex);
+       mutex_lock(&priv->mutex);
        if (!priv->beacon_ctx) {
                IWL_ERR(priv, "updating beacon w/o beacon context!\n");
                goto out;
@@ -238,7 +236,7 @@ static void iwl_bg_beacon_update(struct work_struct *work)
 
        iwlagn_send_beacon_cmd(priv);
  out:
-       mutex_unlock(&priv->shrd->mutex);
+       mutex_unlock(&priv->mutex);
 }
 
 static void iwl_bg_bt_runtime_config(struct work_struct *work)
@@ -246,11 +244,11 @@ static void iwl_bg_bt_runtime_config(struct work_struct *work)
        struct iwl_priv *priv =
                container_of(work, struct iwl_priv, bt_runtime_config);
 
-       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
        /* dont send host command if rf-kill is on */
-       if (!iwl_is_ready_rf(priv->shrd))
+       if (!iwl_is_ready_rf(priv))
                return;
        iwlagn_send_advance_bt_config(priv);
 }
@@ -261,13 +259,13 @@ static void iwl_bg_bt_full_concurrency(struct work_struct *work)
                container_of(work, struct iwl_priv, bt_full_concurrency);
        struct iwl_rxon_context *ctx;
 
-       mutex_lock(&priv->shrd->mutex);
+       mutex_lock(&priv->mutex);
 
-       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                goto out;
 
        /* dont send host command if rf-kill is on */
-       if (!iwl_is_ready_rf(priv->shrd))
+       if (!iwl_is_ready_rf(priv))
                goto out;
 
        IWL_DEBUG_INFO(priv, "BT coex in %s mode\n",
@@ -285,7 +283,7 @@ static void iwl_bg_bt_full_concurrency(struct work_struct *work)
 
        iwlagn_send_advance_bt_config(priv);
 out:
-       mutex_unlock(&priv->shrd->mutex);
+       mutex_unlock(&priv->mutex);
 }
 
 /**
@@ -302,11 +300,11 @@ static void iwl_bg_statistics_periodic(unsigned long data)
 {
        struct iwl_priv *priv = (struct iwl_priv *)data;
 
-       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
        /* dont send host command if rf-kill is on */
-       if (!iwl_is_ready_rf(priv->shrd))
+       if (!iwl_is_ready_rf(priv))
                return;
 
        iwl_send_statistics_request(priv, CMD_ASYNC, false);
@@ -329,14 +327,13 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base,
 
        /* Make sure device is powered up for SRAM reads */
        spin_lock_irqsave(&trans(priv)->reg_lock, reg_flags);
-       if (iwl_grab_nic_access(trans(priv))) {
+       if (unlikely(!iwl_grab_nic_access(trans(priv)))) {
                spin_unlock_irqrestore(&trans(priv)->reg_lock, reg_flags);
                return;
        }
 
        /* Set starting address; reads will auto-increment */
        iwl_write32(trans(priv), HBUS_TARG_MEM_RADDR, ptr);
-       rmb();
 
        /*
         * Refuse to read more than would have fit into the log from
@@ -355,11 +352,12 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base,
                ev = iwl_read32(trans(priv), HBUS_TARG_MEM_RDAT);
                time = iwl_read32(trans(priv), HBUS_TARG_MEM_RDAT);
                if (mode == 0) {
-                       trace_iwlwifi_dev_ucode_cont_event(priv, 0, time, ev);
+                       trace_iwlwifi_dev_ucode_cont_event(
+                                       trans(priv)->dev, 0, time, ev);
                } else {
                        data = iwl_read32(trans(priv), HBUS_TARG_MEM_RDAT);
-                       trace_iwlwifi_dev_ucode_cont_event(priv, time,
-                                                          data, ev);
+                       trace_iwlwifi_dev_ucode_cont_event(
+                                       trans(priv)->dev, time, data, ev);
                }
        }
        /* Allow device to power down */
@@ -424,7 +422,7 @@ static void iwl_continuous_event_trace(struct iwl_priv *priv)
                else
                        priv->event_log.wraps_once_count++;
 
-               trace_iwlwifi_dev_ucode_wrap_event(priv,
+               trace_iwlwifi_dev_ucode_wrap_event(trans(priv)->dev,
                                num_wraps - priv->event_log.num_wraps,
                                next_entry, priv->event_log.next_entry);
 
@@ -463,7 +461,7 @@ static void iwl_bg_ucode_trace(unsigned long data)
 {
        struct iwl_priv *priv = (struct iwl_priv *)data;
 
-       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
        if (priv->event_log.ucode_trace) {
@@ -479,18 +477,18 @@ static void iwl_bg_tx_flush(struct work_struct *work)
        struct iwl_priv *priv =
                container_of(work, struct iwl_priv, tx_flush);
 
-       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
        /* do nothing if rf-kill is on */
-       if (!iwl_is_ready_rf(priv->shrd))
+       if (!iwl_is_ready_rf(priv))
                return;
 
        IWL_DEBUG_INFO(priv, "device request: flush all tx frames\n");
        iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL);
 }
 
-void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
+static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
 {
        int i;
 
@@ -552,13 +550,11 @@ static void iwl_rf_kill_ct_config(struct iwl_priv *priv)
 {
        struct iwl_ct_kill_config cmd;
        struct iwl_ct_kill_throttling_config adv_cmd;
-       unsigned long flags;
        int ret = 0;
 
-       spin_lock_irqsave(&priv->shrd->lock, flags);
        iwl_write32(trans(priv), CSR_UCODE_DRV_GP1_CLR,
                    CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
-       spin_unlock_irqrestore(&priv->shrd->lock, flags);
+
        priv->thermal_throttle.ct_kill_toggle = false;
 
        if (cfg(priv)->base_params->support_ct_kill_exit) {
@@ -567,7 +563,7 @@ static void iwl_rf_kill_ct_config(struct iwl_priv *priv)
                adv_cmd.critical_temperature_exit =
                        cpu_to_le32(hw_params(priv).ct_kill_exit_threshold);
 
-               ret = iwl_trans_send_cmd_pdu(trans(priv),
+               ret = iwl_dvm_send_cmd_pdu(priv,
                                       REPLY_CT_KILL_CONFIG_CMD,
                                       CMD_SYNC, sizeof(adv_cmd), &adv_cmd);
                if (ret)
@@ -582,7 +578,7 @@ static void iwl_rf_kill_ct_config(struct iwl_priv *priv)
                cmd.critical_temperature_R =
                        cpu_to_le32(hw_params(priv).ct_kill_threshold);
 
-               ret = iwl_trans_send_cmd_pdu(trans(priv),
+               ret = iwl_dvm_send_cmd_pdu(priv,
                                       REPLY_CT_KILL_CONFIG_CMD,
                                       CMD_SYNC, sizeof(cmd), &cmd);
                if (ret)
@@ -608,7 +604,7 @@ static int iwlagn_send_calib_cfg_rt(struct iwl_priv *priv, u32 cfg)
        calib_cfg_cmd.ucd_calib_cfg.once.is_enable = IWL_CALIB_RT_CFG_ALL;
        calib_cfg_cmd.ucd_calib_cfg.once.start = cpu_to_le32(cfg);
 
-       return iwl_trans_send_cmd(trans(priv), &cmd);
+       return iwl_dvm_send_cmd(priv, &cmd);
 }
 
 
@@ -618,9 +614,9 @@ static int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant)
          .valid = cpu_to_le32(valid_tx_ant),
        };
 
-       if (IWL_UCODE_API(priv->ucode_ver) > 1) {
+       if (IWL_UCODE_API(priv->fw->ucode_ver) > 1) {
                IWL_DEBUG_HC(priv, "select valid tx ant: %u\n", valid_tx_ant);
-               return iwl_trans_send_cmd_pdu(trans(priv),
+               return iwl_dvm_send_cmd_pdu(priv,
                                        TX_ANT_CONFIGURATION_CMD,
                                        CMD_SYNC,
                                        sizeof(struct iwl_tx_ant_config_cmd),
@@ -644,12 +640,12 @@ int iwl_alive_start(struct iwl_priv *priv)
        IWL_DEBUG_INFO(priv, "Runtime Alive received.\n");
 
        /* After the ALIVE response, we can send host commands to the uCode */
-       set_bit(STATUS_ALIVE, &priv->shrd->status);
+       set_bit(STATUS_ALIVE, &priv->status);
 
        /* Enable watchdog to monitor the driver tx queues */
        iwl_setup_watchdog(priv);
 
-       if (iwl_is_rfkill(priv->shrd))
+       if (iwl_is_rfkill(priv))
                return -ERFKILL;
 
        if (priv->event_log.ucode_trace) {
@@ -673,14 +669,14 @@ int iwl_alive_start(struct iwl_priv *priv)
                priv->bt_valid = IWLAGN_BT_VALID_ENABLE_FLAGS;
                priv->cur_rssi_ctx = NULL;
 
-               iwl_send_prio_tbl(trans(priv));
+               iwl_send_prio_tbl(priv);
 
                /* FIXME: w/a to force change uCode BT state machine */
-               ret = iwl_send_bt_env(trans(priv), IWL_BT_COEX_ENV_OPEN,
+               ret = iwl_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN,
                                         BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
                if (ret)
                        return ret;
-               ret = iwl_send_bt_env(trans(priv), IWL_BT_COEX_ENV_CLOSE,
+               ret = iwl_send_bt_env(priv, IWL_BT_COEX_ENV_CLOSE,
                                         BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
                if (ret)
                        return ret;
@@ -701,9 +697,9 @@ int iwl_alive_start(struct iwl_priv *priv)
        priv->active_rate = IWL_RATES_MASK;
 
        /* Configure Tx antenna selection based on H/W config */
-       iwlagn_send_tx_ant_config(priv, cfg(priv)->valid_tx_ant);
+       iwlagn_send_tx_ant_config(priv, hw_params(priv).valid_tx_ant);
 
-       if (iwl_is_associated_ctx(ctx) && !priv->shrd->wowlan) {
+       if (iwl_is_associated_ctx(ctx) && !priv->wowlan) {
                struct iwl_rxon_cmd *active_rxon =
                                (struct iwl_rxon_cmd *)&ctx->active;
                /* apply any changes in staging */
@@ -718,12 +714,12 @@ int iwl_alive_start(struct iwl_priv *priv)
                iwlagn_set_rxon_chain(priv, ctx);
        }
 
-       if (!priv->shrd->wowlan) {
+       if (!priv->wowlan) {
                /* WoWLAN ucode will not reply in the same way, skip it */
                iwl_reset_run_time_calib(priv);
        }
 
-       set_bit(STATUS_READY, &priv->shrd->status);
+       set_bit(STATUS_READY, &priv->status);
 
        /* Configure the adapter for unassociated operation */
        ret = iwlagn_commit_rxon(priv, ctx);
@@ -738,14 +734,48 @@ int iwl_alive_start(struct iwl_priv *priv)
        return iwl_power_update_mode(priv, true);
 }
 
-static void iwl_cancel_deferred_work(struct iwl_priv *priv);
+/**
+ * iwl_clear_driver_stations - clear knowledge of all stations from driver
+ * @priv: iwl priv struct
+ *
+ * This is called during iwl_down() to make sure that in the case
+ * we're coming there from a hardware restart mac80211 will be
+ * able to reconfigure stations -- if we're getting there in the
+ * normal down flow then the stations will already be cleared.
+ */
+static void iwl_clear_driver_stations(struct iwl_priv *priv)
+{
+       struct iwl_rxon_context *ctx;
+
+       spin_lock_bh(&priv->sta_lock);
+       memset(priv->stations, 0, sizeof(priv->stations));
+       priv->num_stations = 0;
+
+       priv->ucode_key_table = 0;
 
-void __iwl_down(struct iwl_priv *priv)
+       for_each_context(priv, ctx) {
+               /*
+                * Remove all key information that is not stored as part
+                * of station information since mac80211 may not have had
+                * a chance to remove all the keys. When device is
+                * reconfigured by mac80211 after an error all keys will
+                * be reconfigured.
+                */
+               memset(ctx->wep_keys, 0, sizeof(ctx->wep_keys));
+               ctx->key_mapping_keys = 0;
+       }
+
+       spin_unlock_bh(&priv->sta_lock);
+}
+
+void iwl_down(struct iwl_priv *priv)
 {
        int exit_pending;
 
        IWL_DEBUG_INFO(priv, DRV_NAME " is going down\n");
 
+       lockdep_assert_held(&priv->mutex);
+
        iwl_scan_cancel_timeout(priv, 200);
 
        /*
@@ -756,7 +786,7 @@ void __iwl_down(struct iwl_priv *priv)
        ieee80211_remain_on_channel_expired(priv->hw);
 
        exit_pending =
-               test_and_set_bit(STATUS_EXIT_PENDING, &priv->shrd->status);
+               test_and_set_bit(STATUS_EXIT_PENDING, &priv->status);
 
        /* Stop TX queues watchdog. We need to have STATUS_EXIT_PENDING bit set
         * to prevent rearm timer */
@@ -781,7 +811,7 @@ void __iwl_down(struct iwl_priv *priv)
        /* Wipe out the EXIT_PENDING status bit if we are not actually
         * exiting the module */
        if (!exit_pending)
-               clear_bit(STATUS_EXIT_PENDING, &priv->shrd->status);
+               clear_bit(STATUS_EXIT_PENDING, &priv->status);
 
        if (priv->mac80211_registered)
                ieee80211_stop_queues(priv->hw);
@@ -789,29 +819,20 @@ void __iwl_down(struct iwl_priv *priv)
        iwl_trans_stop_device(trans(priv));
 
        /* Clear out all status bits but a few that are stable across reset */
-       priv->shrd->status &=
-                       test_bit(STATUS_RF_KILL_HW, &priv->shrd->status) <<
+       priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) <<
                                STATUS_RF_KILL_HW |
-                       test_bit(STATUS_GEO_CONFIGURED, &priv->shrd->status) <<
+                       test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
                                STATUS_GEO_CONFIGURED |
-                       test_bit(STATUS_FW_ERROR, &priv->shrd->status) <<
-                               STATUS_FW_ERROR |
-                       test_bit(STATUS_EXIT_PENDING, &priv->shrd->status) <<
+                       test_bit(STATUS_EXIT_PENDING, &priv->status) <<
                                STATUS_EXIT_PENDING;
+       priv->shrd->status &=
+                       test_bit(STATUS_FW_ERROR, &priv->shrd->status) <<
+                               STATUS_FW_ERROR;
 
        dev_kfree_skb(priv->beacon_skb);
        priv->beacon_skb = NULL;
 }
 
-void iwl_down(struct iwl_priv *priv)
-{
-       mutex_lock(&priv->shrd->mutex);
-       __iwl_down(priv);
-       mutex_unlock(&priv->shrd->mutex);
-
-       iwl_cancel_deferred_work(priv);
-}
-
 /*****************************************************************************
  *
  * Workqueue callbacks
@@ -823,11 +844,11 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work)
        struct iwl_priv *priv = container_of(work, struct iwl_priv,
                        run_time_calib_work);
 
-       mutex_lock(&priv->shrd->mutex);
+       mutex_lock(&priv->mutex);
 
-       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status) ||
-           test_bit(STATUS_SCANNING, &priv->shrd->status)) {
-               mutex_unlock(&priv->shrd->mutex);
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
+           test_bit(STATUS_SCANNING, &priv->status)) {
+               mutex_unlock(&priv->mutex);
                return;
        }
 
@@ -836,7 +857,7 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work)
                iwl_sensitivity_calibration(priv);
        }
 
-       mutex_unlock(&priv->shrd->mutex);
+       mutex_unlock(&priv->mutex);
 }
 
 void iwlagn_prepare_restart(struct iwl_priv *priv)
@@ -848,7 +869,7 @@ void iwlagn_prepare_restart(struct iwl_priv *priv)
        u8 bt_status;
        bool bt_is_sco;
 
-       lockdep_assert_held(&priv->shrd->mutex);
+       lockdep_assert_held(&priv->mutex);
 
        for_each_context(priv, ctx)
                ctx->vif = NULL;
@@ -869,7 +890,7 @@ void iwlagn_prepare_restart(struct iwl_priv *priv)
        bt_status = priv->bt_status;
        bt_is_sco = priv->bt_is_sco;
 
-       __iwl_down(priv);
+       iwl_down(priv);
 
        priv->bt_full_concurrent = bt_full_concurrent;
        priv->bt_ci_compliance = bt_ci_compliance;
@@ -882,13 +903,13 @@ static void iwl_bg_restart(struct work_struct *data)
 {
        struct iwl_priv *priv = container_of(data, struct iwl_priv, restart);
 
-       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
        if (test_and_clear_bit(STATUS_FW_ERROR, &priv->shrd->status)) {
-               mutex_lock(&priv->shrd->mutex);
+               mutex_lock(&priv->mutex);
                iwlagn_prepare_restart(priv);
-               mutex_unlock(&priv->shrd->mutex);
+               mutex_unlock(&priv->mutex);
                iwl_cancel_deferred_work(priv);
                ieee80211_restart_hw(priv->hw);
        } else {
@@ -903,7 +924,7 @@ 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);
+       lockdep_assert_held(&priv->mutex);
 
        if (!priv->hw_roc_setup)
                return;
@@ -926,9 +947,9 @@ 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);
+       mutex_lock(&priv->mutex);
        iwlagn_disable_roc(priv);
-       mutex_unlock(&priv->shrd->mutex);
+       mutex_unlock(&priv->mutex);
 }
 
 /*****************************************************************************
@@ -939,7 +960,7 @@ static void iwlagn_disable_roc_work(struct work_struct *work)
 
 static void iwl_setup_deferred_work(struct iwl_priv *priv)
 {
-       priv->shrd->workqueue = create_singlethread_workqueue(DRV_NAME);
+       priv->workqueue = create_singlethread_workqueue(DRV_NAME);
 
        init_waitqueue_head(&priv->shrd->wait_command_queue);
 
@@ -954,8 +975,8 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
 
        iwl_setup_scan_deferred_work(priv);
 
-       if (cfg(priv)->lib->bt_setup_deferred_work)
-               cfg(priv)->lib->bt_setup_deferred_work(priv);
+       if (cfg(priv)->bt_params)
+               iwlagn_bt_setup_deferred_work(priv);
 
        init_timer(&priv->statistics_periodic);
        priv->statistics_periodic.data = (unsigned long)priv;
@@ -970,10 +991,10 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
        priv->watchdog.function = iwl_bg_watchdog;
 }
 
-static void iwl_cancel_deferred_work(struct iwl_priv *priv)
+void iwl_cancel_deferred_work(struct iwl_priv *priv)
 {
-       if (cfg(priv)->lib->cancel_deferred_work)
-               cfg(priv)->lib->cancel_deferred_work(priv);
+       if (cfg(priv)->bt_params)
+               iwlagn_bt_cancel_deferred_work(priv);
 
        cancel_work_sync(&priv->run_time_calib_work);
        cancel_work_sync(&priv->beacon_update);
@@ -988,8 +1009,7 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
        del_timer_sync(&priv->ucode_trace);
 }
 
-static void iwl_init_hw_rates(struct iwl_priv *priv,
-                             struct ieee80211_rate *rates)
+static void iwl_init_hw_rates(struct ieee80211_rate *rates)
 {
        int i;
 
@@ -1013,21 +1033,26 @@ static int iwl_init_drv(struct iwl_priv *priv)
 {
        int ret;
 
-       spin_lock_init(&priv->shrd->sta_lock);
+       spin_lock_init(&priv->sta_lock);
 
-       mutex_init(&priv->shrd->mutex);
+       mutex_init(&priv->mutex);
 
-       INIT_LIST_HEAD(&trans(priv)->calib_results);
+       INIT_LIST_HEAD(&priv->calib_results);
 
        priv->ieee_channels = NULL;
        priv->ieee_rates = NULL;
        priv->band = IEEE80211_BAND_2GHZ;
 
+       priv->plcp_delta_threshold =
+               cfg(priv)->base_params->plcp_delta_threshold;
+
        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;
 
+       priv->ucode_owner = IWL_OWNERSHIP_DRIVER;
+
        /* initialize force reset */
        priv->force_reset[IWL_RF_RESET].reset_duration =
                IWL_DELAY_NEXT_FORCE_RF_RESET;
@@ -1063,7 +1088,7 @@ static int iwl_init_drv(struct iwl_priv *priv)
                IWL_ERR(priv, "initializing geos failed: %d\n", ret);
                goto err_free_channel_map;
        }
-       iwl_init_hw_rates(priv, priv->ieee_rates);
+       iwl_init_hw_rates(priv->ieee_rates);
 
        return 0;
 
@@ -1077,11 +1102,10 @@ static void iwl_uninit_drv(struct iwl_priv *priv)
 {
        iwl_free_geos(priv);
        iwl_free_channel_map(priv);
-       if (priv->tx_cmd_pool)
-               kmem_cache_destroy(priv->tx_cmd_pool);
        kfree(priv->scan_cmd);
        kfree(priv->beacon_cmd);
        kfree(rcu_dereference_raw(priv->noa_data));
+       iwl_calib_free_results(priv);
 #ifdef CONFIG_IWLWIFI_DEBUGFS
        kfree(priv->wowlan_sram);
 #endif
@@ -1091,8 +1115,12 @@ static void iwl_uninit_drv(struct iwl_priv *priv)
 #define IWL_RX_BUF_SIZE_4K (4 * 1024)
 #define IWL_RX_BUF_SIZE_8K (8 * 1024)
 
-static int iwl_set_hw_params(struct iwl_priv *priv)
+static void iwl_set_hw_params(struct iwl_priv *priv)
 {
+       if (cfg(priv)->ht_params)
+               hw_params(priv).use_rts_for_aggregation =
+                       cfg(priv)->ht_params->use_rts_for_aggregation;
+
        if (iwlagn_mod_params.amsdu_size_8K)
                hw_params(priv).rx_page_order =
                        get_order(IWL_RX_BUF_SIZE_8K);
@@ -1101,17 +1129,14 @@ static int iwl_set_hw_params(struct iwl_priv *priv)
                        get_order(IWL_RX_BUF_SIZE_4K);
 
        if (iwlagn_mod_params.disable_11n & IWL_DISABLE_HT_ALL)
-               cfg(priv)->sku &= ~EEPROM_SKU_CAP_11N_ENABLE;
+               hw_params(priv).sku &= ~EEPROM_SKU_CAP_11N_ENABLE;
 
        hw_params(priv).num_ampdu_queues =
                cfg(priv)->base_params->num_of_ampdu_queues;
-       hw_params(priv).shadow_reg_enable =
-               cfg(priv)->base_params->shadow_reg_enable;
-       hw_params(priv).sku = cfg(priv)->sku;
        hw_params(priv).wd_timeout = cfg(priv)->base_params->wd_timeout;
 
        /* Device-specific setup */
-       return cfg(priv)->lib->set_hw_params(priv);
+       cfg(priv)->lib->set_hw_params(priv);
 }
 
 
@@ -1151,37 +1176,67 @@ static void iwl_debug_config(struct iwl_priv *priv)
 #endif
 }
 
-int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops,
-               struct iwl_cfg *cfg)
+static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
+                                                const struct iwl_fw *fw)
 {
        int err = 0;
        struct iwl_priv *priv;
        struct ieee80211_hw *hw;
+       struct iwl_op_mode *op_mode;
        u16 num_mac;
+       u32 ucode_flags;
+       struct iwl_trans_config trans_cfg;
 
        /************************
         * 1. Allocating HW data
         ************************/
        hw = iwl_alloc_all();
        if (!hw) {
-               pr_err("%s: Cannot allocate network device\n", cfg->name);
+               pr_err("%s: Cannot allocate network device\n",
+                               cfg(trans)->name);
                err = -ENOMEM;
                goto out;
        }
 
-       priv = hw->priv;
-       priv->shrd = bus->shrd;
-       priv->shrd->priv = priv;
+       op_mode = hw->priv;
+       op_mode->ops = &iwl_dvm_ops;
+       priv = IWL_OP_MODE_GET_DVM(op_mode);
+       priv->shrd = trans->shrd;
+       priv->fw = fw;
+       /* TODO: remove fw from shared data later */
+       priv->shrd->fw = fw;
+
+       /*
+        * Populate the state variables that the transport layer needs
+        * to know about.
+        */
+       trans_cfg.op_mode = op_mode;
+
+       ucode_flags = fw->ucode_capa.flags;
+
+#ifndef CONFIG_IWLWIFI_P2P
+       ucode_flags &= ~IWL_UCODE_TLV_FLAGS_PAN;
+#endif
+
+       if (ucode_flags & IWL_UCODE_TLV_FLAGS_PAN) {
+               priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN;
+               trans_cfg.cmd_queue = IWL_IPAN_CMD_QUEUE_NUM;
+       } else {
+               priv->sta_key_max_num = STA_KEY_MAX_NUM;
+               trans_cfg.cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM;
+       }
+
+       /* Configure transport layer */
+       iwl_trans_configure(trans(priv), &trans_cfg);
 
        /* At this point both hw and priv are allocated. */
 
-       SET_IEEE80211_DEV(hw, trans(priv)->dev);
+       SET_IEEE80211_DEV(priv->hw, trans(priv)->dev);
 
        /* show what debugging capabilities we have */
        iwl_debug_config(priv);
 
        IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n");
-       cfg(priv) = cfg;
 
        /* is antenna coupling more than 35dB ? */
        priv->bt_ant_couple_ok =
@@ -1201,10 +1256,10 @@ int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops,
         * we should init now
         */
        spin_lock_init(&trans(priv)->reg_lock);
-       spin_lock_init(&priv->shrd->lock);
+       spin_lock_init(&priv->statistics.lock);
 
        /***********************
-        * 3. Read REV register
+        * 2. Read REV register
         ***********************/
        IWL_INFO(priv, "Detected %s, REV=0x%X\n",
                cfg(priv)->name, trans(priv)->hw_rev);
@@ -1214,10 +1269,9 @@ int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops,
                goto out_free_traffic_mem;
 
        /*****************
-        * 4. Read EEPROM
+        * 3. Read EEPROM
         *****************/
-       /* Read the EEPROM */
-       err = iwl_eeprom_init(priv, trans(priv)->hw_rev);
+       err = iwl_eeprom_init(trans(priv), trans(priv)->hw_rev);
        /* Reset chip to save power until we load uCode during "up". */
        iwl_trans_stop_hw(trans(priv));
        if (err) {
@@ -1228,7 +1282,7 @@ int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops,
        if (err)
                goto out_free_eeprom;
 
-       err = iwl_eeprom_check_sku(priv);
+       err = iwl_eeprom_init_hw_params(priv);
        if (err)
                goto out_free_eeprom;
 
@@ -1246,16 +1300,27 @@ int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops,
        }
 
        /************************
-        * 5. Setup HW constants
+        * 4. Setup HW constants
         ************************/
-       if (iwl_set_hw_params(priv)) {
-               err = -ENOENT;
-               IWL_ERR(priv, "failed to set hw parameters\n");
-               goto out_free_eeprom;
+       iwl_set_hw_params(priv);
+
+       if (!(hw_params(priv).sku & EEPROM_SKU_CAP_IPAN_ENABLE)) {
+               IWL_DEBUG_INFO(priv, "Your EEPROM disabled PAN");
+               ucode_flags &= ~IWL_UCODE_TLV_FLAGS_PAN;
+               /*
+                * if not PAN, then don't support P2P -- might be a uCode
+                * packaging bug or due to the eeprom check above
+                */
+               ucode_flags &= ~IWL_UCODE_TLV_FLAGS_P2P;
+               priv->sta_key_max_num = STA_KEY_MAX_NUM;
+               trans_cfg.cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM;
+
+               /* Configure transport layer again*/
+               iwl_trans_configure(trans(priv), &trans_cfg);
        }
 
        /*******************
-        * 6. Setup priv
+        * 5. Setup priv
         *******************/
 
        err = iwl_init_drv(priv);
@@ -1264,7 +1329,7 @@ int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops,
        /* At this point both hw and priv are initialized. */
 
        /********************
-        * 7. Setup services
+        * 6. Setup services
         ********************/
        iwl_setup_deferred_work(priv);
        iwl_setup_rx_handlers(priv);
@@ -1273,17 +1338,41 @@ int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops,
        iwl_power_initialize(priv);
        iwl_tt_initialize(priv);
 
-       init_completion(&priv->firmware_loading_complete);
+       snprintf(priv->hw->wiphy->fw_version,
+                sizeof(priv->hw->wiphy->fw_version),
+                "%s", fw->fw_version);
+
+       priv->new_scan_threshold_behaviour =
+               !!(ucode_flags & IWL_UCODE_TLV_FLAGS_NEWSCAN);
+
+       priv->phy_calib_chain_noise_reset_cmd =
+               fw->ucode_capa.standard_phy_calibration_size;
+       priv->phy_calib_chain_noise_gain_cmd =
+               fw->ucode_capa.standard_phy_calibration_size + 1;
 
-       err = iwl_request_firmware(priv, true);
+       /* initialize all valid contexts */
+       iwl_init_context(priv, ucode_flags);
+
+       /**************************************************
+        * This is still part of probe() in a sense...
+        *
+        * 7. Setup and register with mac80211 and debugfs
+        **************************************************/
+       err = iwlagn_mac_setup_register(priv, &fw->ucode_capa);
        if (err)
                goto out_destroy_workqueue;
 
-       return 0;
+       err = iwl_dbgfs_register(priv, DRV_NAME);
+       if (err)
+               IWL_ERR(priv,
+                       "failed to create debugfs files. Ignoring error: %d\n",
+                       err);
+
+       return op_mode;
 
 out_destroy_workqueue:
-       destroy_workqueue(priv->shrd->workqueue);
-       priv->shrd->workqueue = NULL;
+       destroy_workqueue(priv->workqueue);
+       priv->workqueue = NULL;
        iwl_uninit_drv(priv);
 out_free_eeprom:
        iwl_eeprom_free(priv->shrd);
@@ -1291,23 +1380,18 @@ out_free_traffic_mem:
        iwl_free_traffic_mem(priv);
        ieee80211_free_hw(priv->hw);
 out:
-       return err;
+       op_mode = NULL;
+       return op_mode;
 }
 
-void __devexit iwl_remove(struct iwl_priv * priv)
+static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode)
 {
-       wait_for_completion(&priv->firmware_loading_complete);
+       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
 
        IWL_DEBUG_INFO(priv, "*** UNLOAD DRIVER ***\n");
 
        iwl_dbgfs_unregister(priv);
 
-       /* ieee80211_unregister_hw call wil cause iwlagn_mac_stop to
-        * to be called and iwl_down since we are removing the device
-        * we need to set STATUS_EXIT_PENDING bit.
-        */
-       set_bit(STATUS_EXIT_PENDING, &priv->shrd->status);
-
        iwl_testmode_cleanup(priv);
        iwlagn_mac_unregister(priv);
 
@@ -1316,18 +1400,16 @@ 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(trans(priv));
-
        iwl_eeprom_free(priv->shrd);
 
        /*netif_stop_queue(dev); */
-       flush_workqueue(priv->shrd->workqueue);
+       flush_workqueue(priv->workqueue);
 
        /* ieee80211_unregister_hw calls iwlagn_mac_stop, which flushes
-        * priv->shrd->workqueue... so we can't take down the workqueue
+        * priv->workqueue... so we can't take down the workqueue
         * until now... */
-       destroy_workqueue(priv->shrd->workqueue);
-       priv->shrd->workqueue = NULL;
+       destroy_workqueue(priv->workqueue);
+       priv->workqueue = NULL;
        iwl_free_traffic_mem(priv);
 
        iwl_uninit_drv(priv);
@@ -1337,12 +1419,81 @@ void __devexit iwl_remove(struct iwl_priv * priv)
        ieee80211_free_hw(priv->hw);
 }
 
+static void iwl_cmd_queue_full(struct iwl_op_mode *op_mode)
+{
+       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+
+       if (!iwl_check_for_ct_kill(priv)) {
+               IWL_ERR(priv, "Restarting adapter queue is full\n");
+               iwl_nic_error(op_mode);
+       }
+}
+
+static void iwl_nic_config(struct iwl_op_mode *op_mode)
+{
+       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+
+       cfg(priv)->lib->nic_config(priv);
+}
+
+static void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, u8 ac)
+{
+       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+
+       set_bit(ac, &priv->transport_queue_stop);
+       ieee80211_stop_queue(priv->hw, ac);
+}
+
+static void iwl_wake_sw_queue(struct iwl_op_mode *op_mode, u8 ac)
+{
+       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+
+       clear_bit(ac, &priv->transport_queue_stop);
+
+       if (!priv->passive_no_rx)
+               ieee80211_wake_queue(priv->hw, ac);
+}
+
+void iwlagn_lift_passive_no_rx(struct iwl_priv *priv)
+{
+       int ac;
+
+       if (!priv->passive_no_rx)
+               return;
+
+       for (ac = IEEE80211_AC_VO; ac < IEEE80211_NUM_ACS; ac++) {
+               if (!test_bit(ac, &priv->transport_queue_stop)) {
+                       IWL_DEBUG_TX_QUEUES(priv, "Wake queue %d");
+                       ieee80211_wake_queue(priv->hw, ac);
+               } else {
+                       IWL_DEBUG_TX_QUEUES(priv, "Don't wake queue %d");
+               }
+       }
+
+       priv->passive_no_rx = false;
+}
+
+const struct iwl_op_mode_ops iwl_dvm_ops = {
+       .start = iwl_op_mode_dvm_start,
+       .stop = iwl_op_mode_dvm_stop,
+       .rx = iwl_rx_dispatch,
+       .queue_full = iwl_stop_sw_queue,
+       .queue_not_full = iwl_wake_sw_queue,
+       .hw_rf_kill = iwl_set_hw_rfkill_state,
+       .free_skb = iwl_free_skb,
+       .nic_error = iwl_nic_error,
+       .cmd_queue_full = iwl_cmd_queue_full,
+       .nic_config = iwl_nic_config,
+};
 
 /*****************************************************************************
  *
  * driver and module entry point
  *
  *****************************************************************************/
+
+struct kmem_cache *iwl_tx_cmd_pool;
+
 static int __init iwl_init(void)
 {
 
@@ -1350,20 +1501,27 @@ static int __init iwl_init(void)
        pr_info(DRV_DESCRIPTION ", " DRV_VERSION "\n");
        pr_info(DRV_COPYRIGHT "\n");
 
+       iwl_tx_cmd_pool = kmem_cache_create("iwl_dev_cmd",
+                                           sizeof(struct iwl_device_cmd),
+                                           sizeof(void *), 0, NULL);
+       if (!iwl_tx_cmd_pool)
+               return -ENOMEM;
+
        ret = iwlagn_rate_control_register();
        if (ret) {
                pr_err("Unable to register rate control algorithm: %d\n", ret);
-               return ret;
+               goto error_rc_register;
        }
 
        ret = iwl_pci_register_driver();
-
        if (ret)
-               goto error_register;
+               goto error_pci_register;
        return ret;
 
-error_register:
+error_pci_register:
        iwlagn_rate_control_unregister();
+error_rc_register:
+       kmem_cache_destroy(iwl_tx_cmd_pool);
        return ret;
 }
 
@@ -1371,6 +1529,7 @@ static void __exit iwl_exit(void)
 {
        iwl_pci_unregister_driver();
        iwlagn_rate_control_unregister();
+       kmem_cache_destroy(iwl_tx_cmd_pool);
 }
 
 module_exit(iwl_exit);
@@ -1384,8 +1543,6 @@ MODULE_PARM_DESC(debug, "debug output mask");
 
 module_param_named(swcrypto, iwlagn_mod_params.sw_crypto, int, S_IRUGO);
 MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])");
-module_param_named(queues_num, iwlagn_mod_params.num_of_queues, int, S_IRUGO);
-MODULE_PARM_DESC(queues_num, "number of hw queues.");
 module_param_named(11n_disable, iwlagn_mod_params.disable_11n, uint, S_IRUGO);
 MODULE_PARM_DESC(11n_disable,
        "disable 11n functionality, bitmap: 1: full, 2: agg TX, 4: agg RX");
index 37c325ff6e8cbea856ba6bbcf8f462365aa9ac34..3780a03f2716219197938c0815c10d048c9c914a 100644 (file)
 
 #include "iwl-dev.h"
 
-struct iwlagn_ucode_capabilities {
-       u32 max_probe_length;
-       u32 standard_phy_calibration_size;
-       u32 flags;
-};
+struct iwl_ucode_capabilities;
 
 extern struct ieee80211_ops iwlagn_hw_ops;
 
@@ -81,16 +77,31 @@ 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 iwl_cancel_deferred_work(struct iwl_priv *priv);
 void iwlagn_prepare_restart(struct iwl_priv *priv);
+void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb);
+int __must_check iwl_rx_dispatch(struct iwl_op_mode *op_mode,
+                                struct iwl_rx_cmd_buffer *rxb,
+                                struct iwl_device_cmd *cmd);
+void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state);
+void iwl_nic_error(struct iwl_op_mode *op_mode);
+
+bool iwl_check_for_ct_kill(struct iwl_priv *priv);
+
+void iwlagn_lift_passive_no_rx(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);
+                             const struct iwl_ucode_capabilities *capa);
 void iwlagn_mac_unregister(struct iwl_priv *priv);
 
+/* commands */
+int iwl_dvm_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
+int iwl_dvm_send_cmd_pdu(struct iwl_priv *priv, u8 id,
+                        u32 flags, u16 len, const void *data);
+
 /* RXON */
 int iwlagn_set_pan_params(struct iwl_priv *priv);
 int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
@@ -105,9 +116,18 @@ void iwlagn_config_ht40(struct ieee80211_conf *conf,
 
 /* uCode */
 int iwlagn_rx_calib_result(struct iwl_priv *priv,
-                           struct iwl_rx_mem_buffer *rxb,
+                           struct iwl_rx_cmd_buffer *rxb,
                            struct iwl_device_cmd *cmd);
-void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags);
+int iwl_send_bt_env(struct iwl_priv *priv, u8 action, u8 type);
+void iwl_send_prio_tbl(struct iwl_priv *priv);
+int iwl_init_alive_start(struct iwl_priv *priv);
+int iwl_run_init_ucode(struct iwl_priv *priv);
+int iwl_load_ucode_wait_alive(struct iwl_priv *priv,
+                             enum iwl_ucode_type ucode_type);
+int iwl_send_calib_results(struct iwl_priv *priv);
+int iwl_calib_set(struct iwl_priv *priv,
+                 const struct iwl_calib_hdr *cmd, int len);
+void iwl_calib_free_results(struct iwl_priv *priv);
 
 /* lib */
 int iwlagn_send_tx_power(struct iwl_priv *priv);
@@ -119,8 +139,7 @@ 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);
+int iwlagn_suspend(struct iwl_priv *priv, struct cfg80211_wowlan *wowlan);
 #endif
 
 /* rx */
@@ -137,9 +156,9 @@ int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif,
 int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
                       struct ieee80211_sta *sta, u16 tid);
 int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
-                                  struct iwl_rx_mem_buffer *rxb,
+                                  struct iwl_rx_cmd_buffer *rxb,
                                   struct iwl_device_cmd *cmd);
-int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
+int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
                               struct iwl_device_cmd *cmd);
 
 static inline u32 iwl_tx_status_to_mac80211(u32 status)
@@ -174,7 +193,7 @@ void iwlagn_disable_roc(struct iwl_priv *priv);
 /* bt coex */
 void iwlagn_send_advance_bt_config(struct iwl_priv *priv);
 int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
-                                 struct iwl_rx_mem_buffer *rxb,
+                                 struct iwl_rx_cmd_buffer *rxb,
                                  struct iwl_device_cmd *cmd);
 void iwlagn_bt_rx_handler_setup(struct iwl_priv *priv);
 void iwlagn_bt_setup_deferred_work(struct iwl_priv *priv);
@@ -215,6 +234,8 @@ 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);
+void iwl_deactivate_station(struct iwl_priv *priv, const u8 sta_id,
+                           const u8 *addr);
 u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
                    const u8 *addr, bool is_ap, struct ieee80211_sta *sta);
 
@@ -222,46 +243,12 @@ void iwl_sta_fill_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
                     u8 sta_id, struct iwl_link_quality_cmd *link_cmd);
 int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
                    struct iwl_link_quality_cmd *lq, u8 flags, bool init);
-void iwl_reprogram_ap_sta(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
-int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
+int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
                               struct iwl_device_cmd *cmd);
+int iwl_sta_update_ht(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                     struct ieee80211_sta *sta);
 
 
-/**
- * iwl_clear_driver_stations - clear knowledge of all stations from driver
- * @priv: iwl priv struct
- *
- * This is called during iwl_down() to make sure that in the case
- * we're coming there from a hardware restart mac80211 will be
- * able to reconfigure stations -- if we're getting there in the
- * normal down flow then the stations will already be cleared.
- */
-static inline void iwl_clear_driver_stations(struct iwl_priv *priv)
-{
-       unsigned long flags;
-       struct iwl_rxon_context *ctx;
-
-       spin_lock_irqsave(&priv->shrd->sta_lock, flags);
-       memset(priv->stations, 0, sizeof(priv->stations));
-       priv->num_stations = 0;
-
-       priv->ucode_key_table = 0;
-
-       for_each_context(priv, ctx) {
-               /*
-                * Remove all key information that is not stored as part
-                * of station information since mac80211 may not have had
-                * a chance to remove all the keys. When device is
-                * reconfigured by mac80211 after an error all keys will
-                * be reconfigured.
-                */
-               memset(ctx->wep_keys, 0, sizeof(ctx->wep_keys));
-               ctx->key_mapping_keys = 0;
-       }
-
-       spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
-}
-
 static inline int iwl_sta_id(struct ieee80211_sta *sta)
 {
        if (WARN_ON(!sta))
@@ -270,37 +257,6 @@ static inline int iwl_sta_id(struct ieee80211_sta *sta)
        return ((struct iwl_station_priv *)sta->drv_priv)->sta_id;
 }
 
-/**
- * iwl_sta_id_or_broadcast - return sta_id or broadcast sta
- * @priv: iwl priv
- * @context: the current context
- * @sta: mac80211 station
- *
- * In certain circumstances mac80211 passes a station pointer
- * that may be %NULL, for example during TX or key setup. In
- * that case, we need to use the broadcast station, so this
- * inline wraps that pattern.
- */
-static inline int iwl_sta_id_or_broadcast(struct iwl_priv *priv,
-                                         struct iwl_rxon_context *context,
-                                         struct ieee80211_sta *sta)
-{
-       int sta_id;
-
-       if (!sta)
-               return context->bcast_sta_id;
-
-       sta_id = iwl_sta_id(sta);
-
-       /*
-        * mac80211 should not be passing a partially
-        * initialised station!
-        */
-       WARN_ON(sta_id == IWL_INVALID_STATION);
-
-       return sta_id;
-}
-
 int iwlagn_alloc_bcast_station(struct iwl_priv *priv,
                               struct iwl_rxon_context *ctx);
 int iwlagn_add_bssid_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
@@ -350,7 +306,6 @@ static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags)
 }
 
 /* eeprom */
-void iwl_eeprom_enhanced_txpower(struct iwl_priv *priv);
 void iwl_eeprom_get_mac(const struct iwl_shared *shrd, u8 *mac);
 
 extern int iwl_alive_start(struct iwl_priv *priv);
@@ -387,4 +342,68 @@ void iwl_testmode_cleanup(struct iwl_priv *priv)
 }
 #endif
 
+#ifdef CONFIG_IWLWIFI_DEBUG
+void iwl_print_rx_config_cmd(struct iwl_priv *priv,
+                            enum iwl_rxon_context_id ctxid);
+#else
+static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv,
+                                          enum iwl_rxon_context_id ctxid)
+{
+}
+#endif
+
+/* status checks */
+
+static inline int iwl_is_ready(struct iwl_priv *priv)
+{
+       /* The adapter is 'ready' if READY and GEO_CONFIGURED bits are
+        * set but EXIT_PENDING is not */
+       return test_bit(STATUS_READY, &priv->status) &&
+              test_bit(STATUS_GEO_CONFIGURED, &priv->status) &&
+              !test_bit(STATUS_EXIT_PENDING, &priv->status);
+}
+
+static inline int iwl_is_alive(struct iwl_priv *priv)
+{
+       return test_bit(STATUS_ALIVE, &priv->status);
+}
+
+static inline int iwl_is_rfkill(struct iwl_priv *priv)
+{
+       return test_bit(STATUS_RF_KILL_HW, &priv->status);
+}
+
+static inline int iwl_is_ctkill(struct iwl_priv *priv)
+{
+       return test_bit(STATUS_CT_KILL, &priv->status);
+}
+
+static inline int iwl_is_ready_rf(struct iwl_priv *priv)
+{
+       if (iwl_is_rfkill(priv))
+               return 0;
+
+       return iwl_is_ready(priv);
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+#define IWL_DEBUG_QUIET_RFKILL(m, fmt, args...)        \
+do {                                                                   \
+       if (!iwl_is_rfkill((m)))                                        \
+               IWL_ERR(m, fmt, ##args);                                \
+       else                                                            \
+               __iwl_err(trans(m)->dev, true,                          \
+                         !iwl_have_debug_level(IWL_DL_RADIO),          \
+                         fmt, ##args);                                 \
+} while (0)
+#else
+#define IWL_DEBUG_QUIET_RFKILL(m, fmt, args...)        \
+do {                                                                   \
+       if (!iwl_is_rfkill((m)))                                        \
+               IWL_ERR(m, fmt, ##args);                                \
+       else                                                            \
+               __iwl_err(trans(m)->dev, true, true, fmt, ##args);      \
+} while (0)
+#endif                         /* CONFIG_IWLWIFI_DEBUG */
+
 #endif /* __iwl_agn_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-bus.h b/drivers/net/wireless/iwlwifi/iwl-bus.h
deleted file mode 100644 (file)
index 30965e0..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-/******************************************************************************
- *
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
- *
- * 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.GPL.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- * BSD LICENSE
- *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *  * Neither the name Intel Corporation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *****************************************************************************/
-#ifndef __iwl_bus_h__
-#define __iwl_bus_h__
-
-#include <linux/types.h>
-#include <linux/spinlock.h>
-
-/**
- * DOC: Bus layer - role and goal
- *
- * iwl-bus.h defines the API to the bus layer of the iwlwifi driver.
- * The bus layer is responsible for doing very basic bus operations that are
- * listed in the iwl_bus_ops structure.
- * The bus layer registers to the bus driver, advertises the supported HW and
- * gets notifications about enumeration, suspend, resume.
- * For the moment, the bus layer is not a linux kernel module as itself, and
- * the module_init function of the driver must call the bus specific
- * registration functions. These functions are listed at the end of this file.
- * For the moment, there is only one implementation of this interface: PCI-e.
- * This implementation is iwl-pci.c
- */
-
-/**
- * DOC: encapsulation and type safety
- *
- * The iwl_bus describes the data that is shared amongst all the bus layer
- * implementations. This data is visible to other layers. Data in the bus
- * specific area is not visible outside the bus specific implementation.
- * iwl_bus holds a pointer to iwl_shared which holds pointer to all the other
- * layers of the driver (iwl_priv, iwl_trans). In fact, this is the way to go
- * when the transport layer needs to call a function of another layer.
- *
- * In order to achieve encapsulation, iwl_priv cannot be dereferenced from the
- * bus layer. Type safety is still kept since functions that gets iwl_priv gets
- * a typed pointer (as opposed to void *).
- */
-
-/**
- * DOC: probe flow
- *
- * The module_init calls the bus specific registration function. The
- * registration to the bus layer will trigger an enumeration of the bus which
- * will call the bus specific probe function.
- * The first thing this function must do is to allocate the memory needed by
- * iwl_bus + the bus_specific data.
- * Once the bus specific probe function has configured the hardware, it
- * chooses the appropriate transport layer and calls iwl_probe that will run
- * the bus independent probe flow.
- *
- * Note: The bus specific code must set the following data in iwl_bus before it
- *       calls iwl_probe:
- *     * bus->dev
- *     * bus->irq
- *     * bus->ops
- */
-
-struct iwl_shared;
-struct iwl_bus;
-
-/**
- * struct iwl_bus - bus common data
- *
- * This data is common to all bus layer implementations.
- *
- * @ops - pointer to iwl_bus_ops
- * @shrd - pointer to iwl_shared which holds shared data from the upper layer
- *     NB: for the time being this needs to be set by the upper layer since
- *     it allocates the shared data
- */
-struct iwl_bus {
-       struct iwl_shared *shrd;
-
-       /* pointer to bus specific struct */
-       /*Ensure that this pointer will always be aligned to sizeof pointer */
-       char bus_specific[0] __attribute__((__aligned__(sizeof(void *))));
-};
-
-/*****************************************************
-* Bus layer registration functions
-******************************************************/
-int __must_check iwl_pci_register_driver(void);
-void iwl_pci_unregister_driver(void);
-
-#endif /* __iwl_bus_h__ */
index 957bc00cdaf0f469e07338983e10a74e7c368e10..82152311d73b3ebe5a89d3cdfac1732892327696 100644 (file)
  * This file declares the config structures for all devices.
  */
 
-extern struct iwl_cfg iwl5300_agn_cfg;
-extern struct iwl_cfg iwl5100_agn_cfg;
-extern struct iwl_cfg iwl5350_agn_cfg;
-extern struct iwl_cfg iwl5100_bgn_cfg;
-extern struct iwl_cfg iwl5100_abg_cfg;
-extern struct iwl_cfg iwl5150_agn_cfg;
-extern struct iwl_cfg iwl5150_abg_cfg;
-extern struct iwl_cfg iwl6005_2agn_cfg;
-extern struct iwl_cfg iwl6005_2abg_cfg;
-extern struct iwl_cfg iwl6005_2bg_cfg;
-extern struct iwl_cfg iwl6005_2agn_sff_cfg;
-extern struct iwl_cfg iwl6005_2agn_d_cfg;
-extern struct iwl_cfg iwl1030_bgn_cfg;
-extern struct iwl_cfg iwl1030_bg_cfg;
-extern struct iwl_cfg iwl6030_2agn_cfg;
-extern struct iwl_cfg iwl6030_2abg_cfg;
-extern struct iwl_cfg iwl6030_2bgn_cfg;
-extern struct iwl_cfg iwl6030_2bg_cfg;
-extern struct iwl_cfg iwl6000i_2agn_cfg;
-extern struct iwl_cfg iwl6000i_2abg_cfg;
-extern struct iwl_cfg iwl6000i_2bg_cfg;
-extern struct iwl_cfg iwl6000_3agn_cfg;
-extern struct iwl_cfg iwl6050_2agn_cfg;
-extern struct iwl_cfg iwl6050_2abg_cfg;
-extern struct iwl_cfg iwl6150_bgn_cfg;
-extern struct iwl_cfg iwl6150_bg_cfg;
-extern struct iwl_cfg iwl1000_bgn_cfg;
-extern struct iwl_cfg iwl1000_bg_cfg;
-extern struct iwl_cfg iwl100_bgn_cfg;
-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_2bgn_d_cfg;
-extern struct iwl_cfg iwl2030_2bgn_cfg;
-extern struct iwl_cfg iwl6035_2agn_cfg;
-extern struct iwl_cfg iwl105_bgn_cfg;
-extern struct iwl_cfg iwl105_bgn_d_cfg;
-extern struct iwl_cfg iwl135_bgn_cfg;
+extern const struct iwl_cfg iwl5300_agn_cfg;
+extern const struct iwl_cfg iwl5100_agn_cfg;
+extern const struct iwl_cfg iwl5350_agn_cfg;
+extern const struct iwl_cfg iwl5100_bgn_cfg;
+extern const struct iwl_cfg iwl5100_abg_cfg;
+extern const struct iwl_cfg iwl5150_agn_cfg;
+extern const struct iwl_cfg iwl5150_abg_cfg;
+extern const struct iwl_cfg iwl6005_2agn_cfg;
+extern const struct iwl_cfg iwl6005_2abg_cfg;
+extern const struct iwl_cfg iwl6005_2bg_cfg;
+extern const struct iwl_cfg iwl6005_2agn_sff_cfg;
+extern const struct iwl_cfg iwl6005_2agn_d_cfg;
+extern const struct iwl_cfg iwl6005_2agn_mow1_cfg;
+extern const struct iwl_cfg iwl6005_2agn_mow2_cfg;
+extern const struct iwl_cfg iwl1030_bgn_cfg;
+extern const struct iwl_cfg iwl1030_bg_cfg;
+extern const struct iwl_cfg iwl6030_2agn_cfg;
+extern const struct iwl_cfg iwl6030_2abg_cfg;
+extern const struct iwl_cfg iwl6030_2bgn_cfg;
+extern const struct iwl_cfg iwl6030_2bg_cfg;
+extern const struct iwl_cfg iwl6000i_2agn_cfg;
+extern const struct iwl_cfg iwl6000i_2abg_cfg;
+extern const struct iwl_cfg iwl6000i_2bg_cfg;
+extern const struct iwl_cfg iwl6000_3agn_cfg;
+extern const struct iwl_cfg iwl6050_2agn_cfg;
+extern const struct iwl_cfg iwl6050_2abg_cfg;
+extern const struct iwl_cfg iwl6150_bgn_cfg;
+extern const struct iwl_cfg iwl6150_bg_cfg;
+extern const struct iwl_cfg iwl1000_bgn_cfg;
+extern const struct iwl_cfg iwl1000_bg_cfg;
+extern const struct iwl_cfg iwl100_bgn_cfg;
+extern const struct iwl_cfg iwl100_bg_cfg;
+extern const struct iwl_cfg iwl130_bgn_cfg;
+extern const struct iwl_cfg iwl130_bg_cfg;
+extern const struct iwl_cfg iwl2000_2bgn_cfg;
+extern const struct iwl_cfg iwl2000_2bgn_d_cfg;
+extern const struct iwl_cfg iwl2030_2bgn_cfg;
+extern const struct iwl_cfg iwl6035_2agn_cfg;
+extern const struct iwl_cfg iwl105_bgn_cfg;
+extern const struct iwl_cfg iwl105_bgn_d_cfg;
+extern const struct iwl_cfg iwl135_bgn_cfg;
 
 #endif /* __iwl_pci_h__ */
index c20618d9226813d2e1b75654c2000522e181eebc..9ed73e5154be908a18662fb9493292233594e0d8 100644 (file)
 #ifndef __iwl_commands_h__
 #define __iwl_commands_h__
 
-#include <linux/etherdevice.h>
 #include <linux/ieee80211.h>
+#include <linux/types.h>
 
-struct iwl_priv;
-
-/* uCode version contains 4 values: Major/Minor/API/Serial */
-#define IWL_UCODE_MAJOR(ver)   (((ver) & 0xFF000000) >> 24)
-#define IWL_UCODE_MINOR(ver)   (((ver) & 0x00FF0000) >> 16)
-#define IWL_UCODE_API(ver)     (((ver) & 0x0000FF00) >> 8)
-#define IWL_UCODE_SERIAL(ver)  ((ver) & 0x000000FF)
-
-
-/* Tx rates */
-#define IWL_CCK_RATES  4
-#define IWL_OFDM_RATES 8
-#define IWL_MAX_RATES  (IWL_CCK_RATES + IWL_OFDM_RATES)
 
 enum {
        REPLY_ALIVE = 0x1,
@@ -213,48 +200,6 @@ enum {
 /* iwl_cmd_header flags value */
 #define IWL_CMD_FAILED_MSK 0x40
 
-#define SEQ_TO_QUEUE(s)        (((s) >> 8) & 0x1f)
-#define QUEUE_TO_SEQ(q)        (((q) & 0x1f) << 8)
-#define SEQ_TO_INDEX(s)        ((s) & 0xff)
-#define INDEX_TO_SEQ(i)        ((i) & 0xff)
-#define SEQ_RX_FRAME   cpu_to_le16(0x8000)
-
-/**
- * struct iwl_cmd_header
- *
- * This header format appears in the beginning of each command sent from the
- * driver, and each response/notification received from uCode.
- */
-struct iwl_cmd_header {
-       u8 cmd;         /* Command ID:  REPLY_RXON, etc. */
-       u8 flags;       /* 0:5 reserved, 6 abort, 7 internal */
-       /*
-        * The driver sets up the sequence number to values of its choosing.
-        * uCode does not use this value, but passes it back to the driver
-        * when sending the response to each driver-originated command, so
-        * the driver can match the response to the command.  Since the values
-        * don't get used by uCode, the driver may set up an arbitrary format.
-        *
-        * There is one exception:  uCode sets bit 15 when it originates
-        * the response/notification, i.e. when the response/notification
-        * is not a direct response to a command sent by the driver.  For
-        * example, uCode issues REPLY_RX when it sends a received frame
-        * to the driver; it is not a direct response to any driver command.
-        *
-        * The Linux driver uses the following format:
-        *
-        *  0:7         tfd index - position within TX queue
-        *  8:12        TX queue id
-        *  13:14       reserved
-        *  15          unsolicited RX or uCode-originated notification
-        */
-       __le16 sequence;
-
-       /* command or response/notification data follows immediately */
-       u8 data[0];
-} __packed;
-
-
 /**
  * iwlagn rate_n_flags bit fields
  *
@@ -3151,8 +3096,6 @@ struct iwl_enhance_sensitivity_cmd {
  */
 
 /* Phy calibration command for series */
-/* The default calibrate table size if not specified by firmware */
-#define IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE    18
 enum {
        IWL_PHY_CALIBRATE_DC_CMD                = 8,
        IWL_PHY_CALIBRATE_LO_CMD                = 9,
@@ -3161,11 +3104,8 @@ enum {
        IWL_PHY_CALIBRATE_BASE_BAND_CMD         = 16,
        IWL_PHY_CALIBRATE_TX_IQ_PERD_CMD        = 17,
        IWL_PHY_CALIBRATE_TEMP_OFFSET_CMD       = 18,
-       IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE = 19,
 };
 
-#define IWL_MAX_PHY_CALIBRATE_TBL_SIZE         (253)
-
 /* This enum defines the bitmap of various calibrations to enable in both
  * init ucode and runtime ucode through CALIBRATION_CFG_CMD.
  */
@@ -3905,50 +3845,6 @@ struct iwlagn_wowlan_kek_kck_material_cmd {
        __le64  replay_ctr;
 } __packed;
 
-/******************************************************************************
- * (13)
- * Union of all expected notifications/responses:
- *
- *****************************************************************************/
-#define FH_RSCSR_FRAME_SIZE_MSK        (0x00003FFF)    /* bits 0-13 */
-
-struct iwl_rx_packet {
-       /*
-        * The first 4 bytes of the RX frame header contain both the RX frame
-        * size and some flags.
-        * Bit fields:
-        * 31:    flag flush RB request
-        * 30:    flag ignore TC (terminal counter) request
-        * 29:    flag fast IRQ request
-        * 28-14: Reserved
-        * 13-00: RX frame size
-        */
-       __le32 len_n_flags;
-       struct iwl_cmd_header hdr;
-       union {
-               struct iwl_alive_resp alive_frame;
-               struct iwl_spectrum_notification spectrum_notif;
-               struct iwl_csa_notification csa_notif;
-               struct iwl_error_resp err_resp;
-               struct iwl_card_state_notif card_state_notif;
-               struct iwl_add_sta_resp add_sta;
-               struct iwl_rem_sta_resp rem_sta;
-               struct iwl_sleep_notification sleep_notif;
-               struct iwl_spectrum_resp spectrum;
-               struct iwl_notif_statistics stats;
-               struct iwl_bt_notif_statistics stats_bt;
-               struct iwl_compressed_ba_resp compressed_ba;
-               struct iwl_missed_beacon_notif missed_beacon;
-               struct iwl_coex_medium_notification coex_medium_notif;
-               struct iwl_coex_event_resp coex_event;
-               struct iwl_bt_coex_profile_notif bt_coex_profile_notif;
-               __le32 status;
-               u8 raw[0];
-       } u;
-} __packed;
-
-int iwl_agn_check_rxon_cmd(struct iwl_priv *priv);
-
 /*
  * REPLY_WIPAN_PARAMS = 0xb2 (Commands and Notification)
  */
index 0677b3dfbfb2de98b351db54666f37841d4daeb1..8b85940731f22992e51bca762727e5b5855e8420 100644 (file)
@@ -38,7 +38,6 @@
 #include "iwl-core.h"
 #include "iwl-io.h"
 #include "iwl-power.h"
-#include "iwl-agn.h"
 #include "iwl-shared.h"
 #include "iwl-agn.h"
 #include "iwl-trans.h"
@@ -114,7 +113,7 @@ int iwl_init_geos(struct iwl_priv *priv)
        if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates ||
            priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) {
                IWL_DEBUG_INFO(priv, "Geography modes already initialized.\n");
-               set_bit(STATUS_GEO_CONFIGURED, &priv->shrd->status);
+               set_bit(STATUS_GEO_CONFIGURED, &priv->status);
                return 0;
        }
 
@@ -137,7 +136,7 @@ int iwl_init_geos(struct iwl_priv *priv)
        sband->bitrates = &rates[IWL_FIRST_OFDM_RATE];
        sband->n_bitrates = IWL_RATE_COUNT_LEGACY - IWL_FIRST_OFDM_RATE;
 
-       if (cfg(priv)->sku & EEPROM_SKU_CAP_11N_ENABLE)
+       if (hw_params(priv).sku & EEPROM_SKU_CAP_11N_ENABLE)
                iwl_init_ht_hw_capab(priv, &sband->ht_cap,
                                         IEEE80211_BAND_5GHZ);
 
@@ -147,7 +146,7 @@ int iwl_init_geos(struct iwl_priv *priv)
        sband->bitrates = rates;
        sband->n_bitrates = IWL_RATE_COUNT_LEGACY;
 
-       if (cfg(priv)->sku & EEPROM_SKU_CAP_11N_ENABLE)
+       if (hw_params(priv).sku & EEPROM_SKU_CAP_11N_ENABLE)
                iwl_init_ht_hw_capab(priv, &sband->ht_cap,
                                         IEEE80211_BAND_2GHZ);
 
@@ -202,18 +201,18 @@ int iwl_init_geos(struct iwl_priv *priv)
        priv->tx_power_next = max_tx_power;
 
        if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) &&
-            cfg(priv)->sku & EEPROM_SKU_CAP_BAND_52GHZ) {
+            hw_params(priv).sku & EEPROM_SKU_CAP_BAND_52GHZ) {
                IWL_INFO(priv, "Incorrectly detected BG card as ABG. "
                        "Please send your %s to maintainer.\n",
                        trans(priv)->hw_id_str);
-               cfg(priv)->sku &= ~EEPROM_SKU_CAP_BAND_52GHZ;
+               hw_params(priv).sku &= ~EEPROM_SKU_CAP_BAND_52GHZ;
        }
 
        IWL_INFO(priv, "Tunable channels: %d 802.11bg, %d 802.11a channels\n",
                   priv->bands[IEEE80211_BAND_2GHZ].n_channels,
                   priv->bands[IEEE80211_BAND_5GHZ].n_channels);
 
-       set_bit(STATUS_GEO_CONFIGURED, &priv->shrd->status);
+       set_bit(STATUS_GEO_CONFIGURED, &priv->status);
 
        return 0;
 }
@@ -225,7 +224,7 @@ void iwl_free_geos(struct iwl_priv *priv)
 {
        kfree(priv->ieee_channels);
        kfree(priv->ieee_rates);
-       clear_bit(STATUS_GEO_CONFIGURED, &priv->shrd->status);
+       clear_bit(STATUS_GEO_CONFIGURED, &priv->status);
 }
 
 static bool iwl_is_channel_extension(struct iwl_priv *priv,
@@ -317,7 +316,7 @@ int iwl_send_rxon_timing(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
 
        conf = &priv->hw->conf;
 
-       lockdep_assert_held(&priv->shrd->mutex);
+       lockdep_assert_held(&priv->mutex);
 
        memset(&ctx->timing, 0, sizeof(struct iwl_rxon_time_cmd));
 
@@ -370,7 +369,7 @@ int iwl_send_rxon_timing(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
                        le32_to_cpu(ctx->timing.beacon_init_val),
                        le16_to_cpu(ctx->timing.atim_window));
 
-       return iwl_trans_send_cmd_pdu(trans(priv), ctx->rxon_timing_cmd,
+       return iwl_dvm_send_cmd_pdu(priv, ctx->rxon_timing_cmd,
                                CMD_SYNC, sizeof(ctx->timing), &ctx->timing);
 }
 
@@ -643,7 +642,7 @@ u8 iwl_get_single_channel_number(struct iwl_priv *priv,
  * NOTE:  Does not commit to the hardware; it sets appropriate bit fields
  * in the staging RXON flag structure based on the ch->band
  */
-int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch,
+void iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch,
                         struct iwl_rxon_context *ctx)
 {
        enum ieee80211_band band = ch->band;
@@ -651,7 +650,7 @@ int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch,
 
        if ((le16_to_cpu(ctx->staging.channel) == channel) &&
            (priv->band == band))
-               return 0;
+               return;
 
        ctx->staging.channel = cpu_to_le16(channel);
        if (band == IEEE80211_BAND_5GHZ)
@@ -663,7 +662,6 @@ int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch,
 
        IWL_DEBUG_INFO(priv, "Staging channel set to %d [%d]\n", channel, band);
 
-       return 0;
 }
 
 void iwl_set_flags_for_band(struct iwl_priv *priv,
@@ -800,11 +798,10 @@ void iwl_chswitch_done(struct iwl_priv *priv, bool is_success)
         */
        struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 
-       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
-       if (test_and_clear_bit(STATUS_CHANNEL_SWITCH_PENDING,
-                               &priv->shrd->status))
+       if (test_and_clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
                ieee80211_chswitch_done(ctx->vif, is_success);
 }
 
@@ -831,22 +828,27 @@ void iwl_print_rx_config_cmd(struct iwl_priv *priv,
 }
 #endif
 
-void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
+static void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
 {
        unsigned int reload_msec;
        unsigned long reload_jiffies;
 
+#ifdef CONFIG_IWLWIFI_DEBUG
+       if (iwl_have_debug_level(IWL_DL_FW_ERRORS))
+               iwl_print_rx_config_cmd(priv, IWL_RXON_CTX_BSS);
+#endif
+
        /* Set the FW error flag -- cleared on iwl_down */
        set_bit(STATUS_FW_ERROR, &priv->shrd->status);
 
        /* Cancel currently queued command. */
        clear_bit(STATUS_HCMD_ACTIVE, &priv->shrd->status);
 
-       iwl_abort_notification_waits(priv->shrd);
+       iwl_abort_notification_waits(&priv->notif_wait);
 
        /* Keep the restart process from trying to send host
         * commands by clearing the ready bit */
-       clear_bit(STATUS_READY, &priv->shrd->status);
+       clear_bit(STATUS_READY, &priv->status);
 
        wake_up(&priv->shrd->wait_command_queue);
 
@@ -871,11 +873,11 @@ void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
                        priv->reload_count = 0;
        }
 
-       if (!test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) {
+       if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) {
                if (iwlagn_mod_params.restart_fw) {
                        IWL_DEBUG_FW_ERRORS(priv,
                                  "Restarting adapter due to uCode error.\n");
-                       queue_work(priv->shrd->workqueue, &priv->restart);
+                       queue_work(priv->workqueue, &priv->restart);
                } else
                        IWL_DEBUG_FW_ERRORS(priv,
                                  "Detected FW error, but not restarting\n");
@@ -889,7 +891,7 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
        bool defer;
        struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 
-       lockdep_assert_held(&priv->shrd->mutex);
+       lockdep_assert_held(&priv->mutex);
 
        if (priv->tx_power_user_lmt == tx_power && !force)
                return 0;
@@ -909,7 +911,7 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
                return -EINVAL;
        }
 
-       if (!iwl_is_ready_rf(priv->shrd))
+       if (!iwl_is_ready_rf(priv))
                return -EIO;
 
        /* scan complete and commit_rxon use tx_power_next value,
@@ -917,7 +919,7 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
        priv->tx_power_next = tx_power;
 
        /* do not set tx power when scanning or channel changing */
-       defer = test_bit(STATUS_SCANNING, &priv->shrd->status) ||
+       defer = test_bit(STATUS_SCANNING, &priv->status) ||
                memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging));
        if (defer && !force) {
                IWL_DEBUG_INFO(priv, "Deferring tx power set\n");
@@ -955,7 +957,7 @@ void iwl_send_bt_config(struct iwl_priv *priv)
        IWL_DEBUG_INFO(priv, "BT coex %s\n",
                (bt_cmd.flags == BT_COEX_DISABLE) ? "disable" : "active");
 
-       if (iwl_trans_send_cmd_pdu(trans(priv), REPLY_BT_CONFIG,
+       if (iwl_dvm_send_cmd_pdu(priv, REPLY_BT_CONFIG,
                             CMD_SYNC, sizeof(struct iwl_bt_cmd), &bt_cmd))
                IWL_ERR(priv, "failed to send BT Coex Config\n");
 }
@@ -968,12 +970,12 @@ int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear)
        };
 
        if (flags & CMD_ASYNC)
-               return iwl_trans_send_cmd_pdu(trans(priv), REPLY_STATISTICS_CMD,
+               return iwl_dvm_send_cmd_pdu(priv, REPLY_STATISTICS_CMD,
                                              CMD_ASYNC,
                                               sizeof(struct iwl_statistics_cmd),
                                               &statistics_cmd);
        else
-               return iwl_trans_send_cmd_pdu(trans(priv), REPLY_STATISTICS_CMD,
+               return iwl_dvm_send_cmd_pdu(priv, REPLY_STATISTICS_CMD,
                                        CMD_SYNC,
                                        sizeof(struct iwl_statistics_cmd),
                                        &statistics_cmd);
@@ -1000,7 +1002,7 @@ int iwl_alloc_traffic_mem(struct iwl_priv *priv)
 {
        u32 traffic_size = IWL_TRAFFIC_DUMP_SIZE;
 
-       if (iwl_get_debug_level(priv->shrd) & IWL_DL_TX) {
+       if (iwl_have_debug_level(IWL_DL_TX)) {
                if (!priv->tx_traffic) {
                        priv->tx_traffic =
                                kzalloc(traffic_size, GFP_KERNEL);
@@ -1008,7 +1010,7 @@ int iwl_alloc_traffic_mem(struct iwl_priv *priv)
                                return -ENOMEM;
                }
        }
-       if (iwl_get_debug_level(priv->shrd) & IWL_DL_RX) {
+       if (iwl_have_debug_level(IWL_DL_RX)) {
                if (!priv->rx_traffic) {
                        priv->rx_traffic =
                                kzalloc(traffic_size, GFP_KERNEL);
@@ -1035,7 +1037,7 @@ void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv,
        __le16 fc;
        u16 len;
 
-       if (likely(!(iwl_get_debug_level(priv->shrd) & IWL_DL_TX)))
+       if (likely(!iwl_have_debug_level(IWL_DL_TX)))
                return;
 
        if (!priv->tx_traffic)
@@ -1059,7 +1061,7 @@ void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv,
        __le16 fc;
        u16 len;
 
-       if (likely(!(iwl_get_debug_level(priv->shrd) & IWL_DL_RX)))
+       if (likely(!iwl_have_debug_level(IWL_DL_RX)))
                return;
 
        if (!priv->rx_traffic)
@@ -1216,7 +1218,7 @@ void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len)
 
 static void iwl_force_rf_reset(struct iwl_priv *priv)
 {
-       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
        if (!iwl_is_any_associated(priv)) {
@@ -1241,7 +1243,7 @@ int iwl_force_reset(struct iwl_priv *priv, int mode, bool external)
 {
        struct iwl_force_reset *force_reset;
 
-       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return -EINVAL;
 
        if (mode >= IWL_MAX_FORCE_RESET) {
@@ -1297,7 +1299,7 @@ int iwl_cmd_echo_test(struct iwl_priv *priv)
                .flags = CMD_SYNC,
        };
 
-       ret = iwl_trans_send_cmd(trans(priv), &cmd);
+       ret = iwl_dvm_send_cmd(priv, &cmd);
        if (ret)
                IWL_ERR(priv, "echo testing fail: 0X%x\n", ret);
        else
@@ -1331,30 +1333,20 @@ void iwl_bg_watchdog(unsigned long data)
        int cnt;
        unsigned long timeout;
 
-       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
-       if (iwl_is_rfkill(priv->shrd))
+       if (iwl_is_rfkill(priv))
                return;
 
-       timeout = cfg(priv)->base_params->wd_timeout;
+       timeout = hw_params(priv).wd_timeout;
        if (timeout == 0)
                return;
 
-       /* monitor and check for stuck cmd queue */
-       if (iwl_check_stuck_queue(priv, priv->shrd->cmd_queue))
-               return;
-
-       /* monitor and check for other stuck queues */
-       if (iwl_is_any_associated(priv)) {
-               for (cnt = 0; cnt < hw_params(priv).max_txq_num; cnt++) {
-                       /* skip as we already checked the command queue */
-                       if (cnt == priv->shrd->cmd_queue)
-                               continue;
-                       if (iwl_check_stuck_queue(priv, cnt))
-                               return;
-               }
-       }
+       /* monitor and check for stuck queues */
+       for (cnt = 0; cnt < cfg(priv)->base_params->num_of_queues; cnt++)
+               if (iwl_check_stuck_queue(priv, cnt))
+                       return;
 
        mod_timer(&priv->watchdog, jiffies +
                  msecs_to_jiffies(IWL_WD_TICK(timeout)));
@@ -1362,7 +1354,7 @@ void iwl_bg_watchdog(unsigned long data)
 
 void iwl_setup_watchdog(struct iwl_priv *priv)
 {
-       unsigned int timeout = cfg(priv)->base_params->wd_timeout;
+       unsigned int timeout = hw_params(priv).wd_timeout;
 
        if (!iwlagn_mod_params.wd_disable) {
                /* use system default */
@@ -1456,31 +1448,30 @@ __le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base,
        return cpu_to_le32(res);
 }
 
-void iwl_set_hw_rfkill_state(struct iwl_priv *priv, bool state)
+void iwl_nic_error(struct iwl_op_mode *op_mode)
 {
-       wiphy_rfkill_set_hw_state(priv->hw->wiphy, state);
+       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+
+       iwlagn_fw_error(priv, false);
 }
 
-void iwl_nic_config(struct iwl_priv *priv)
+void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
 {
-       cfg(priv)->lib->nic_config(priv);
+       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+
+       if (state)
+               set_bit(STATUS_RF_KILL_HW, &priv->status);
+       else
+               clear_bit(STATUS_RF_KILL_HW, &priv->status);
+
+       wiphy_rfkill_set_hw_state(priv->hw->wiphy, state);
 }
 
-void iwl_free_skb(struct iwl_priv *priv, struct sk_buff *skb)
+void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb)
 {
        struct ieee80211_tx_info *info;
 
        info = IEEE80211_SKB_CB(skb);
-       kmem_cache_free(priv->tx_cmd_pool, (info->driver_data[1]));
+       kmem_cache_free(iwl_tx_cmd_pool, (info->driver_data[1]));
        dev_kfree_skb_any(skb);
 }
-
-void iwl_stop_sw_queue(struct iwl_priv *priv, u8 ac)
-{
-       ieee80211_stop_queue(priv->hw, ac);
-}
-
-void iwl_wake_sw_queue(struct iwl_priv *priv, u8 ac)
-{
-       ieee80211_wake_queue(priv->hw, ac);
-}
index 8d60dcf6f2eb87b10da6e33446c440b5a6609ead..635eb685edeb9308b35d0a2d015aaeb3db795cd0 100644 (file)
@@ -76,13 +76,7 @@ struct iwl_cmd;
 
 struct iwl_lib_ops {
        /* set hw dependent parameters */
-       int (*set_hw_params)(struct iwl_priv *priv);
-       /* setup BT Rx handler */
-       void (*bt_rx_handler_setup)(struct iwl_priv *priv);
-       /* setup BT related deferred work */
-       void (*bt_setup_deferred_work)(struct iwl_priv *priv);
-       /* cancel deferred work */
-       void (*cancel_deferred_work)(struct iwl_priv *priv);
+       void (*set_hw_params)(struct iwl_priv *priv);
        int (*set_channel_switch)(struct iwl_priv *priv,
                                  struct ieee80211_channel_switch *ch_switch);
        /* device specific configuration */
@@ -95,72 +89,6 @@ struct iwl_lib_ops {
        void (*temperature)(struct iwl_priv *priv);
 };
 
-/*
- * @max_ll_items: max number of OTP blocks
- * @shadow_ram_support: shadow support for OTP memory
- * @led_compensation: compensate on the led on/off time per HW according
- *     to the deviation to achieve the desired led frequency.
- *     The detail algorithm is described in iwl-led.c
- * @chain_noise_num_beacons: number of beacons used to compute chain noise
- * @adv_thermal_throttle: support advance thermal throttle
- * @support_ct_kill_exit: support ct kill exit condition
- * @support_wimax_coexist: support wimax/wifi co-exist
- * @plcp_delta_threshold: plcp error rate threshold used to trigger
- *     radio tuning when there is a high receiving plcp error rate
- * @chain_noise_scale: default chain noise scale used for gain computation
- * @wd_timeout: TX queues watchdog timeout
- * @max_event_log_size: size of event log buffer size for ucode event logging
- * @shadow_reg_enable: HW shadhow register bit
- * @no_idle_support: do not support idle mode
- * @hd_v2: v2 of enhanced sensitivity value, used for 2000 series and up
- * wd_disable: disable watchdog timer
- */
-struct iwl_base_params {
-       int eeprom_size;
-       int num_of_queues;      /* def: HW dependent */
-       int num_of_ampdu_queues;/* def: HW dependent */
-       /* for iwl_apm_init() */
-       u32 pll_cfg_val;
-
-       const u16 max_ll_items;
-       const bool shadow_ram_support;
-       u16 led_compensation;
-       bool adv_thermal_throttle;
-       bool support_ct_kill_exit;
-       const bool support_wimax_coexist;
-       u8 plcp_delta_threshold;
-       s32 chain_noise_scale;
-       unsigned int wd_timeout;
-       u32 max_event_log_size;
-       const bool shadow_reg_enable;
-       const bool no_idle_support;
-       const bool hd_v2;
-       const bool wd_disable;
-};
-/*
- * @advanced_bt_coexist: support advanced bt coexist
- * @bt_init_traffic_load: specify initial bt traffic load
- * @bt_prio_boost: default bt priority boost value
- * @agg_time_limit: maximum number of uSec in aggregation
- * @bt_sco_disable: uCode should not response to BT in SCO/ESCO mode
- */
-struct iwl_bt_params {
-       bool advanced_bt_coexist;
-       u8 bt_init_traffic_load;
-       u8 bt_prio_boost;
-       u16 agg_time_limit;
-       bool bt_sco_disable;
-       bool bt_session_2;
-};
-/*
- * @use_rts_for_aggregation: use rts/cts protection for HT traffic
- */
-struct iwl_ht_params {
-       const bool ht_greenfield_support; /* if used set to true */
-       bool use_rts_for_aggregation;
-       enum ieee80211_smps_mode smps_mode;
-};
-
 /***************************
  *   L i b                 *
  ***************************/
@@ -169,7 +97,7 @@ 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);
 int iwl_full_rxon_required(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
-int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch,
+void iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch,
                         struct iwl_rxon_context *ctx);
 void iwl_set_flags_for_band(struct iwl_priv *priv,
                            struct iwl_rxon_context *ctx,
@@ -197,6 +125,8 @@ const char *get_ctrl_string(int cmd);
 void iwl_clear_traffic_stats(struct iwl_priv *priv);
 void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc,
                      u16 len);
+void iwl_reset_traffic_log(struct iwl_priv *priv);
+
 #else
 static inline int iwl_alloc_traffic_mem(struct iwl_priv *priv)
 {
@@ -242,8 +172,6 @@ void iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
 void iwl_force_scan_end(struct iwl_priv *priv);
 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,
-                      const u8 *ta, const u8 *ie, int ie_len, int left);
 void iwl_setup_rx_scan_handlers(struct iwl_priv *priv);
 void iwl_setup_scan_deferred_work(struct iwl_priv *priv);
 void iwl_cancel_scan_deferred_work(struct iwl_priv *priv);
@@ -263,6 +191,10 @@ int __must_check iwl_scan_initiate(struct iwl_priv *priv,
 
 #define IWL_SCAN_CHECK_WATCHDOG                (HZ * 7)
 
+/* traffic log definitions */
+#define IWL_TRAFFIC_ENTRIES    (256)
+#define IWL_TRAFFIC_ENTRY_SIZE  (64)
+
 /*****************************************************
  *   S e n d i n g     H o s t     C o m m a n d s   *
  *****************************************************/
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.c b/drivers/net/wireless/iwlwifi/iwl-debug.c
new file mode 100644 (file)
index 0000000..059efab
--- /dev/null
@@ -0,0 +1,127 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved.
+ *
+ * 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.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#include <linux/interrupt.h>
+#include "iwl-debug.h"
+
+#define __iwl_fn(fn)                                           \
+void __iwl_ ##fn(struct device *dev, const char *fmt, ...)     \
+{                                                              \
+       struct va_format vaf = {                                \
+               .fmt = fmt,                                     \
+       };                                                      \
+       va_list args;                                           \
+                                                               \
+       va_start(args, fmt);                                    \
+       vaf.va = &args;                                         \
+       dev_ ##fn(dev, "%pV", &vaf);                            \
+       trace_iwlwifi_ ##fn(&vaf);                              \
+       va_end(args);                                           \
+}
+
+__iwl_fn(warn)
+__iwl_fn(info)
+__iwl_fn(crit)
+
+void __iwl_err(struct device *dev, bool rfkill_prefix, bool trace_only,
+               const char *fmt, ...)
+{
+       struct va_format vaf = {
+               .fmt = fmt,
+       };
+       va_list args;
+
+       va_start(args, fmt);
+       vaf.va = &args;
+       if (!trace_only) {
+               if (rfkill_prefix)
+                       dev_err(dev, "(RFKILL) %pV", &vaf);
+               else
+                       dev_err(dev, "%pV", &vaf);
+       }
+       trace_iwlwifi_err(&vaf);
+       va_end(args);
+}
+
+#if defined(CONFIG_IWLWIFI_DEBUG) || defined(CONFIG_IWLWIFI_DEVICE_TRACING)
+void __iwl_dbg(struct device *dev,
+              u32 level, bool limit, const char *function,
+              const char *fmt, ...)
+{
+       struct va_format vaf = {
+               .fmt = fmt,
+       };
+       va_list args;
+
+       va_start(args, fmt);
+       vaf.va = &args;
+#ifdef CONFIG_IWLWIFI_DEBUG
+       if (iwl_have_debug_level(level) &&
+           (!limit || net_ratelimit()))
+               dev_err(dev, "%c %s %pV", in_interrupt() ? 'I' : 'U',
+                       function, &vaf);
+#endif
+       trace_iwlwifi_dbg(level, in_interrupt(), function, &vaf);
+       va_end(args);
+}
+#endif
index 351b41d7f4fd11107068f770e7e6ea014034bdc9..a6b32a11e103092fd11ce2d074034fca9e23d854 100644 (file)
 #ifndef __iwl_debug_h__
 #define __iwl_debug_h__
 
-#include "iwl-bus.h"
 #include "iwl-shared.h"
+#include "iwl-devtrace.h"
 
 struct iwl_priv;
 
-/*No matter what is m (priv, bus, trans), this will work */
-#define IWL_ERR(m, f, a...) dev_err(trans(m)->dev, f, ## a)
-#define IWL_WARN(m, f, a...) dev_warn(trans(m)->dev, f, ## a)
-#define IWL_INFO(m, f, a...) dev_info(trans(m)->dev, f, ## a)
-#define IWL_CRIT(m, f, a...) dev_crit(trans(m)->dev, f, ## a)
+void __iwl_err(struct device *dev, bool rfkill_prefix, bool only_trace,
+               const char *fmt, ...);
+void __iwl_warn(struct device *dev, const char *fmt, ...);
+void __iwl_info(struct device *dev, const char *fmt, ...);
+void __iwl_crit(struct device *dev, const char *fmt, ...);
+
+/* No matter what is m (priv, bus, trans), this will work */
+#define IWL_ERR(m, f, a...) __iwl_err(trans(m)->dev, false, false, f, ## a)
+#define IWL_WARN(m, f, a...) __iwl_warn(trans(m)->dev, f, ## a)
+#define IWL_INFO(m, f, a...) __iwl_info(trans(m)->dev, f, ## a)
+#define IWL_CRIT(m, f, a...) __iwl_crit(trans(m)->dev, f, ## a)
+
+#if defined(CONFIG_IWLWIFI_DEBUG) || defined(CONFIG_IWLWIFI_DEVICE_TRACING)
+void __iwl_dbg(struct device *dev,
+              u32 level, bool limit, const char *function,
+              const char *fmt, ...);
+#else
+static inline void
+__iwl_dbg(struct device *dev,
+         u32 level, bool limit, const char *function,
+         const char *fmt, ...)
+{}
+#endif
 
 #define iwl_print_hex_error(m, p, len)                                 \
 do {                                                                   \
@@ -46,54 +64,20 @@ do {                                                                        \
                       DUMP_PREFIX_OFFSET, 16, 1, p, len, 1);           \
 } while (0)
 
-#ifdef CONFIG_IWLWIFI_DEBUG
-#define IWL_DEBUG(m, level, fmt, ...)                                  \
-do {                                                                   \
-       if (iwl_get_debug_level((m)->shrd) & (level))                   \
-               dev_err(trans(m)->dev, "%c %s " fmt,                    \
-                       in_interrupt() ? 'I' : 'U', __func__,           \
-                       ##__VA_ARGS__);                                 \
-} while (0)
-
-#define IWL_DEBUG_LIMIT(m, level, fmt, ...)                            \
-do {                                                                   \
-       if (iwl_get_debug_level((m)->shrd) & (level) &&                 \
-           net_ratelimit())                                            \
-               dev_err(trans(m)->dev, "%c %s " fmt,                    \
-                       in_interrupt() ? 'I' : 'U', __func__,           \
-                       ##__VA_ARGS__);                                 \
-} while (0)
+#define IWL_DEBUG(m, level, fmt, args...)                              \
+       __iwl_dbg(trans(m)->dev, level, false, __func__, fmt, ##args)
+#define IWL_DEBUG_LIMIT(m, level, fmt, args...)                                \
+       __iwl_dbg(trans(m)->dev, level, true, __func__, fmt, ##args)
 
+#ifdef CONFIG_IWLWIFI_DEBUG
 #define iwl_print_hex_dump(m, level, p, len)                           \
 do {                                                                   \
-       if (iwl_get_debug_level((m)->shrd) & level)                     \
+       if (iwl_have_debug_level(level))                                \
                print_hex_dump(KERN_DEBUG, "iwl data: ",                \
                               DUMP_PREFIX_OFFSET, 16, 1, p, len, 1);   \
 } while (0)
-
-#define IWL_DEBUG_QUIET_RFKILL(p, fmt, ...)                            \
-do {                                                                   \
-       if (!iwl_is_rfkill(p->shrd))                                    \
-               dev_err(trans(p)->dev, "%s%c %s " fmt,                  \
-                       "",                                             \
-                       in_interrupt() ? 'I' : 'U', __func__,           \
-                       ##__VA_ARGS__);                                 \
-       else if (iwl_get_debug_level(p->shrd) & IWL_DL_RADIO)           \
-               dev_err(trans(p)->dev, "%s%c %s " fmt,                  \
-                       "(RFKILL) ",                                    \
-                       in_interrupt() ? 'I' : 'U', __func__,           \
-                       ##__VA_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
index 136de6fb3fa4ae236be455353b140f5deffbfc7e..9b71c87847c2959b4c48196385c604bc431baabb 100644 (file)
@@ -234,12 +234,11 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
 
        /* default is to dump the entire data segment */
        if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) {
-               struct iwl_trans *trans = trans(priv);
                priv->dbgfs_sram_offset = 0x800000;
-               if (trans->shrd->ucode_type == IWL_UCODE_INIT)
-                       priv->dbgfs_sram_len = trans->ucode_init.data.len;
+               if (priv->shrd->ucode_type == IWL_UCODE_INIT)
+                       priv->dbgfs_sram_len = priv->fw->ucode_init.data.len;
                else
-                       priv->dbgfs_sram_len = trans->ucode_rt.data.len;
+                       priv->dbgfs_sram_len = priv->fw->ucode_rt.data.len;
        }
        len = priv->dbgfs_sram_len;
 
@@ -342,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,
-                                      trans(priv)->ucode_wowlan.data.len);
+                                      priv->fw->ucode_wowlan.data.len);
 }
 static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
                                        size_t count, loff_t *ppos)
@@ -455,7 +454,7 @@ static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf,
        char *buf;
        ssize_t ret;
 
-       if (!test_bit(STATUS_GEO_CONFIGURED, &priv->shrd->status))
+       if (!test_bit(STATUS_GEO_CONFIGURED, &priv->status))
                return -EAGAIN;
 
        buf = kzalloc(bufsz, GFP_KERNEL);
@@ -526,32 +525,26 @@ static ssize_t iwl_dbgfs_status_read(struct file *file,
 
        pos += scnprintf(buf + pos, bufsz - pos, "STATUS_HCMD_ACTIVE:\t %d\n",
                test_bit(STATUS_HCMD_ACTIVE, &priv->shrd->status));
-       pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INT_ENABLED:\t %d\n",
-               test_bit(STATUS_INT_ENABLED, &priv->shrd->status));
        pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_HW:\t %d\n",
-               test_bit(STATUS_RF_KILL_HW, &priv->shrd->status));
+               test_bit(STATUS_RF_KILL_HW, &priv->status));
        pos += scnprintf(buf + pos, bufsz - pos, "STATUS_CT_KILL:\t\t %d\n",
-               test_bit(STATUS_CT_KILL, &priv->shrd->status));
-       pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INIT:\t\t %d\n",
-               test_bit(STATUS_INIT, &priv->shrd->status));
+               test_bit(STATUS_CT_KILL, &priv->status));
        pos += scnprintf(buf + pos, bufsz - pos, "STATUS_ALIVE:\t\t %d\n",
-               test_bit(STATUS_ALIVE, &priv->shrd->status));
+               test_bit(STATUS_ALIVE, &priv->status));
        pos += scnprintf(buf + pos, bufsz - pos, "STATUS_READY:\t\t %d\n",
-               test_bit(STATUS_READY, &priv->shrd->status));
-       pos += scnprintf(buf + pos, bufsz - pos, "STATUS_TEMPERATURE:\t %d\n",
-               test_bit(STATUS_TEMPERATURE, &priv->shrd->status));
+               test_bit(STATUS_READY, &priv->status));
        pos += scnprintf(buf + pos, bufsz - pos, "STATUS_GEO_CONFIGURED:\t %d\n",
-               test_bit(STATUS_GEO_CONFIGURED, &priv->shrd->status));
+               test_bit(STATUS_GEO_CONFIGURED, &priv->status));
        pos += scnprintf(buf + pos, bufsz - pos, "STATUS_EXIT_PENDING:\t %d\n",
-               test_bit(STATUS_EXIT_PENDING, &priv->shrd->status));
+               test_bit(STATUS_EXIT_PENDING, &priv->status));
        pos += scnprintf(buf + pos, bufsz - pos, "STATUS_STATISTICS:\t %d\n",
-               test_bit(STATUS_STATISTICS, &priv->shrd->status));
+               test_bit(STATUS_STATISTICS, &priv->status));
        pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCANNING:\t %d\n",
-               test_bit(STATUS_SCANNING, &priv->shrd->status));
+               test_bit(STATUS_SCANNING, &priv->status));
        pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCAN_ABORTING:\t %d\n",
-               test_bit(STATUS_SCAN_ABORTING, &priv->shrd->status));
+               test_bit(STATUS_SCAN_ABORTING, &priv->status));
        pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCAN_HW:\t\t %d\n",
-               test_bit(STATUS_SCAN_HW, &priv->shrd->status));
+               test_bit(STATUS_SCAN_HW, &priv->status));
        pos += scnprintf(buf + pos, bufsz - pos, "STATUS_POWER_PMI:\t %d\n",
                test_bit(STATUS_POWER_PMI, &priv->shrd->status));
        pos += scnprintf(buf + pos, bufsz - pos, "STATUS_FW_ERROR:\t %d\n",
@@ -757,14 +750,14 @@ static ssize_t iwl_dbgfs_sleep_level_override_write(struct file *file,
        if (value != -1 && (value < 0 || value >= IWL_POWER_NUM))
                return -EINVAL;
 
-       if (!iwl_is_ready_rf(priv->shrd))
+       if (!iwl_is_ready_rf(priv))
                return -EAGAIN;
 
        priv->power_data.debug_sleep_level_override = value;
 
-       mutex_lock(&priv->shrd->mutex);
+       mutex_lock(&priv->mutex);
        iwl_power_update_mode(priv, true);
-       mutex_unlock(&priv->shrd->mutex);
+       mutex_unlock(&priv->mutex);
 
        return count;
 }
@@ -835,7 +828,7 @@ static ssize_t iwl_dbgfs_traffic_log_read(struct file *file,
 
        char *buf;
        int bufsz = ((IWL_TRAFFIC_ENTRIES * IWL_TRAFFIC_ENTRY_SIZE * 64) * 2) +
-               (hw_params(priv).max_txq_num * 32 * 8) + 400;
+               (cfg(priv)->base_params->num_of_queues * 32 * 8) + 400;
        const u8 *ptr;
        ssize_t ret;
 
@@ -844,8 +837,7 @@ static ssize_t iwl_dbgfs_traffic_log_read(struct file *file,
                IWL_ERR(priv, "Can not allocate buffer\n");
                return -ENOMEM;
        }
-       if (priv->tx_traffic &&
-               (iwl_get_debug_level(priv->shrd) & IWL_DL_TX)) {
+       if (priv->tx_traffic && iwl_have_debug_level(IWL_DL_TX)) {
                ptr = priv->tx_traffic;
                pos += scnprintf(buf + pos, bufsz - pos,
                                "Tx Traffic idx: %u\n", priv->tx_traffic_idx);
@@ -863,8 +855,7 @@ static ssize_t iwl_dbgfs_traffic_log_read(struct file *file,
                }
        }
 
-       if (priv->rx_traffic &&
-               (iwl_get_debug_level(priv->shrd) & IWL_DL_RX)) {
+       if (priv->rx_traffic && iwl_have_debug_level(IWL_DL_RX)) {
                ptr = priv->rx_traffic;
                pos += scnprintf(buf + pos, bufsz - pos,
                                "Rx Traffic idx: %u\n", priv->rx_traffic_idx);
@@ -919,6 +910,8 @@ static int iwl_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz)
        int p = 0;
        u32 flag;
 
+       lockdep_assert_held(&priv->statistics.lock);
+
        flag = le32_to_cpu(priv->statistics.flag);
 
        p += scnprintf(buf + p, bufsz - p, "Statistics Flag(0x%X):\n", flag);
@@ -952,7 +945,7 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file,
        struct statistics_rx_non_phy *delta_general, *max_general;
        struct statistics_rx_ht_phy *ht, *accum_ht, *delta_ht, *max_ht;
 
-       if (!iwl_is_alive(priv->shrd))
+       if (!iwl_is_alive(priv))
                return -EAGAIN;
 
        buf = kzalloc(bufsz, GFP_KERNEL);
@@ -966,6 +959,7 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file,
         * the last statistics notification from uCode
         * might not reflect the current uCode activity
         */
+       spin_lock_bh(&priv->statistics.lock);
        ofdm = &priv->statistics.rx_ofdm;
        cck = &priv->statistics.rx_cck;
        general = &priv->statistics.rx_non_phy;
@@ -1362,6 +1356,8 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file,
                         accum_ht->unsupport_mcs,
                         delta_ht->unsupport_mcs, max_ht->unsupport_mcs);
 
+       spin_unlock_bh(&priv->statistics.lock);
+
        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
        kfree(buf);
        return ret;
@@ -1378,7 +1374,7 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,
        ssize_t ret;
        struct statistics_tx *tx, *accum_tx, *delta_tx, *max_tx;
 
-       if (!iwl_is_alive(priv->shrd))
+       if (!iwl_is_alive(priv))
                return -EAGAIN;
 
        buf = kzalloc(bufsz, GFP_KERNEL);
@@ -1391,6 +1387,8 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,
         * the last statistics notification from uCode
         * might not reflect the current uCode activity
         */
+       spin_lock_bh(&priv->statistics.lock);
+
        tx = &priv->statistics.tx;
        accum_tx = &priv->accum_stats.tx;
        delta_tx = &priv->delta_stats.tx;
@@ -1540,19 +1538,25 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,
        if (tx->tx_power.ant_a || tx->tx_power.ant_b || tx->tx_power.ant_c) {
                pos += scnprintf(buf + pos, bufsz - pos,
                        "tx power: (1/2 dB step)\n");
-               if ((cfg(priv)->valid_tx_ant & ANT_A) && tx->tx_power.ant_a)
+               if ((hw_params(priv).valid_tx_ant & ANT_A) &&
+                   tx->tx_power.ant_a)
                        pos += scnprintf(buf + pos, bufsz - pos,
                                        fmt_hex, "antenna A:",
                                        tx->tx_power.ant_a);
-               if ((cfg(priv)->valid_tx_ant & ANT_B) && tx->tx_power.ant_b)
+               if ((hw_params(priv).valid_tx_ant & ANT_B) &&
+                   tx->tx_power.ant_b)
                        pos += scnprintf(buf + pos, bufsz - pos,
                                        fmt_hex, "antenna B:",
                                        tx->tx_power.ant_b);
-               if ((cfg(priv)->valid_tx_ant & ANT_C) && tx->tx_power.ant_c)
+               if ((hw_params(priv).valid_tx_ant & ANT_C) &&
+                   tx->tx_power.ant_c)
                        pos += scnprintf(buf + pos, bufsz - pos,
                                        fmt_hex, "antenna C:",
                                        tx->tx_power.ant_c);
        }
+
+       spin_unlock_bh(&priv->statistics.lock);
+
        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
        kfree(buf);
        return ret;
@@ -1572,7 +1576,7 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file,
        struct statistics_dbg *dbg, *accum_dbg, *delta_dbg, *max_dbg;
        struct statistics_div *div, *accum_div, *delta_div, *max_div;
 
-       if (!iwl_is_alive(priv->shrd))
+       if (!iwl_is_alive(priv))
                return -EAGAIN;
 
        buf = kzalloc(bufsz, GFP_KERNEL);
@@ -1585,6 +1589,9 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file,
         * the last statistics notification from uCode
         * might not reflect the current uCode activity
         */
+
+       spin_lock_bh(&priv->statistics.lock);
+
        general = &priv->statistics.common;
        dbg = &priv->statistics.common.dbg;
        div = &priv->statistics.common.div;
@@ -1669,6 +1676,9 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file,
                         accum_general->num_of_sos_states,
                         delta_general->num_of_sos_states,
                         max_general->num_of_sos_states);
+
+       spin_unlock_bh(&priv->statistics.lock);
+
        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
        kfree(buf);
        return ret;
@@ -1685,16 +1695,16 @@ static ssize_t iwl_dbgfs_ucode_bt_stats_read(struct file *file,
        ssize_t ret;
        struct statistics_bt_activity *bt, *accum_bt;
 
-       if (!iwl_is_alive(priv->shrd))
+       if (!iwl_is_alive(priv))
                return -EAGAIN;
 
        if (!priv->bt_enable_flag)
                return -EINVAL;
 
        /* make request to uCode to retrieve statistics information */
-       mutex_lock(&priv->shrd->mutex);
+       mutex_lock(&priv->mutex);
        ret = iwl_send_statistics_request(priv, CMD_SYNC, false);
-       mutex_unlock(&priv->shrd->mutex);
+       mutex_unlock(&priv->mutex);
 
        if (ret) {
                IWL_ERR(priv,
@@ -1712,6 +1722,9 @@ static ssize_t iwl_dbgfs_ucode_bt_stats_read(struct file *file,
         * the last statistics notification from uCode
         * might not reflect the current uCode activity
         */
+
+       spin_lock_bh(&priv->statistics.lock);
+
        bt = &priv->statistics.bt_activity;
        accum_bt = &priv->accum_stats.bt_activity;
 
@@ -1757,6 +1770,8 @@ static ssize_t iwl_dbgfs_ucode_bt_stats_read(struct file *file,
                         le32_to_cpu(priv->statistics.num_bt_kills),
                         priv->statistics.accum_num_bt_kills);
 
+       spin_unlock_bh(&priv->statistics.lock);
+
        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
        kfree(buf);
        return ret;
@@ -1773,7 +1788,7 @@ static ssize_t iwl_dbgfs_reply_tx_error_read(struct file *file,
                (sizeof(struct reply_agg_tx_error_statistics) * 24) + 200;
        ssize_t ret;
 
-       if (!iwl_is_alive(priv->shrd))
+       if (!iwl_is_alive(priv))
                return -EAGAIN;
 
        buf = kzalloc(bufsz, GFP_KERNEL);
@@ -2085,9 +2100,9 @@ static ssize_t iwl_dbgfs_clear_ucode_statistics_write(struct file *file,
                return -EFAULT;
 
        /* make request to uCode to retrieve statistics information */
-       mutex_lock(&priv->shrd->mutex);
+       mutex_lock(&priv->mutex);
        iwl_send_statistics_request(priv, CMD_SYNC, true);
-       mutex_unlock(&priv->shrd->mutex);
+       mutex_unlock(&priv->mutex);
 
        return count;
 }
@@ -2131,7 +2146,7 @@ static ssize_t iwl_dbgfs_ucode_tracing_write(struct file *file,
 
        if (trace) {
                priv->event_log.ucode_trace = true;
-               if (iwl_is_alive(priv->shrd)) {
+               if (iwl_is_alive(priv)) {
                        /* start collecting data now */
                        mod_timer(&priv->ucode_trace, jiffies);
                }
@@ -2220,7 +2235,7 @@ static ssize_t iwl_dbgfs_plcp_delta_read(struct file *file,
        const size_t bufsz = sizeof(buf);
 
        pos += scnprintf(buf + pos, bufsz - pos, "%u\n",
-                       cfg(priv)->base_params->plcp_delta_threshold);
+                       priv->plcp_delta_threshold);
 
        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 }
@@ -2242,10 +2257,10 @@ static ssize_t iwl_dbgfs_plcp_delta_write(struct file *file,
                return -EINVAL;
        if ((plcp < IWL_MAX_PLCP_ERR_THRESHOLD_MIN) ||
                (plcp > IWL_MAX_PLCP_ERR_THRESHOLD_MAX))
-               cfg(priv)->base_params->plcp_delta_threshold =
+               priv->plcp_delta_threshold =
                        IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE;
        else
-               cfg(priv)->base_params->plcp_delta_threshold = plcp;
+               priv->plcp_delta_threshold = plcp;
        return count;
 }
 
@@ -2321,7 +2336,7 @@ static ssize_t iwl_dbgfs_txfifo_flush_write(struct file *file,
        if (sscanf(buf, "%d", &flush) != 1)
                return -EINVAL;
 
-       if (iwl_is_rfkill(priv->shrd))
+       if (iwl_is_rfkill(priv))
                return -EFAULT;
 
        iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL);
@@ -2347,7 +2362,7 @@ static ssize_t iwl_dbgfs_wd_timeout_write(struct file *file,
        if (timeout < 0 || timeout > IWL_MAX_WD_TIMEOUT)
                timeout = IWL_DEF_WD_TIMEOUT;
 
-       cfg(priv)->base_params->wd_timeout = timeout;
+       hw_params(priv).wd_timeout = timeout;
        iwl_setup_watchdog(priv);
        return count;
 }
@@ -2410,7 +2425,7 @@ static ssize_t iwl_dbgfs_protection_mode_read(struct file *file,
        if (cfg(priv)->ht_params)
                pos += scnprintf(buf + pos, bufsz - pos,
                         "use %s for aggregation\n",
-                        (cfg(priv)->ht_params->use_rts_for_aggregation) ?
+                        (hw_params(priv).use_rts_for_aggregation) ?
                                "rts/cts" : "cts-to-self");
        else
                pos += scnprintf(buf + pos, bufsz - pos, "N/A");
@@ -2437,9 +2452,9 @@ static ssize_t iwl_dbgfs_protection_mode_write(struct file *file,
        if (sscanf(buf, "%d", &rts) != 1)
                return -EINVAL;
        if (rts)
-               cfg(priv)->ht_params->use_rts_for_aggregation = true;
+               hw_params(priv).use_rts_for_aggregation = true;
        else
-               cfg(priv)->ht_params->use_rts_for_aggregation = false;
+               hw_params(priv).use_rts_for_aggregation = false;
        return count;
 }
 
@@ -2485,52 +2500,6 @@ DEBUGFS_READ_WRITE_FILE_OPS(protection_mode);
 DEBUGFS_READ_FILE_OPS(reply_tx_error);
 DEBUGFS_WRITE_FILE_OPS(echo_test);
 
-#ifdef CONFIG_IWLWIFI_DEBUG
-static ssize_t iwl_dbgfs_debug_level_read(struct file *file,
-                                         char __user *user_buf,
-                                         size_t count, loff_t *ppos)
-{
-       struct iwl_priv *priv = file->private_data;
-       struct iwl_shared *shrd = priv->shrd;
-       char buf[11];
-       int len;
-
-       len = scnprintf(buf, sizeof(buf), "0x%.8x",
-                       iwl_get_debug_level(shrd));
-
-       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
-}
-
-static ssize_t iwl_dbgfs_debug_level_write(struct file *file,
-                                          const char __user *user_buf,
-                                          size_t count, loff_t *ppos)
-{
-       struct iwl_priv *priv = file->private_data;
-       struct iwl_shared *shrd = priv->shrd;
-       char buf[11];
-       unsigned long val;
-       int ret;
-
-       if (count > sizeof(buf))
-               return -EINVAL;
-
-       memset(buf, 0, sizeof(buf));
-       if (copy_from_user(buf, user_buf, count))
-               return -EFAULT;
-
-       ret = strict_strtoul(buf, 0, &val);
-       if (ret)
-               return ret;
-
-       shrd->dbg_level_dev = val;
-       if (iwl_alloc_traffic_mem(priv))
-               IWL_ERR(priv, "Not enough memory to generate traffic log\n");
-
-       return count;
-}
-DEBUGFS_READ_WRITE_FILE_OPS(debug_level);
-#endif /* CONFIG_IWLWIFI_DEBUG */
-
 /*
  * Create the debugfs files and directories
  *
@@ -2595,9 +2564,6 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
        DEBUGFS_ADD_FILE(echo_test, dir_debug, S_IWUSR);
        if (iwl_advanced_bt_coexist(priv))
                DEBUGFS_ADD_FILE(bt_traffic, dir_debug, S_IRUSR);
-#ifdef CONFIG_IWLWIFI_DEBUG
-       DEBUGFS_ADD_FILE(debug_level, dir_debug, S_IRUSR | S_IWUSR);
-#endif
 
        DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf,
                         &priv->disable_sens_cal);
index aa99457c3a52360ce647b8869ff766207c0c9b59..aa4b3b122da4d5a08e2f754409802181b81ebba0 100644 (file)
 #include <linux/wait.h>
 #include <linux/leds.h>
 #include <linux/slab.h>
-#include <net/ieee80211_radiotap.h>
+#include <linux/mutex.h>
 
 #include "iwl-eeprom.h"
 #include "iwl-csr.h"
-#include "iwl-prph.h"
 #include "iwl-debug.h"
 #include "iwl-agn-hw.h"
 #include "iwl-led.h"
 #include "iwl-power.h"
 #include "iwl-agn-rs.h"
 #include "iwl-agn-tt.h"
-#include "iwl-bus.h"
 #include "iwl-trans.h"
 #include "iwl-shared.h"
+#include "iwl-op-mode.h"
+#include "iwl-notif-wait.h"
 
 struct iwl_tx_queue;
 
@@ -294,7 +294,6 @@ struct iwl_vif_priv {
 
 struct iwl_sensitivity_ranges {
        u16 min_nrg_cck;
-       u16 max_nrg_cck;
 
        u16 nrg_th_cck;
        u16 nrg_th_ofdm;
@@ -442,9 +441,6 @@ struct iwl_chain_noise_data {
        u8 state;
 };
 
-#define        EEPROM_SEM_TIMEOUT 10           /* milliseconds */
-#define EEPROM_SEM_RETRY_LIMIT 1000    /* number of attempts (not time) */
-
 enum {
        MEASUREMENT_READY = (1 << 0),
        MEASUREMENT_ACTIVE = (1 << 1),
@@ -673,11 +669,6 @@ struct iwl_rxon_context {
                bool enabled, is_40mhz;
                u8 extension_chan_offset;
        } ht;
-
-       u8 bssid[ETH_ALEN];
-       bool preauth_bssid;
-
-       bool last_tx_rejected;
 };
 
 enum iwl_scan_type {
@@ -696,11 +687,11 @@ struct iwl_testmode_trace {
        dma_addr_t dma_addr;
        bool trace_enabled;
 };
-struct iwl_testmode_sram {
+struct iwl_testmode_mem {
        u32 buff_size;
        u32 num_chunks;
        u8 *buff_addr;
-       bool sram_readed;
+       bool read_in_progress;
 };
 #endif
 
@@ -710,31 +701,55 @@ struct iwl_wipan_noa_data {
        u8 data[];
 };
 
+#define IWL_OP_MODE_GET_DVM(_iwl_op_mode) \
+       ((struct iwl_priv *) ((_iwl_op_mode)->op_mode_specific))
+
+#define IWL_MAC80211_GET_DVM(_hw) \
+       ((struct iwl_priv *) ((struct iwl_op_mode *) \
+       (_hw)->priv)->op_mode_specific)
+
 struct iwl_priv {
 
        /*data shared among all the driver's layers */
        struct iwl_shared *shrd;
+       const struct iwl_fw *fw;
+       unsigned long status;
+
+       spinlock_t sta_lock;
+       struct mutex mutex;
+
+       unsigned long transport_queue_stop;
+       bool passive_no_rx;
 
        /* ieee device used by generic ieee processing code */
        struct ieee80211_hw *hw;
        struct ieee80211_channel *ieee_channels;
        struct ieee80211_rate *ieee_rates;
-       struct kmem_cache *tx_cmd_pool;
+
+       struct list_head calib_results;
+
+       struct workqueue_struct *workqueue;
 
        enum ieee80211_band band;
 
        void (*pre_rx_handler)(struct iwl_priv *priv,
-                              struct iwl_rx_mem_buffer *rxb);
+                              struct iwl_rx_cmd_buffer *rxb);
        int (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv,
-                                      struct iwl_rx_mem_buffer *rxb,
+                                      struct iwl_rx_cmd_buffer *rxb,
                                       struct iwl_device_cmd *cmd);
 
+       struct iwl_notif_wait_data notif_wait;
+
        struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
 
        /* spectrum measurement report caching */
        struct iwl_spectrum_notification measure_report;
        u8 measurement_status;
 
+#define IWL_OWNERSHIP_DRIVER   0
+#define IWL_OWNERSHIP_TM       1
+       u8 ucode_owner;
+
        /* ucode beacon time */
        u32 ucode_beacon_time;
        int missed_beacon_threshold;
@@ -760,6 +775,8 @@ struct iwl_priv {
        struct iwl_channel_info *channel_info;  /* channel info array */
        u8 channel_count;       /* # of channels */
 
+       u8 plcp_delta_threshold;
+
        /* thermal calibration */
        s32 temperature;        /* Celsius */
        s32 last_temperature;
@@ -782,16 +799,11 @@ struct iwl_priv {
 
        bool new_scan_threshold_behaviour;
 
+       bool wowlan;
+
        /* EEPROM MAC addresses */
        struct mac_address addresses[2];
 
-       /* uCode images, save to reload in case of failure */
-       int fw_index;                   /* firmware we're trying to load */
-       u32 ucode_ver;                  /* version of ucode, copy of
-                                          iwl_ucode.ver */
-
-       char firmware_name[25];
-
        struct iwl_rxon_context contexts[NUM_IWL_RXON_CTX];
 
        __le16 switch_channel;
@@ -801,7 +813,6 @@ struct iwl_priv {
        u8 start_calib;
        struct iwl_sensitivity_data sensitivity_data;
        struct iwl_chain_noise_data chain_noise_data;
-       bool enhance_sensitivity_table;
        __le16 sensitivity_tbl[HD_TABLE_SIZE];
        __le16 enhance_sensitivity_tbl[ENHANCE_HD_TABLE_ENTRIES];
 
@@ -847,6 +858,7 @@ struct iwl_priv {
                struct statistics_bt_activity bt_activity;
                __le32 num_bt_kills, accum_num_bt_kills;
 #endif
+               spinlock_t lock;
        } statistics;
 #ifdef CONFIG_IWLWIFI_DEBUGFS
        struct {
@@ -869,11 +881,6 @@ struct iwl_priv {
        struct iwl_rx_phy_res last_phy_res;
        bool last_phy_res_valid;
 
-       struct completion firmware_loading_complete;
-
-       u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr;
-       u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr;
-
        /*
         * chain noise reset and gain commands are the
         * two extra calibration commands follows the standard
@@ -964,7 +971,7 @@ struct iwl_priv {
        bool led_registered;
 #ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE
        struct iwl_testmode_trace testmode_trace;
-       struct iwl_testmode_sram testmode_sram;
+       struct iwl_testmode_mem testmode_mem;
        u32 tm_fixed_rate;
 #endif
 
@@ -975,6 +982,7 @@ struct iwl_priv {
        bool have_rekey_data;
 }; /*iwl_priv */
 
+extern struct kmem_cache *iwl_tx_cmd_pool;
 extern struct iwl_mod_params iwlagn_mod_params;
 
 static inline struct iwl_rxon_context *
index 4d892211ce4ca973cef472728ed144eedda6c09a..06203d6a1d86fe50c38c590ded15954aa0ab0c04 100644 (file)
 #undef TRACE_EVENT
 #define TRACE_EVENT(name, proto, ...) \
 static inline void trace_ ## name(proto) {}
+#undef DECLARE_EVENT_CLASS
+#define DECLARE_EVENT_CLASS(...)
+#undef DEFINE_EVENT
+#define DEFINE_EVENT(evt_class, name, proto, ...) \
+static inline void trace_ ## name(proto) {}
 #endif
 
-#define PRIV_ENTRY     __field(void *, priv)
-#define PRIV_ASSIGN    __entry->priv = priv
+#define DEV_ENTRY      __string(dev, dev_name(dev))
+#define DEV_ASSIGN     __assign_str(dev, dev_name(dev))
 
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM iwlwifi_io
 
 TRACE_EVENT(iwlwifi_dev_ioread32,
-       TP_PROTO(void *priv, u32 offs, u32 val),
-       TP_ARGS(priv, offs, val),
+       TP_PROTO(const struct device *dev, u32 offs, u32 val),
+       TP_ARGS(dev, offs, val),
        TP_STRUCT__entry(
-               PRIV_ENTRY
+               DEV_ENTRY
                __field(u32, offs)
                __field(u32, val)
        ),
        TP_fast_assign(
-               PRIV_ASSIGN;
+               DEV_ASSIGN;
                __entry->offs = offs;
                __entry->val = val;
        ),
-       TP_printk("[%p] read io[%#x] = %#x", __entry->priv, __entry->offs, __entry->val)
+       TP_printk("[%s] read io[%#x] = %#x",
+                 __get_str(dev), __entry->offs, __entry->val)
 );
 
 TRACE_EVENT(iwlwifi_dev_iowrite8,
-       TP_PROTO(void *priv, u32 offs, u8 val),
-       TP_ARGS(priv, offs, val),
+       TP_PROTO(const struct device *dev, u32 offs, u8 val),
+       TP_ARGS(dev, offs, val),
        TP_STRUCT__entry(
-               PRIV_ENTRY
+               DEV_ENTRY
                __field(u32, offs)
                __field(u8, val)
        ),
        TP_fast_assign(
-               PRIV_ASSIGN;
+               DEV_ASSIGN;
                __entry->offs = offs;
                __entry->val = val;
        ),
-       TP_printk("[%p] write io[%#x] = %#x)", __entry->priv, __entry->offs, __entry->val)
+       TP_printk("[%s] write io[%#x] = %#x)",
+                 __get_str(dev), __entry->offs, __entry->val)
 );
 
 TRACE_EVENT(iwlwifi_dev_iowrite32,
-       TP_PROTO(void *priv, u32 offs, u32 val),
-       TP_ARGS(priv, offs, val),
+       TP_PROTO(const struct device *dev, u32 offs, u32 val),
+       TP_ARGS(dev, offs, val),
        TP_STRUCT__entry(
-               PRIV_ENTRY
+               DEV_ENTRY
                __field(u32, offs)
                __field(u32, val)
        ),
        TP_fast_assign(
-               PRIV_ASSIGN;
+               DEV_ASSIGN;
                __entry->offs = offs;
                __entry->val = val;
        ),
-       TP_printk("[%p] write io[%#x] = %#x)", __entry->priv, __entry->offs, __entry->val)
+       TP_printk("[%s] write io[%#x] = %#x)",
+                 __get_str(dev), __entry->offs, __entry->val)
 );
 
 TRACE_EVENT(iwlwifi_dev_irq,
-       TP_PROTO(void *priv),
-       TP_ARGS(priv),
+       TP_PROTO(const struct device *dev),
+       TP_ARGS(dev),
        TP_STRUCT__entry(
-               PRIV_ENTRY
+               DEV_ENTRY
        ),
        TP_fast_assign(
-               PRIV_ASSIGN;
+               DEV_ASSIGN;
        ),
        /* TP_printk("") doesn't compile */
        TP_printk("%d", 0)
 );
 
 TRACE_EVENT(iwlwifi_dev_ict_read,
-       TP_PROTO(void *priv, u32 index, u32 value),
-       TP_ARGS(priv, index, value),
+       TP_PROTO(const struct device *dev, u32 index, u32 value),
+       TP_ARGS(dev, index, value),
        TP_STRUCT__entry(
-               PRIV_ENTRY
+               DEV_ENTRY
                __field(u32, index)
                __field(u32, value)
        ),
        TP_fast_assign(
-               PRIV_ASSIGN;
+               DEV_ASSIGN;
                __entry->index = index;
                __entry->value = value;
        ),
-       TP_printk("read ict[%d] = %#.8x", __entry->index, __entry->value)
+       TP_printk("[%s] read ict[%d] = %#.8x",
+                 __get_str(dev), __entry->index, __entry->value)
 );
 
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM iwlwifi_ucode
 
 TRACE_EVENT(iwlwifi_dev_ucode_cont_event,
-       TP_PROTO(void *priv, u32 time, u32 data, u32 ev),
-       TP_ARGS(priv, time, data, ev),
+       TP_PROTO(const struct device *dev, u32 time, u32 data, u32 ev),
+       TP_ARGS(dev, time, data, ev),
        TP_STRUCT__entry(
-               PRIV_ENTRY
+               DEV_ENTRY
 
                __field(u32, time)
                __field(u32, data)
                __field(u32, ev)
        ),
        TP_fast_assign(
-               PRIV_ASSIGN;
+               DEV_ASSIGN;
                __entry->time = time;
                __entry->data = data;
                __entry->ev = ev;
        ),
-       TP_printk("[%p] EVT_LOGT:%010u:0x%08x:%04u",
-                 __entry->priv, __entry->time, __entry->data, __entry->ev)
+       TP_printk("[%s] EVT_LOGT:%010u:0x%08x:%04u",
+                 __get_str(dev), __entry->time, __entry->data, __entry->ev)
 );
 
 TRACE_EVENT(iwlwifi_dev_ucode_wrap_event,
-       TP_PROTO(void *priv, u32 wraps, u32 n_entry, u32 p_entry),
-       TP_ARGS(priv, wraps, n_entry, p_entry),
+       TP_PROTO(const struct device *dev, u32 wraps, u32 n_entry, u32 p_entry),
+       TP_ARGS(dev, wraps, n_entry, p_entry),
        TP_STRUCT__entry(
-               PRIV_ENTRY
+               DEV_ENTRY
 
                __field(u32, wraps)
                __field(u32, n_entry)
                __field(u32, p_entry)
        ),
        TP_fast_assign(
-               PRIV_ASSIGN;
+               DEV_ASSIGN;
                __entry->wraps = wraps;
                __entry->n_entry = n_entry;
                __entry->p_entry = p_entry;
        ),
-       TP_printk("[%p] wraps=#%02d n=0x%X p=0x%X",
-                 __entry->priv, __entry->wraps, __entry->n_entry,
+       TP_printk("[%s] wraps=#%02d n=0x%X p=0x%X",
+                 __get_str(dev), __entry->wraps, __entry->n_entry,
                  __entry->p_entry)
 );
 
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM iwlwifi_msg
+
+#define MAX_MSG_LEN    100
+
+DECLARE_EVENT_CLASS(iwlwifi_msg_event,
+       TP_PROTO(struct va_format *vaf),
+       TP_ARGS(vaf),
+       TP_STRUCT__entry(
+               __dynamic_array(char, msg, MAX_MSG_LEN)
+       ),
+       TP_fast_assign(
+               WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg),
+                                      MAX_MSG_LEN, vaf->fmt,
+                                      *vaf->va) >= MAX_MSG_LEN);
+       ),
+       TP_printk("%s", (char *)__get_dynamic_array(msg))
+);
+
+DEFINE_EVENT(iwlwifi_msg_event, iwlwifi_err,
+       TP_PROTO(struct va_format *vaf),
+       TP_ARGS(vaf)
+);
+
+DEFINE_EVENT(iwlwifi_msg_event, iwlwifi_warn,
+       TP_PROTO(struct va_format *vaf),
+       TP_ARGS(vaf)
+);
+
+DEFINE_EVENT(iwlwifi_msg_event, iwlwifi_info,
+       TP_PROTO(struct va_format *vaf),
+       TP_ARGS(vaf)
+);
+
+DEFINE_EVENT(iwlwifi_msg_event, iwlwifi_crit,
+       TP_PROTO(struct va_format *vaf),
+       TP_ARGS(vaf)
+);
+
+TRACE_EVENT(iwlwifi_dbg,
+       TP_PROTO(u32 level, bool in_interrupt, const char *function,
+                struct va_format *vaf),
+       TP_ARGS(level, in_interrupt, function, vaf),
+       TP_STRUCT__entry(
+               __field(u32, level)
+               __field(u8, in_interrupt)
+               __string(function, function)
+               __dynamic_array(char, msg, MAX_MSG_LEN)
+       ),
+       TP_fast_assign(
+               __entry->level = level;
+               __entry->in_interrupt = in_interrupt;
+               __assign_str(function, function);
+               WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg),
+                                      MAX_MSG_LEN, vaf->fmt,
+                                      *vaf->va) >= MAX_MSG_LEN);
+       ),
+       TP_printk("%s", (char *)__get_dynamic_array(msg))
+);
+
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM iwlwifi
 
 TRACE_EVENT(iwlwifi_dev_hcmd,
-       TP_PROTO(void *priv, u32 flags,
+       TP_PROTO(const struct device *dev, u32 flags,
                 const void *hcmd0, size_t len0,
                 const void *hcmd1, size_t len1,
                 const void *hcmd2, size_t len2),
-       TP_ARGS(priv, flags, hcmd0, len0, hcmd1, len1, hcmd2, len2),
+       TP_ARGS(dev, flags, hcmd0, len0, hcmd1, len1, hcmd2, len2),
        TP_STRUCT__entry(
-               PRIV_ENTRY
+               DEV_ENTRY
                __dynamic_array(u8, hcmd0, len0)
                __dynamic_array(u8, hcmd1, len1)
                __dynamic_array(u8, hcmd2, len2)
                __field(u32, flags)
        ),
        TP_fast_assign(
-               PRIV_ASSIGN;
+               DEV_ASSIGN;
                memcpy(__get_dynamic_array(hcmd0), hcmd0, len0);
                memcpy(__get_dynamic_array(hcmd1), hcmd1, len1);
                memcpy(__get_dynamic_array(hcmd2), hcmd2, len2);
                __entry->flags = flags;
        ),
-       TP_printk("[%p] hcmd %#.2x (%ssync)",
-                 __entry->priv, ((u8 *)__get_dynamic_array(hcmd0))[0],
+       TP_printk("[%s] hcmd %#.2x (%ssync)",
+                 __get_str(dev), ((u8 *)__get_dynamic_array(hcmd0))[0],
                  __entry->flags & CMD_ASYNC ? "a" : "")
 );
 
 TRACE_EVENT(iwlwifi_dev_rx,
-       TP_PROTO(void *priv, void *rxbuf, size_t len),
-       TP_ARGS(priv, rxbuf, len),
+       TP_PROTO(const struct device *dev, void *rxbuf, size_t len),
+       TP_ARGS(dev, rxbuf, len),
        TP_STRUCT__entry(
-               PRIV_ENTRY
+               DEV_ENTRY
                __dynamic_array(u8, rxbuf, len)
        ),
        TP_fast_assign(
-               PRIV_ASSIGN;
+               DEV_ASSIGN;
                memcpy(__get_dynamic_array(rxbuf), rxbuf, len);
        ),
-       TP_printk("[%p] RX cmd %#.2x",
-                 __entry->priv, ((u8 *)__get_dynamic_array(rxbuf))[4])
+       TP_printk("[%s] RX cmd %#.2x",
+                 __get_str(dev), ((u8 *)__get_dynamic_array(rxbuf))[4])
 );
 
 TRACE_EVENT(iwlwifi_dev_tx,
-       TP_PROTO(void *priv, void *tfd, size_t tfdlen,
+       TP_PROTO(const struct device *dev, 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),
+       TP_ARGS(dev, tfd, tfdlen, buf0, buf0_len, buf1, buf1_len),
        TP_STRUCT__entry(
-               PRIV_ENTRY
+               DEV_ENTRY
 
                __field(size_t, framelen)
                __dynamic_array(u8, tfd, tfdlen)
@@ -226,29 +295,28 @@ TRACE_EVENT(iwlwifi_dev_tx,
                __dynamic_array(u8, buf1, buf1_len)
        ),
        TP_fast_assign(
-               PRIV_ASSIGN;
+               DEV_ASSIGN;
                __entry->framelen = buf0_len + buf1_len;
                memcpy(__get_dynamic_array(tfd), tfd, tfdlen);
                memcpy(__get_dynamic_array(buf0), buf0, buf0_len);
                memcpy(__get_dynamic_array(buf1), buf1, buf1_len);
        ),
-       TP_printk("[%p] TX %.2x (%zu bytes)",
-                 __entry->priv,
-                 ((u8 *)__get_dynamic_array(buf0))[0],
+       TP_printk("[%s] TX %.2x (%zu bytes)",
+                 __get_str(dev), ((u8 *)__get_dynamic_array(buf0))[0],
                  __entry->framelen)
 );
 
 TRACE_EVENT(iwlwifi_dev_ucode_error,
-       TP_PROTO(void *priv, u32 desc, u32 tsf_low,
+       TP_PROTO(const struct device *dev, 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,
                 u32 brd_ver),
-       TP_ARGS(priv, desc, tsf_low, data1, data2, line,
+       TP_ARGS(dev, desc, tsf_low, data1, data2, line,
                blink1, blink2, ilink1, ilink2, bcon_time, gp1, gp2,
                gp3, ucode_ver, hw_ver, brd_ver),
        TP_STRUCT__entry(
-               PRIV_ENTRY
+               DEV_ENTRY
                __field(u32, desc)
                __field(u32, tsf_low)
                __field(u32, data1)
@@ -267,7 +335,7 @@ TRACE_EVENT(iwlwifi_dev_ucode_error,
                __field(u32, brd_ver)
        ),
        TP_fast_assign(
-               PRIV_ASSIGN;
+               DEV_ASSIGN;
                __entry->desc = desc;
                __entry->tsf_low = tsf_low;
                __entry->data1 = data1;
@@ -285,11 +353,11 @@ TRACE_EVENT(iwlwifi_dev_ucode_error,
                __entry->hw_ver = hw_ver;
                __entry->brd_ver = brd_ver;
        ),
-       TP_printk("[%p] #%02d %010u data 0x%08X 0x%08X line %u, "
+       TP_printk("[%s] #%02d %010u data 0x%08X 0x%08X line %u, "
                  "blink 0x%05X 0x%05X ilink 0x%05X 0x%05X "
                  "bcon_tm %010u gp 0x%08X 0x%08X 0x%08X uCode 0x%08X "
                  "hw 0x%08X brd 0x%08X",
-                 __entry->priv, __entry->desc, __entry->tsf_low,
+                 __get_str(dev), __entry->desc, __entry->tsf_low,
                  __entry->data1,
                  __entry->data2, __entry->line, __entry->blink1,
                  __entry->blink2, __entry->ilink1, __entry->ilink2,
@@ -299,23 +367,23 @@ TRACE_EVENT(iwlwifi_dev_ucode_error,
 );
 
 TRACE_EVENT(iwlwifi_dev_ucode_event,
-       TP_PROTO(void *priv, u32 time, u32 data, u32 ev),
-       TP_ARGS(priv, time, data, ev),
+       TP_PROTO(const struct device *dev, u32 time, u32 data, u32 ev),
+       TP_ARGS(dev, time, data, ev),
        TP_STRUCT__entry(
-               PRIV_ENTRY
+               DEV_ENTRY
 
                __field(u32, time)
                __field(u32, data)
                __field(u32, ev)
        ),
        TP_fast_assign(
-               PRIV_ASSIGN;
+               DEV_ASSIGN;
                __entry->time = time;
                __entry->data = data;
                __entry->ev = ev;
        ),
-       TP_printk("[%p] EVT_LOGT:%010u:0x%08x:%04u",
-                 __entry->priv, __entry->time, __entry->data, __entry->ev)
+       TP_printk("[%s] EVT_LOGT:%010u:0x%08x:%04u",
+                 __get_str(dev), __entry->time, __entry->data, __entry->ev)
 );
 #endif /* __IWLWIFI_DEVICE_TRACE */
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c
new file mode 100644 (file)
index 0000000..29a3ae4
--- /dev/null
@@ -0,0 +1,763 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ *
+ * 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.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+#include <linux/completion.h>
+#include <linux/dma-mapping.h>
+#include <linux/firmware.h>
+#include <linux/module.h>
+
+#include "iwl-drv.h"
+#include "iwl-trans.h"
+#include "iwl-shared.h"
+#include "iwl-op-mode.h"
+
+/* private includes */
+#include "iwl-fw-file.h"
+
+/**
+ * struct iwl_drv - drv common data
+ * @fw: the iwl_fw structure
+ * @shrd: pointer to common shared structure
+ * @op_mode: the running op_mode
+ * @fw_index: firmware revision to try loading
+ * @firmware_name: composite filename of ucode file to load
+ * @request_firmware_complete: the firmware has been obtained from user space
+ */
+struct iwl_drv {
+       struct iwl_fw fw;
+
+       struct iwl_shared *shrd;
+       struct iwl_op_mode *op_mode;
+
+       int fw_index;                   /* firmware we're trying to load */
+       char firmware_name[25];         /* name of firmware file to load */
+
+       struct completion request_firmware_complete;
+};
+
+
+
+static void iwl_free_fw_desc(struct iwl_drv *drv, struct fw_desc *desc)
+{
+       if (desc->v_addr)
+               dma_free_coherent(trans(drv)->dev, desc->len,
+                                 desc->v_addr, desc->p_addr);
+       desc->v_addr = NULL;
+       desc->len = 0;
+}
+
+static void iwl_free_fw_img(struct iwl_drv *drv, struct fw_img *img)
+{
+       iwl_free_fw_desc(drv, &img->code);
+       iwl_free_fw_desc(drv, &img->data);
+}
+
+static void iwl_dealloc_ucode(struct iwl_drv *drv)
+{
+       iwl_free_fw_img(drv, &drv->fw.ucode_rt);
+       iwl_free_fw_img(drv, &drv->fw.ucode_init);
+       iwl_free_fw_img(drv, &drv->fw.ucode_wowlan);
+}
+
+static int iwl_alloc_fw_desc(struct iwl_drv *drv, struct fw_desc *desc,
+                     const void *data, size_t len)
+{
+       if (!len) {
+               desc->v_addr = NULL;
+               return -EINVAL;
+       }
+
+       desc->v_addr = dma_alloc_coherent(trans(drv)->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_ucode_callback(const struct firmware *ucode_raw, void *context);
+
+#define UCODE_EXPERIMENTAL_INDEX       100
+#define UCODE_EXPERIMENTAL_TAG         "exp"
+
+static int iwl_request_firmware(struct iwl_drv *drv, bool first)
+{
+       const struct iwl_cfg *cfg = cfg(drv);
+       const char *name_pre = cfg->fw_name_pre;
+       char tag[8];
+
+       if (first) {
+#ifdef CONFIG_IWLWIFI_DEBUG_EXPERIMENTAL_UCODE
+               drv->fw_index = UCODE_EXPERIMENTAL_INDEX;
+               strcpy(tag, UCODE_EXPERIMENTAL_TAG);
+       } else if (drv->fw_index == UCODE_EXPERIMENTAL_INDEX) {
+#endif
+               drv->fw_index = cfg->ucode_api_max;
+               sprintf(tag, "%d", drv->fw_index);
+       } else {
+               drv->fw_index--;
+               sprintf(tag, "%d", drv->fw_index);
+       }
+
+       if (drv->fw_index < cfg->ucode_api_min) {
+               IWL_ERR(drv, "no suitable firmware found!\n");
+               return -ENOENT;
+       }
+
+       sprintf(drv->firmware_name, "%s%s%s", name_pre, tag, ".ucode");
+
+       IWL_DEBUG_INFO(drv, "attempting to load firmware %s'%s'\n",
+                      (drv->fw_index == UCODE_EXPERIMENTAL_INDEX)
+                               ? "EXPERIMENTAL " : "",
+                      drv->firmware_name);
+
+       return request_firmware_nowait(THIS_MODULE, 1, drv->firmware_name,
+                                      trans(drv)->dev,
+                                      GFP_KERNEL, drv, iwl_ucode_callback);
+}
+
+struct iwlagn_firmware_pieces {
+       const void *inst, *data, *init, *init_data, *wowlan_inst, *wowlan_data;
+       size_t inst_size, data_size, init_size, init_data_size,
+              wowlan_inst_size, wowlan_data_size;
+
+       u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr;
+       u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr;
+};
+
+static int iwl_parse_v1_v2_firmware(struct iwl_drv *drv,
+                                      const struct firmware *ucode_raw,
+                                      struct iwlagn_firmware_pieces *pieces)
+{
+       struct iwl_ucode_header *ucode = (void *)ucode_raw->data;
+       u32 api_ver, hdr_size, build;
+       char buildstr[25];
+       const u8 *src;
+
+       drv->fw.ucode_ver = le32_to_cpu(ucode->ver);
+       api_ver = IWL_UCODE_API(drv->fw.ucode_ver);
+
+       switch (api_ver) {
+       default:
+               hdr_size = 28;
+               if (ucode_raw->size < hdr_size) {
+                       IWL_ERR(drv, "File size too small!\n");
+                       return -EINVAL;
+               }
+               build = le32_to_cpu(ucode->u.v2.build);
+               pieces->inst_size = le32_to_cpu(ucode->u.v2.inst_size);
+               pieces->data_size = le32_to_cpu(ucode->u.v2.data_size);
+               pieces->init_size = le32_to_cpu(ucode->u.v2.init_size);
+               pieces->init_data_size =
+                       le32_to_cpu(ucode->u.v2.init_data_size);
+               src = ucode->u.v2.data;
+               break;
+       case 0:
+       case 1:
+       case 2:
+               hdr_size = 24;
+               if (ucode_raw->size < hdr_size) {
+                       IWL_ERR(drv, "File size too small!\n");
+                       return -EINVAL;
+               }
+               build = 0;
+               pieces->inst_size = le32_to_cpu(ucode->u.v1.inst_size);
+               pieces->data_size = le32_to_cpu(ucode->u.v1.data_size);
+               pieces->init_size = le32_to_cpu(ucode->u.v1.init_size);
+               pieces->init_data_size =
+                       le32_to_cpu(ucode->u.v1.init_data_size);
+               src = ucode->u.v1.data;
+               break;
+       }
+
+       if (build)
+               sprintf(buildstr, " build %u%s", build,
+                      (drv->fw_index == UCODE_EXPERIMENTAL_INDEX)
+                               ? " (EXP)" : "");
+       else
+               buildstr[0] = '\0';
+
+       snprintf(drv->fw.fw_version,
+                sizeof(drv->fw.fw_version),
+                "%u.%u.%u.%u%s",
+                IWL_UCODE_MAJOR(drv->fw.ucode_ver),
+                IWL_UCODE_MINOR(drv->fw.ucode_ver),
+                IWL_UCODE_API(drv->fw.ucode_ver),
+                IWL_UCODE_SERIAL(drv->fw.ucode_ver),
+                buildstr);
+
+       /* Verify size of file vs. image size info in file's header */
+       if (ucode_raw->size != hdr_size + pieces->inst_size +
+                               pieces->data_size + pieces->init_size +
+                               pieces->init_data_size) {
+
+               IWL_ERR(drv,
+                       "uCode file size %d does not match expected size\n",
+                       (int)ucode_raw->size);
+               return -EINVAL;
+       }
+
+       pieces->inst = src;
+       src += pieces->inst_size;
+       pieces->data = src;
+       src += pieces->data_size;
+       pieces->init = src;
+       src += pieces->init_size;
+       pieces->init_data = src;
+       src += pieces->init_data_size;
+
+       return 0;
+}
+
+static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
+                               const struct firmware *ucode_raw,
+                               struct iwlagn_firmware_pieces *pieces,
+                               struct iwl_ucode_capabilities *capa)
+{
+       struct iwl_tlv_ucode_header *ucode = (void *)ucode_raw->data;
+       struct iwl_ucode_tlv *tlv;
+       size_t len = ucode_raw->size;
+       const u8 *data;
+       int wanted_alternative = iwlagn_mod_params.wanted_ucode_alternative;
+       int tmp;
+       u64 alternatives;
+       u32 tlv_len;
+       enum iwl_ucode_tlv_type tlv_type;
+       const u8 *tlv_data;
+       char buildstr[25];
+       u32 build;
+
+       if (len < sizeof(*ucode)) {
+               IWL_ERR(drv, "uCode has invalid length: %zd\n", len);
+               return -EINVAL;
+       }
+
+       if (ucode->magic != cpu_to_le32(IWL_TLV_UCODE_MAGIC)) {
+               IWL_ERR(drv, "invalid uCode magic: 0X%x\n",
+                       le32_to_cpu(ucode->magic));
+               return -EINVAL;
+       }
+
+       /*
+        * Check which alternatives are present, and "downgrade"
+        * when the chosen alternative is not present, warning
+        * the user when that happens. Some files may not have
+        * any alternatives, so don't warn in that case.
+        */
+       alternatives = le64_to_cpu(ucode->alternatives);
+       tmp = wanted_alternative;
+       if (wanted_alternative > 63)
+               wanted_alternative = 63;
+       while (wanted_alternative && !(alternatives & BIT(wanted_alternative)))
+               wanted_alternative--;
+       if (wanted_alternative && wanted_alternative != tmp)
+               IWL_WARN(drv,
+                        "uCode alternative %d not available, choosing %d\n",
+                        tmp, wanted_alternative);
+
+       drv->fw.ucode_ver = le32_to_cpu(ucode->ver);
+       build = le32_to_cpu(ucode->build);
+
+       if (build)
+               sprintf(buildstr, " build %u%s", build,
+                      (drv->fw_index == UCODE_EXPERIMENTAL_INDEX)
+                               ? " (EXP)" : "");
+       else
+               buildstr[0] = '\0';
+
+       snprintf(drv->fw.fw_version,
+                sizeof(drv->fw.fw_version),
+                "%u.%u.%u.%u%s",
+                IWL_UCODE_MAJOR(drv->fw.ucode_ver),
+                IWL_UCODE_MINOR(drv->fw.ucode_ver),
+                IWL_UCODE_API(drv->fw.ucode_ver),
+                IWL_UCODE_SERIAL(drv->fw.ucode_ver),
+                buildstr);
+
+       data = ucode->data;
+
+       len -= sizeof(*ucode);
+
+       while (len >= sizeof(*tlv)) {
+               u16 tlv_alt;
+
+               len -= sizeof(*tlv);
+               tlv = (void *)data;
+
+               tlv_len = le32_to_cpu(tlv->length);
+               tlv_type = le16_to_cpu(tlv->type);
+               tlv_alt = le16_to_cpu(tlv->alternative);
+               tlv_data = tlv->data;
+
+               if (len < tlv_len) {
+                       IWL_ERR(drv, "invalid TLV len: %zd/%u\n",
+                               len, tlv_len);
+                       return -EINVAL;
+               }
+               len -= ALIGN(tlv_len, 4);
+               data += sizeof(*tlv) + ALIGN(tlv_len, 4);
+
+               /*
+                * Alternative 0 is always valid.
+                *
+                * Skip alternative TLVs that are not selected.
+                */
+               if (tlv_alt != 0 && tlv_alt != wanted_alternative)
+                       continue;
+
+               switch (tlv_type) {
+               case IWL_UCODE_TLV_INST:
+                       pieces->inst = tlv_data;
+                       pieces->inst_size = tlv_len;
+                       break;
+               case IWL_UCODE_TLV_DATA:
+                       pieces->data = tlv_data;
+                       pieces->data_size = tlv_len;
+                       break;
+               case IWL_UCODE_TLV_INIT:
+                       pieces->init = tlv_data;
+                       pieces->init_size = tlv_len;
+                       break;
+               case IWL_UCODE_TLV_INIT_DATA:
+                       pieces->init_data = tlv_data;
+                       pieces->init_data_size = tlv_len;
+                       break;
+               case IWL_UCODE_TLV_BOOT:
+                       IWL_ERR(drv, "Found unexpected BOOT ucode\n");
+                       break;
+               case IWL_UCODE_TLV_PROBE_MAX_LEN:
+                       if (tlv_len != sizeof(u32))
+                               goto invalid_tlv_len;
+                       capa->max_probe_length =
+                                       le32_to_cpup((__le32 *)tlv_data);
+                       break;
+               case IWL_UCODE_TLV_PAN:
+                       if (tlv_len)
+                               goto invalid_tlv_len;
+                       capa->flags |= IWL_UCODE_TLV_FLAGS_PAN;
+                       break;
+               case IWL_UCODE_TLV_FLAGS:
+                       /* must be at least one u32 */
+                       if (tlv_len < sizeof(u32))
+                               goto invalid_tlv_len;
+                       /* and a proper number of u32s */
+                       if (tlv_len % sizeof(u32))
+                               goto invalid_tlv_len;
+                       /*
+                        * This driver only reads the first u32 as
+                        * right now no more features are defined,
+                        * if that changes then either the driver
+                        * will not work with the new firmware, or
+                        * it'll not take advantage of new features.
+                        */
+                       capa->flags = le32_to_cpup((__le32 *)tlv_data);
+                       break;
+               case IWL_UCODE_TLV_INIT_EVTLOG_PTR:
+                       if (tlv_len != sizeof(u32))
+                               goto invalid_tlv_len;
+                       pieces->init_evtlog_ptr =
+                                       le32_to_cpup((__le32 *)tlv_data);
+                       break;
+               case IWL_UCODE_TLV_INIT_EVTLOG_SIZE:
+                       if (tlv_len != sizeof(u32))
+                               goto invalid_tlv_len;
+                       pieces->init_evtlog_size =
+                                       le32_to_cpup((__le32 *)tlv_data);
+                       break;
+               case IWL_UCODE_TLV_INIT_ERRLOG_PTR:
+                       if (tlv_len != sizeof(u32))
+                               goto invalid_tlv_len;
+                       pieces->init_errlog_ptr =
+                                       le32_to_cpup((__le32 *)tlv_data);
+                       break;
+               case IWL_UCODE_TLV_RUNT_EVTLOG_PTR:
+                       if (tlv_len != sizeof(u32))
+                               goto invalid_tlv_len;
+                       pieces->inst_evtlog_ptr =
+                                       le32_to_cpup((__le32 *)tlv_data);
+                       break;
+               case IWL_UCODE_TLV_RUNT_EVTLOG_SIZE:
+                       if (tlv_len != sizeof(u32))
+                               goto invalid_tlv_len;
+                       pieces->inst_evtlog_size =
+                                       le32_to_cpup((__le32 *)tlv_data);
+                       break;
+               case IWL_UCODE_TLV_RUNT_ERRLOG_PTR:
+                       if (tlv_len != sizeof(u32))
+                               goto invalid_tlv_len;
+                       pieces->inst_errlog_ptr =
+                                       le32_to_cpup((__le32 *)tlv_data);
+                       break;
+               case IWL_UCODE_TLV_ENHANCE_SENS_TBL:
+                       if (tlv_len)
+                               goto invalid_tlv_len;
+                       drv->fw.enhance_sensitivity_table = true;
+                       break;
+               case IWL_UCODE_TLV_WOWLAN_INST:
+                       pieces->wowlan_inst = tlv_data;
+                       pieces->wowlan_inst_size = tlv_len;
+                       break;
+               case IWL_UCODE_TLV_WOWLAN_DATA:
+                       pieces->wowlan_data = tlv_data;
+                       pieces->wowlan_data_size = tlv_len;
+                       break;
+               case IWL_UCODE_TLV_PHY_CALIBRATION_SIZE:
+                       if (tlv_len != sizeof(u32))
+                               goto invalid_tlv_len;
+                       capa->standard_phy_calibration_size =
+                                       le32_to_cpup((__le32 *)tlv_data);
+                       break;
+               default:
+                       IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type);
+                       break;
+               }
+       }
+
+       if (len) {
+               IWL_ERR(drv, "invalid TLV after parsing: %zd\n", len);
+               iwl_print_hex_dump(drv, IWL_DL_FW, (u8 *)data, len);
+               return -EINVAL;
+       }
+
+       return 0;
+
+ invalid_tlv_len:
+       IWL_ERR(drv, "TLV %d has invalid size: %u\n", tlv_type, tlv_len);
+       iwl_print_hex_dump(drv, IWL_DL_FW, tlv_data, tlv_len);
+
+       return -EINVAL;
+}
+
+/**
+ * iwl_ucode_callback - callback when firmware was loaded
+ *
+ * If loaded successfully, copies the firmware into buffers
+ * for the card to fetch (via DMA).
+ */
+static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
+{
+       struct iwl_drv *drv = context;
+       const struct iwl_cfg *cfg = cfg(drv);
+       struct iwl_fw *fw = &drv->fw;
+       struct iwl_ucode_header *ucode;
+       int err;
+       struct iwlagn_firmware_pieces pieces;
+       const unsigned int api_max = cfg->ucode_api_max;
+       unsigned int api_ok = cfg->ucode_api_ok;
+       const unsigned int api_min = cfg->ucode_api_min;
+       u32 api_ver;
+
+       fw->ucode_capa.max_probe_length = 200;
+       fw->ucode_capa.standard_phy_calibration_size =
+                       IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE;
+
+       if (!api_ok)
+               api_ok = api_max;
+
+       memset(&pieces, 0, sizeof(pieces));
+
+       if (!ucode_raw) {
+               if (drv->fw_index <= api_ok)
+                       IWL_ERR(drv,
+                               "request for firmware file '%s' failed.\n",
+                               drv->firmware_name);
+               goto try_again;
+       }
+
+       IWL_DEBUG_INFO(drv, "Loaded firmware file '%s' (%zd bytes).\n",
+                      drv->firmware_name, ucode_raw->size);
+
+       /* Make sure that we got at least the API version number */
+       if (ucode_raw->size < 4) {
+               IWL_ERR(drv, "File size way too small!\n");
+               goto try_again;
+       }
+
+       /* Data from ucode file:  header followed by uCode images */
+       ucode = (struct iwl_ucode_header *)ucode_raw->data;
+
+       if (ucode->ver)
+               err = iwl_parse_v1_v2_firmware(drv, ucode_raw, &pieces);
+       else
+               err = iwl_parse_tlv_firmware(drv, ucode_raw, &pieces,
+                                          &fw->ucode_capa);
+
+       if (err)
+               goto try_again;
+
+       api_ver = IWL_UCODE_API(drv->fw.ucode_ver);
+
+       /*
+        * api_ver should match the api version forming part of the
+        * firmware filename ... but we don't check for that and only rely
+        * on the API version read from firmware header from here on forward
+        */
+       /* no api version check required for experimental uCode */
+       if (drv->fw_index != UCODE_EXPERIMENTAL_INDEX) {
+               if (api_ver < api_min || api_ver > api_max) {
+                       IWL_ERR(drv,
+                               "Driver unable to support your firmware API. "
+                               "Driver supports v%u, firmware is v%u.\n",
+                               api_max, api_ver);
+                       goto try_again;
+               }
+
+               if (api_ver < api_ok) {
+                       if (api_ok != api_max)
+                               IWL_ERR(drv, "Firmware has old API version, "
+                                       "expected v%u through v%u, got v%u.\n",
+                                       api_ok, api_max, api_ver);
+                       else
+                               IWL_ERR(drv, "Firmware has old API version, "
+                                       "expected v%u, got v%u.\n",
+                                       api_max, api_ver);
+                       IWL_ERR(drv, "New firmware can be obtained from "
+                                     "http://www.intellinuxwireless.org/.\n");
+               }
+       }
+
+       IWL_INFO(drv, "loaded firmware version %s", drv->fw.fw_version);
+
+       /*
+        * For any of the failures below (before allocating pci memory)
+        * we will try to load a version with a smaller API -- maybe the
+        * user just got a corrupted version of the latest API.
+        */
+
+       IWL_DEBUG_INFO(drv, "f/w package hdr ucode version raw = 0x%x\n",
+                      drv->fw.ucode_ver);
+       IWL_DEBUG_INFO(drv, "f/w package hdr runtime inst size = %Zd\n",
+                      pieces.inst_size);
+       IWL_DEBUG_INFO(drv, "f/w package hdr runtime data size = %Zd\n",
+                      pieces.data_size);
+       IWL_DEBUG_INFO(drv, "f/w package hdr init inst size = %Zd\n",
+                      pieces.init_size);
+       IWL_DEBUG_INFO(drv, "f/w package hdr init data size = %Zd\n",
+                      pieces.init_data_size);
+
+       /* Verify that uCode images will fit in card's SRAM */
+       if (pieces.inst_size > cfg->max_inst_size) {
+               IWL_ERR(drv, "uCode instr len %Zd too large to fit in\n",
+                       pieces.inst_size);
+               goto try_again;
+       }
+
+       if (pieces.data_size > cfg->max_data_size) {
+               IWL_ERR(drv, "uCode data len %Zd too large to fit in\n",
+                       pieces.data_size);
+               goto try_again;
+       }
+
+       if (pieces.init_size > cfg->max_inst_size) {
+               IWL_ERR(drv, "uCode init instr len %Zd too large to fit in\n",
+                       pieces.init_size);
+               goto try_again;
+       }
+
+       if (pieces.init_data_size > cfg->max_data_size) {
+               IWL_ERR(drv, "uCode init data len %Zd too large to fit in\n",
+                       pieces.init_data_size);
+               goto try_again;
+       }
+
+       /* Allocate ucode buffers for card's bus-master loading ... */
+
+       /* 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(drv, &drv->fw.ucode_rt.code,
+                             pieces.inst, pieces.inst_size))
+               goto err_pci_alloc;
+       if (iwl_alloc_fw_desc(drv, &drv->fw.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(drv,
+                                     &drv->fw.ucode_init.code,
+                                     pieces.init, pieces.init_size))
+                       goto err_pci_alloc;
+               if (iwl_alloc_fw_desc(drv,
+                                     &drv->fw.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(drv,
+                                     &drv->fw.ucode_wowlan.code,
+                                     pieces.wowlan_inst,
+                                     pieces.wowlan_inst_size))
+                       goto err_pci_alloc;
+               if (iwl_alloc_fw_desc(drv,
+                                     &drv->fw.ucode_wowlan.data,
+                                     pieces.wowlan_data,
+                                     pieces.wowlan_data_size))
+                       goto err_pci_alloc;
+       }
+
+       /* Now that we can no longer fail, copy information */
+
+       /*
+        * The (size - 16) / 12 formula is based on the information recorded
+        * for each event, which is of mode 1 (including timestamp) for all
+        * new microcodes that include this information.
+        */
+       fw->init_evtlog_ptr = pieces.init_evtlog_ptr;
+       if (pieces.init_evtlog_size)
+               fw->init_evtlog_size = (pieces.init_evtlog_size - 16)/12;
+       else
+               fw->init_evtlog_size =
+                       cfg->base_params->max_event_log_size;
+       fw->init_errlog_ptr = pieces.init_errlog_ptr;
+       fw->inst_evtlog_ptr = pieces.inst_evtlog_ptr;
+       if (pieces.inst_evtlog_size)
+               fw->inst_evtlog_size = (pieces.inst_evtlog_size - 16)/12;
+       else
+               fw->inst_evtlog_size =
+                       cfg->base_params->max_event_log_size;
+       fw->inst_errlog_ptr = pieces.inst_errlog_ptr;
+
+       /*
+        * figure out the offset of chain noise reset and gain commands
+        * base on the size of standard phy calibration commands table size
+        */
+       if (fw->ucode_capa.standard_phy_calibration_size >
+           IWL_MAX_PHY_CALIBRATE_TBL_SIZE)
+               fw->ucode_capa.standard_phy_calibration_size =
+                       IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE;
+
+       /* We have our copies now, allow OS release its copies */
+       release_firmware(ucode_raw);
+       complete(&drv->request_firmware_complete);
+
+       drv->op_mode = iwl_dvm_ops.start(drv->shrd->trans, &drv->fw);
+
+       if (!drv->op_mode)
+               goto out_unbind;
+
+       return;
+
+ try_again:
+       /* try next, if any */
+       release_firmware(ucode_raw);
+       if (iwl_request_firmware(drv, false))
+               goto out_unbind;
+       return;
+
+ err_pci_alloc:
+       IWL_ERR(drv, "failed to allocate pci memory\n");
+       iwl_dealloc_ucode(drv);
+       release_firmware(ucode_raw);
+ out_unbind:
+       complete(&drv->request_firmware_complete);
+       device_release_driver(trans(drv)->dev);
+}
+
+int iwl_drv_start(struct iwl_shared *shrd,
+                 struct iwl_trans *trans, const struct iwl_cfg *cfg)
+{
+       struct iwl_drv *drv;
+       int ret;
+
+       shrd->cfg = cfg;
+
+       drv = kzalloc(sizeof(*drv), GFP_KERNEL);
+       if (!drv) {
+               dev_printk(KERN_ERR, trans->dev, "Couldn't allocate iwl_drv");
+               return -ENOMEM;
+       }
+       drv->shrd = shrd;
+       shrd->drv = drv;
+
+       init_completion(&drv->request_firmware_complete);
+
+       ret = iwl_request_firmware(drv, true);
+
+       if (ret) {
+               dev_printk(KERN_ERR, trans->dev, "Couldn't request the fw");
+               kfree(drv);
+               shrd->drv = NULL;
+       }
+
+       return ret;
+}
+
+void iwl_drv_stop(struct iwl_shared *shrd)
+{
+       struct iwl_drv *drv = shrd->drv;
+
+       wait_for_completion(&drv->request_firmware_complete);
+
+       /* op_mode can be NULL if its start failed */
+       if (drv->op_mode)
+               iwl_op_mode_stop(drv->op_mode);
+
+       iwl_dealloc_ucode(drv);
+
+       kfree(drv);
+       shrd->drv = NULL;
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.h b/drivers/net/wireless/iwlwifi/iwl-drv.h
new file mode 100644 (file)
index 0000000..3b771c1
--- /dev/null
@@ -0,0 +1,123 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ *
+ * 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.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef __iwl_drv_h__
+#define __iwl_drv_h__
+
+#include "iwl-shared.h"
+
+/**
+ * DOC: Driver system flows - drv component
+ *
+ * This component implements the system flows such as bus enumeration, bus
+ * removal. Bus dependent parts of system flows (such as iwl_pci_probe) are in
+ * bus specific files (transport files). This is the code that is common among
+ * different buses.
+ *
+ * This component is also in charge of managing the several implementations of
+ * the wifi flows: it will allow to have several fw API implementation. These
+ * different implementations will differ in the way they implement mac80211's
+ * handlers too.
+
+ * The init flow wrt to the drv component looks like this:
+ * 1) The bus specific component is called from module_init
+ * 2) The bus specific component registers the bus driver
+ * 3) The bus driver calls the probe function
+ * 4) The bus specific component configures the bus
+ * 5) The bus specific component calls to the drv bus agnostic part
+ *    (iwl_drv_start)
+ * 6) iwl_drv_start fetches the fw ASYNC, iwl_ucode_callback
+ * 7) iwl_ucode_callback parses the fw file
+ * 8) iwl_ucode_callback starts the wifi implementation to matches the fw
+ */
+
+/**
+ * iwl_drv_start - start the drv
+ *
+ * @shrd: the shrd area
+ * @trans_ops: the ops of the transport
+ * @cfg: device specific constants / virtual functions
+ *
+ * TODO: review the parameters given to this function
+ *
+ * starts the driver: fetches the firmware. This should be called by bus
+ * specific system flows implementations. For example, the bus specific probe
+ * function should do bus related operations only, and then call to this
+ * function.
+ */
+int iwl_drv_start(struct iwl_shared *shrd,
+                 struct iwl_trans *trans, const struct iwl_cfg *cfg);
+
+/**
+ * iwl_drv_stop - stop the drv
+ *
+ * @shrd: the shrd area
+ *
+ * TODO: review the parameters given to this function
+ *
+ * Stop the driver. This should be called by bus specific system flows
+ * implementations. For example, the bus specific remove function should first
+ * call this function and then do the bus related operations only.
+ */
+void iwl_drv_stop(struct iwl_shared *shrd);
+
+#endif /* __iwl_drv_h__ */
index d1fd1cdb29c23923e4818bc6e6afb9426303ac0e..23cea42b94959ba5c09ad852b24b7c28ad3a85dc 100644 (file)
@@ -75,6 +75,7 @@
 #include "iwl-agn.h"
 #include "iwl-eeprom.h"
 #include "iwl-io.h"
+#include "iwl-prph.h"
 
 /************************** EEPROM BANDS ****************************
  *
@@ -149,23 +150,27 @@ 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_bus *bus)
+
+#define        EEPROM_SEM_TIMEOUT 10           /* milliseconds */
+#define EEPROM_SEM_RETRY_LIMIT 1000    /* number of attempts (not time) */
+
+static int iwl_eeprom_acquire_semaphore(struct iwl_trans *trans)
 {
        u16 count;
        int ret;
 
        for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) {
                /* Request semaphore */
-               iwl_set_bit(trans(bus), CSR_HW_IF_CONFIG_REG,
+               iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
                            CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
 
                /* See if we got it */
-               ret = iwl_poll_bit(trans(bus), CSR_HW_IF_CONFIG_REG,
+               ret = iwl_poll_bit(trans, 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(trans(bus),
+                       IWL_DEBUG_EEPROM(trans,
                                "Acquired semaphore after %d tries.\n",
                                count+1);
                        return ret;
@@ -175,9 +180,9 @@ static int iwl_eeprom_acquire_semaphore(struct iwl_bus *bus)
        return ret;
 }
 
-static void iwl_eeprom_release_semaphore(struct iwl_bus *bus)
+static void iwl_eeprom_release_semaphore(struct iwl_trans *trans)
 {
-       iwl_clear_bit(trans(bus), CSR_HW_IF_CONFIG_REG,
+       iwl_clear_bit(trans, CSR_HW_IF_CONFIG_REG,
                CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
 
 }
@@ -248,46 +253,46 @@ err:
 
 }
 
-int iwl_eeprom_check_sku(struct iwl_priv *priv)
+int iwl_eeprom_init_hw_params(struct iwl_priv *priv)
 {
        struct iwl_shared *shrd = priv->shrd;
        u16 radio_cfg;
 
-       if (!cfg(priv)->sku) {
-               /* not using sku overwrite */
-               cfg(priv)->sku = iwl_eeprom_query16(shrd, EEPROM_SKU_CAP);
-               if (cfg(priv)->sku & EEPROM_SKU_CAP_11N_ENABLE &&
-                   !cfg(priv)->ht_params) {
-                       IWL_ERR(priv, "Invalid 11n configuration\n");
-                       return -EINVAL;
-               }
+       hw_params(priv).sku = iwl_eeprom_query16(shrd, EEPROM_SKU_CAP);
+       if (hw_params(priv).sku & EEPROM_SKU_CAP_11N_ENABLE &&
+           !cfg(priv)->ht_params) {
+               IWL_ERR(priv, "Invalid 11n configuration\n");
+               return -EINVAL;
        }
-       if (!cfg(priv)->sku) {
+
+       if (!hw_params(priv).sku) {
                IWL_ERR(priv, "Invalid device sku\n");
                return -EINVAL;
        }
 
-       IWL_INFO(priv, "Device SKU: 0x%X\n", cfg(priv)->sku);
-
-       if (!cfg(priv)->valid_tx_ant && !cfg(priv)->valid_rx_ant) {
-               /* not using .cfg overwrite */
-               radio_cfg = iwl_eeprom_query16(shrd, EEPROM_RADIO_CONFIG);
-               cfg(priv)->valid_tx_ant = EEPROM_RF_CFG_TX_ANT_MSK(radio_cfg);
-               cfg(priv)->valid_rx_ant = EEPROM_RF_CFG_RX_ANT_MSK(radio_cfg);
-               if (!cfg(priv)->valid_tx_ant || !cfg(priv)->valid_rx_ant) {
-                       IWL_ERR(priv, "Invalid chain (0x%X, 0x%X)\n",
-                               cfg(priv)->valid_tx_ant,
-                               cfg(priv)->valid_rx_ant);
-                       return -EINVAL;
-               }
-               IWL_INFO(priv, "Valid Tx ant: 0x%X, Valid Rx ant: 0x%X\n",
-                        cfg(priv)->valid_tx_ant, cfg(priv)->valid_rx_ant);
+       IWL_INFO(priv, "Device SKU: 0x%X\n", hw_params(priv).sku);
+
+       radio_cfg = iwl_eeprom_query16(shrd, EEPROM_RADIO_CONFIG);
+
+       hw_params(priv).valid_tx_ant = EEPROM_RF_CFG_TX_ANT_MSK(radio_cfg);
+       hw_params(priv).valid_rx_ant = EEPROM_RF_CFG_RX_ANT_MSK(radio_cfg);
+
+       /* check overrides (some devices have wrong EEPROM) */
+       if (cfg(priv)->valid_tx_ant)
+               hw_params(priv).valid_tx_ant = cfg(priv)->valid_tx_ant;
+       if (cfg(priv)->valid_rx_ant)
+               hw_params(priv).valid_rx_ant = cfg(priv)->valid_rx_ant;
+
+       if (!hw_params(priv).valid_tx_ant || !hw_params(priv).valid_rx_ant) {
+               IWL_ERR(priv, "Invalid chain (0x%X, 0x%X)\n",
+                       hw_params(priv).valid_tx_ant,
+                       hw_params(priv).valid_rx_ant);
+               return -EINVAL;
        }
-       /*
-        * for some special cases,
-        * EEPROM did not reflect the correct antenna setting
-        * so overwrite the valid tx/rx antenna from .cfg
-        */
+
+       IWL_INFO(priv, "Valid Tx ant: 0x%X, Valid Rx ant: 0x%X\n",
+                hw_params(priv).valid_tx_ant, hw_params(priv).valid_rx_ant);
+
        return 0;
 }
 
@@ -304,19 +309,20 @@ void iwl_eeprom_get_mac(const struct iwl_shared *shrd, u8 *mac)
  *
 ******************************************************************************/
 
-static void iwl_set_otp_access(struct iwl_bus *bus, enum iwl_access_mode mode)
+static void iwl_set_otp_access(struct iwl_trans *trans,
+                              enum iwl_access_mode mode)
 {
-       iwl_read32(trans(bus), CSR_OTP_GP_REG);
+       iwl_read32(trans, CSR_OTP_GP_REG);
 
        if (mode == IWL_OTP_ACCESS_ABSOLUTE)
-               iwl_clear_bit(trans(bus), CSR_OTP_GP_REG,
+               iwl_clear_bit(trans, CSR_OTP_GP_REG,
                              CSR_OTP_GP_REG_OTP_ACCESS_MODE);
        else
-               iwl_set_bit(trans(bus), CSR_OTP_GP_REG,
+               iwl_set_bit(trans, CSR_OTP_GP_REG,
                            CSR_OTP_GP_REG_OTP_ACCESS_MODE);
 }
 
-static int iwl_get_nvm_type(struct iwl_bus *bus, u32 hw_rev)
+static int iwl_get_nvm_type(struct iwl_trans *trans, u32 hw_rev)
 {
        u32 otpgp;
        int nvm_type;
@@ -324,7 +330,7 @@ static int iwl_get_nvm_type(struct iwl_bus *bus, 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(bus, "Unknown hardware type\n");
+               IWL_ERR(trans, "Unknown hardware type\n");
                return -ENOENT;
        case CSR_HW_REV_TYPE_5300:
        case CSR_HW_REV_TYPE_5350:
@@ -333,7 +339,7 @@ static int iwl_get_nvm_type(struct iwl_bus *bus, u32 hw_rev)
                nvm_type = NVM_DEVICE_TYPE_EEPROM;
                break;
        default:
-               otpgp = iwl_read32(trans(bus), CSR_OTP_GP_REG);
+               otpgp = iwl_read32(trans, CSR_OTP_GP_REG);
                if (otpgp & CSR_OTP_GP_REG_DEVICE_SELECT)
                        nvm_type = NVM_DEVICE_TYPE_OTP;
                else
@@ -343,73 +349,74 @@ static int iwl_get_nvm_type(struct iwl_bus *bus, u32 hw_rev)
        return  nvm_type;
 }
 
-static int iwl_init_otp_access(struct iwl_bus *bus)
+static int iwl_init_otp_access(struct iwl_trans *trans)
 {
        int ret;
 
        /* Enable 40MHz radio clock */
-       iwl_write32(trans(bus), CSR_GP_CNTRL,
-                   iwl_read32(trans(bus), CSR_GP_CNTRL) |
+       iwl_write32(trans, CSR_GP_CNTRL,
+                   iwl_read32(trans, CSR_GP_CNTRL) |
                    CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
 
        /* wait for clock to be ready */
-       ret = iwl_poll_bit(trans(bus), CSR_GP_CNTRL,
+       ret = iwl_poll_bit(trans, 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(bus, "Time out access OTP\n");
+               IWL_ERR(trans, "Time out access OTP\n");
        else {
-               iwl_set_bits_prph(trans(bus), APMG_PS_CTRL_REG,
+               iwl_set_bits_prph(trans, APMG_PS_CTRL_REG,
                                  APMG_PS_CTRL_VAL_RESET_REQ);
                udelay(5);
-               iwl_clear_bits_prph(trans(bus), APMG_PS_CTRL_REG,
+               iwl_clear_bits_prph(trans, 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 (cfg(bus)->base_params->shadow_ram_support)
-                       iwl_set_bit(trans(bus), CSR_DBG_LINK_PWR_MGMT_REG,
+               if (cfg(trans)->base_params->shadow_ram_support)
+                       iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG,
                                CSR_RESET_LINK_PWR_MGMT_DISABLED);
        }
        return ret;
 }
 
-static int iwl_read_otp_word(struct iwl_bus *bus, u16 addr, __le16 *eeprom_data)
+static int iwl_read_otp_word(struct iwl_trans *trans, u16 addr,
+                            __le16 *eeprom_data)
 {
        int ret = 0;
        u32 r;
        u32 otpgp;
 
-       iwl_write32(trans(bus), CSR_EEPROM_REG,
+       iwl_write32(trans, CSR_EEPROM_REG,
                    CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
-       ret = iwl_poll_bit(trans(bus), CSR_EEPROM_REG,
+       ret = iwl_poll_bit(trans, CSR_EEPROM_REG,
                                 CSR_EEPROM_REG_READ_VALID_MSK,
                                 CSR_EEPROM_REG_READ_VALID_MSK,
                                 IWL_EEPROM_ACCESS_TIMEOUT);
        if (ret < 0) {
-               IWL_ERR(bus, "Time out reading OTP[%d]\n", addr);
+               IWL_ERR(trans, "Time out reading OTP[%d]\n", addr);
                return ret;
        }
-       r = iwl_read32(trans(bus), CSR_EEPROM_REG);
+       r = iwl_read32(trans, CSR_EEPROM_REG);
        /* check for ECC errors: */
-       otpgp = iwl_read32(trans(bus), CSR_OTP_GP_REG);
+       otpgp = iwl_read32(trans, 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(trans(bus), CSR_OTP_GP_REG,
+               iwl_set_bit(trans, CSR_OTP_GP_REG,
                        CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
-               IWL_ERR(bus, "Uncorrectable OTP ECC error, abort OTP read\n");
+               IWL_ERR(trans, "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(trans(bus), CSR_OTP_GP_REG,
+               iwl_set_bit(trans, CSR_OTP_GP_REG,
                                CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK);
-               IWL_ERR(bus, "Correctable OTP ECC error, continue read\n");
+               IWL_ERR(trans, "Correctable OTP ECC error, continue read\n");
        }
        *eeprom_data = cpu_to_le16(r >> 16);
        return 0;
@@ -418,20 +425,20 @@ static int iwl_read_otp_word(struct iwl_bus *bus, u16 addr, __le16 *eeprom_data)
 /*
  * iwl_is_otp_empty: check for empty OTP
  */
-static bool iwl_is_otp_empty(struct iwl_bus *bus)
+static bool iwl_is_otp_empty(struct iwl_trans *trans)
 {
        u16 next_link_addr = 0;
        __le16 link_value;
        bool is_empty = false;
 
        /* locate the beginning of OTP link list */
-       if (!iwl_read_otp_word(bus, next_link_addr, &link_value)) {
+       if (!iwl_read_otp_word(trans, next_link_addr, &link_value)) {
                if (!link_value) {
-                       IWL_ERR(bus, "OTP is empty\n");
+                       IWL_ERR(trans, "OTP is empty\n");
                        is_empty = true;
                }
        } else {
-               IWL_ERR(bus, "Unable to read first block of OTP list.\n");
+               IWL_ERR(trans, "Unable to read first block of OTP list.\n");
                is_empty = true;
        }
 
@@ -448,7 +455,7 @@ static bool iwl_is_otp_empty(struct iwl_bus *bus)
  *   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_bus *bus,
+static int iwl_find_otp_image(struct iwl_trans *trans,
                                        u16 *validblockaddr)
 {
        u16 next_link_addr = 0, valid_addr;
@@ -456,10 +463,10 @@ static int iwl_find_otp_image(struct iwl_bus *bus,
        int usedblocks = 0;
 
        /* set addressing mode to absolute to traverse the link list */
-       iwl_set_otp_access(bus, IWL_OTP_ACCESS_ABSOLUTE);
+       iwl_set_otp_access(trans, IWL_OTP_ACCESS_ABSOLUTE);
 
        /* checking for empty OTP or error */
-       if (iwl_is_otp_empty(bus))
+       if (iwl_is_otp_empty(trans))
                return -EINVAL;
 
        /*
@@ -473,9 +480,9 @@ static int iwl_find_otp_image(struct iwl_bus *bus,
                 */
                valid_addr = next_link_addr;
                next_link_addr = le16_to_cpu(link_value) * sizeof(u16);
-               IWL_DEBUG_EEPROM(bus, "OTP blocks %d addr 0x%x\n",
+               IWL_DEBUG_EEPROM(trans, "OTP blocks %d addr 0x%x\n",
                               usedblocks, next_link_addr);
-               if (iwl_read_otp_word(bus, next_link_addr, &link_value))
+               if (iwl_read_otp_word(trans, next_link_addr, &link_value))
                        return -EINVAL;
                if (!link_value) {
                        /*
@@ -490,10 +497,10 @@ static int iwl_find_otp_image(struct iwl_bus *bus,
                }
                /* more in the link list, continue */
                usedblocks++;
-       } while (usedblocks <= cfg(bus)->base_params->max_ll_items);
+       } while (usedblocks <= cfg(trans)->base_params->max_ll_items);
 
        /* OTP has no valid blocks */
-       IWL_DEBUG_EEPROM(bus, "OTP has no valid blocks\n");
+       IWL_DEBUG_EEPROM(trans, "OTP has no valid blocks\n");
        return -EINVAL;
 }
 
@@ -506,7 +513,7 @@ static int iwl_find_otp_image(struct iwl_bus *bus,
  * 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_cfg *cfg,
+static s8 iwl_get_max_txpower_avg(const struct iwl_cfg *cfg,
                struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
                int element, s8 *max_txpower_in_half_dbm)
 {
@@ -582,7 +589,7 @@ iwl_eeprom_enh_txp_read_element(struct iwl_priv *priv,
 #define TXP_CHECK_AND_PRINT(x) ((txp->flags & IWL_EEPROM_ENH_TXP_FL_##x) \
                            ? # x " " : "")
 
-void iwl_eeprom_enhanced_txpower(struct iwl_priv *priv)
+static void iwl_eeprom_enhanced_txpower(struct iwl_priv *priv)
 {
        struct iwl_shared *shrd = priv->shrd;
        struct iwl_eeprom_enhanced_txpwr *txp_array, *txp;
@@ -653,63 +660,62 @@ void iwl_eeprom_enhanced_txpower(struct iwl_priv *priv)
  *
  * NOTE:  This routine uses the non-debug IO access functions.
  */
-int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev)
+int iwl_eeprom_init(struct iwl_trans *trans, u32 hw_rev)
 {
-       struct iwl_shared *shrd = priv->shrd;
        __le16 *e;
-       u32 gp = iwl_read32(trans(priv), CSR_EEPROM_GP);
+       u32 gp = iwl_read32(trans, CSR_EEPROM_GP);
        int sz;
        int ret;
        u16 addr;
        u16 validblockaddr = 0;
        u16 cache_addr = 0;
 
-       trans(priv)->nvm_device_type = iwl_get_nvm_type(bus(priv), hw_rev);
-       if (trans(priv)->nvm_device_type == -ENOENT)
+       trans->nvm_device_type = iwl_get_nvm_type(trans, hw_rev);
+       if (trans->nvm_device_type == -ENOENT)
                return -ENOENT;
        /* allocate eeprom */
-       sz = cfg(priv)->base_params->eeprom_size;
-       IWL_DEBUG_EEPROM(priv, "NVM size = %d\n", sz);
-       shrd->eeprom = kzalloc(sz, GFP_KERNEL);
-       if (!shrd->eeprom) {
+       sz = cfg(trans)->base_params->eeprom_size;
+       IWL_DEBUG_EEPROM(trans, "NVM size = %d\n", sz);
+       trans->shrd->eeprom = kzalloc(sz, GFP_KERNEL);
+       if (!trans->shrd->eeprom) {
                ret = -ENOMEM;
                goto alloc_err;
        }
-       e = (__le16 *)shrd->eeprom;
+       e = (__le16 *)trans->shrd->eeprom;
 
-       ret = iwl_eeprom_verify_signature(trans(priv));
+       ret = iwl_eeprom_verify_signature(trans);
        if (ret < 0) {
-               IWL_ERR(priv, "EEPROM not found, EEPROM_GP=0x%08x\n", gp);
+               IWL_ERR(trans, "EEPROM not found, EEPROM_GP=0x%08x\n", gp);
                ret = -ENOENT;
                goto err;
        }
 
        /* Make sure driver (instead of uCode) is allowed to read EEPROM */
-       ret = iwl_eeprom_acquire_semaphore(bus(priv));
+       ret = iwl_eeprom_acquire_semaphore(trans);
        if (ret < 0) {
-               IWL_ERR(priv, "Failed to acquire EEPROM semaphore.\n");
+               IWL_ERR(trans, "Failed to acquire EEPROM semaphore.\n");
                ret = -ENOENT;
                goto err;
        }
 
-       if (trans(priv)->nvm_device_type == NVM_DEVICE_TYPE_OTP) {
+       if (trans->nvm_device_type == NVM_DEVICE_TYPE_OTP) {
 
-               ret = iwl_init_otp_access(bus(priv));
+               ret = iwl_init_otp_access(trans);
                if (ret) {
-                       IWL_ERR(priv, "Failed to initialize OTP access.\n");
+                       IWL_ERR(trans, "Failed to initialize OTP access.\n");
                        ret = -ENOENT;
                        goto done;
                }
-               iwl_write32(trans(priv), CSR_EEPROM_GP,
-                           iwl_read32(trans(priv), CSR_EEPROM_GP) &
+               iwl_write32(trans, CSR_EEPROM_GP,
+                           iwl_read32(trans, CSR_EEPROM_GP) &
                            ~CSR_EEPROM_GP_IF_OWNER_MSK);
 
-               iwl_set_bit(trans(priv), CSR_OTP_GP_REG,
+               iwl_set_bit(trans, CSR_OTP_GP_REG,
                             CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK |
                             CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
                /* traversing the linked list if no shadow ram supported */
-               if (!cfg(priv)->base_params->shadow_ram_support) {
-                       if (iwl_find_otp_image(bus(priv), &validblockaddr)) {
+               if (!cfg(trans)->base_params->shadow_ram_support) {
+                       if (iwl_find_otp_image(trans, &validblockaddr)) {
                                ret = -ENOENT;
                                goto done;
                        }
@@ -718,7 +724,7 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev)
                     addr += sizeof(u16)) {
                        __le16 eeprom_data;
 
-                       ret = iwl_read_otp_word(bus(priv), addr, &eeprom_data);
+                       ret = iwl_read_otp_word(trans, addr, &eeprom_data);
                        if (ret)
                                goto done;
                        e[cache_addr / 2] = eeprom_data;
@@ -729,34 +735,35 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev)
                for (addr = 0; addr < sz; addr += sizeof(u16)) {
                        u32 r;
 
-                       iwl_write32(trans(priv), CSR_EEPROM_REG,
+                       iwl_write32(trans, CSR_EEPROM_REG,
                                    CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
 
-                       ret = iwl_poll_bit(trans(priv), CSR_EEPROM_REG,
+                       ret = iwl_poll_bit(trans, 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 EEPROM[%d]\n", addr);
+                               IWL_ERR(trans,
+                                       "Time out reading EEPROM[%d]\n", addr);
                                goto done;
                        }
-                       r = iwl_read32(trans(priv), CSR_EEPROM_REG);
+                       r = iwl_read32(trans, CSR_EEPROM_REG);
                        e[addr / 2] = cpu_to_le16(r >> 16);
                }
        }
 
-       IWL_DEBUG_EEPROM(priv, "NVM Type: %s, version: 0x%x\n",
-                      (trans(priv)->nvm_device_type == NVM_DEVICE_TYPE_OTP)
+       IWL_DEBUG_EEPROM(trans, "NVM Type: %s, version: 0x%x\n",
+                      (trans->nvm_device_type == NVM_DEVICE_TYPE_OTP)
                       ? "OTP" : "EEPROM",
-                      iwl_eeprom_query16(shrd, EEPROM_VERSION));
+                      iwl_eeprom_query16(trans->shrd, EEPROM_VERSION));
 
        ret = 0;
 done:
-       iwl_eeprom_release_semaphore(bus(priv));
+       iwl_eeprom_release_semaphore(trans);
 
 err:
        if (ret)
-               iwl_eeprom_free(priv->shrd);
+               iwl_eeprom_free(trans->shrd);
 alloc_err:
        return ret;
 }
@@ -1018,8 +1025,8 @@ int iwl_init_channel_map(struct iwl_priv *priv)
         * driver need to process addition information
         * to determine the max channel tx power limits
         */
-       if (cfg(priv)->lib->eeprom_ops.update_enhanced_txpower)
-               cfg(priv)->lib->eeprom_ops.update_enhanced_txpower(priv);
+       if (cfg(priv)->lib->eeprom_ops.enhanced_txpower)
+               iwl_eeprom_enhanced_txpower(priv);
 
        return 0;
 }
index 13f2d3928ef8e57cb34869b0e7a282108aa7da69..e4a758340996211f8072c5cdb3223e536741802e 100644 (file)
@@ -67,6 +67,7 @@
 
 struct iwl_priv;
 struct iwl_shared;
+struct iwl_trans;
 
 /*
  * EEPROM access time values:
@@ -301,14 +302,14 @@ extern const u8 iwl_eeprom_band_1[14];
 
 struct iwl_eeprom_ops {
        const u32 regulatory_bands[7];
-       void (*update_enhanced_txpower) (struct iwl_priv *priv);
+       bool enhanced_txpower;
 };
 
 
-int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev);
+int iwl_eeprom_init(struct iwl_trans *trans, u32 hw_rev);
 void iwl_eeprom_free(struct iwl_shared *shrd);
 int  iwl_eeprom_check_version(struct iwl_priv *priv);
-int  iwl_eeprom_check_sku(struct iwl_priv *priv);
+int iwl_eeprom_init_hw_params(struct iwl_priv *priv);
 const u8 *iwl_eeprom_query_addr(const struct iwl_shared *shrd, size_t offset);
 u16 iwl_eeprom_query16(const struct iwl_shared *shrd, size_t offset);
 int iwl_init_channel_map(struct iwl_priv *priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
new file mode 100644 (file)
index 0000000..7ca6c95
--- /dev/null
@@ -0,0 +1,160 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ *
+ * 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.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef __iwl_fw_file_h__
+#define __iwl_fw_file_h__
+
+#include <linux/netdevice.h>
+
+/* v1/v2 uCode file layout */
+struct iwl_ucode_header {
+       __le32 ver;     /* major/minor/API/serial */
+       union {
+               struct {
+                       __le32 inst_size;       /* bytes of runtime code */
+                       __le32 data_size;       /* bytes of runtime data */
+                       __le32 init_size;       /* bytes of init code */
+                       __le32 init_data_size;  /* bytes of init data */
+                       __le32 boot_size;       /* bytes of bootstrap code */
+                       u8 data[0];             /* in same order as sizes */
+               } v1;
+               struct {
+                       __le32 build;           /* build number */
+                       __le32 inst_size;       /* bytes of runtime code */
+                       __le32 data_size;       /* bytes of runtime data */
+                       __le32 init_size;       /* bytes of init code */
+                       __le32 init_data_size;  /* bytes of init data */
+                       __le32 boot_size;       /* bytes of bootstrap code */
+                       u8 data[0];             /* in same order as sizes */
+               } v2;
+       } u;
+};
+
+/*
+ * new TLV uCode file layout
+ *
+ * The new TLV file format contains TLVs, that each specify
+ * some piece of data. To facilitate "groups", for example
+ * different instruction image with different capabilities,
+ * bundled with the same init image, an alternative mechanism
+ * is provided:
+ * When the alternative field is 0, that means that the item
+ * is always valid. When it is non-zero, then it is only
+ * valid in conjunction with items of the same alternative,
+ * in which case the driver (user) selects one alternative
+ * to use.
+ */
+
+enum iwl_ucode_tlv_type {
+       IWL_UCODE_TLV_INVALID           = 0, /* unused */
+       IWL_UCODE_TLV_INST              = 1,
+       IWL_UCODE_TLV_DATA              = 2,
+       IWL_UCODE_TLV_INIT              = 3,
+       IWL_UCODE_TLV_INIT_DATA         = 4,
+       IWL_UCODE_TLV_BOOT              = 5,
+       IWL_UCODE_TLV_PROBE_MAX_LEN     = 6, /* a u32 value */
+       IWL_UCODE_TLV_PAN               = 7,
+       IWL_UCODE_TLV_RUNT_EVTLOG_PTR   = 8,
+       IWL_UCODE_TLV_RUNT_EVTLOG_SIZE  = 9,
+       IWL_UCODE_TLV_RUNT_ERRLOG_PTR   = 10,
+       IWL_UCODE_TLV_INIT_EVTLOG_PTR   = 11,
+       IWL_UCODE_TLV_INIT_EVTLOG_SIZE  = 12,
+       IWL_UCODE_TLV_INIT_ERRLOG_PTR   = 13,
+       IWL_UCODE_TLV_ENHANCE_SENS_TBL  = 14,
+       IWL_UCODE_TLV_PHY_CALIBRATION_SIZE = 15,
+       IWL_UCODE_TLV_WOWLAN_INST       = 16,
+       IWL_UCODE_TLV_WOWLAN_DATA       = 17,
+       IWL_UCODE_TLV_FLAGS             = 18,
+};
+
+struct iwl_ucode_tlv {
+       __le16 type;            /* see above */
+       __le16 alternative;     /* see comment */
+       __le32 length;          /* not including type/length fields */
+       u8 data[0];
+};
+
+#define IWL_TLV_UCODE_MAGIC    0x0a4c5749
+
+struct iwl_tlv_ucode_header {
+       /*
+        * The TLV style ucode header is distinguished from
+        * the v1/v2 style header by first four bytes being
+        * zero, as such is an invalid combination of
+        * major/minor/API/serial versions.
+        */
+       __le32 zero;
+       __le32 magic;
+       u8 human_readable[64];
+       __le32 ver;             /* major/minor/API/serial */
+       __le32 build;
+       __le64 alternatives;    /* bitmask of valid alternatives */
+       /*
+        * The data contained herein has a TLV layout,
+        * see above for the TLV header and types.
+        * Note that each TLV is padded to a length
+        * that is a multiple of 4 for alignment.
+        */
+       u8 data[0];
+};
+
+#endif  /* __iwl_fw_file_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h
new file mode 100644 (file)
index 0000000..453812a
--- /dev/null
@@ -0,0 +1,146 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ *
+ * 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.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef __iwl_fw_h__
+#define __iwl_fw_h__
+#include <linux/types.h>
+
+/**
+ * enum iwl_ucode_tlv_flag - ucode API flags
+ * @IWL_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously
+ *     was a separate TLV but moved here to save space.
+ * @IWL_UCODE_TLV_FLAGS_NEWSCAN: new uCode scan behaviour on hidden SSID,
+ *     treats good CRC threshold as a boolean
+ * @IWL_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w).
+ * @IWL_UCODE_TLV_FLAGS_P2P: This uCode image supports P2P.
+ */
+enum iwl_ucode_tlv_flag {
+       IWL_UCODE_TLV_FLAGS_PAN         = BIT(0),
+       IWL_UCODE_TLV_FLAGS_NEWSCAN     = BIT(1),
+       IWL_UCODE_TLV_FLAGS_MFP         = BIT(2),
+       IWL_UCODE_TLV_FLAGS_P2P         = BIT(3),
+};
+
+/* The default calibrate table size if not specified by firmware file */
+#define IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE    18
+#define IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE                19
+#define IWL_MAX_PHY_CALIBRATE_TBL_SIZE                 253
+
+struct iwl_ucode_capabilities {
+       u32 max_probe_length;
+       u32 standard_phy_calibration_size;
+       u32 flags;
+};
+
+/* 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 */
+};
+
+/* uCode version contains 4 values: Major/Minor/API/Serial */
+#define IWL_UCODE_MAJOR(ver)   (((ver) & 0xFF000000) >> 24)
+#define IWL_UCODE_MINOR(ver)   (((ver) & 0x00FF0000) >> 16)
+#define IWL_UCODE_API(ver)     (((ver) & 0x0000FF00) >> 8)
+#define IWL_UCODE_SERIAL(ver)  ((ver) & 0x000000FF)
+
+/**
+ * struct iwl_fw - variables associated with the firmware
+ *
+ * @ucode_ver: ucode version from the ucode file
+ * @fw_version: firmware version string
+ * @ucode_rt: run time ucode image
+ * @ucode_init: init ucode image
+ * @ucode_wowlan: wake on wireless ucode image (optional)
+ * @ucode_capa: capabilities parsed from the ucode file.
+ * @enhance_sensitivity_table: device can do enhanced sensitivity.
+ * @init_evtlog_ptr: event log offset for init ucode.
+ * @init_evtlog_size: event log size for init ucode.
+ * @init_errlog_ptr: error log offfset for init ucode.
+ * @inst_evtlog_ptr: event log offset for runtime ucode.
+ * @inst_evtlog_size: event log size for runtime ucode.
+ * @inst_errlog_ptr: error log offfset for runtime ucode.
+ */
+struct iwl_fw {
+       u32 ucode_ver;
+
+       char fw_version[ETHTOOL_BUSINFO_LEN];
+
+       /* ucode images */
+       struct fw_img ucode_rt;
+       struct fw_img ucode_init;
+       struct fw_img ucode_wowlan;
+
+       struct iwl_ucode_capabilities ucode_capa;
+       bool enhance_sensitivity_table;
+
+       u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr;
+       u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr;
+};
+
+#endif  /* __iwl_fw_h__ */
index e2e3b5c9cf7fb411fb6f22c86138fda0b4ebcb4d..081dd34d2387d1787ab575ebb2106c9d683ab119 100644 (file)
@@ -118,16 +118,17 @@ int iwl_grab_nic_access_silent(struct iwl_trans *trans)
        return 0;
 }
 
-int iwl_grab_nic_access(struct iwl_trans *trans)
+bool iwl_grab_nic_access(struct iwl_trans *trans)
 {
        int ret = iwl_grab_nic_access_silent(trans);
-       if (ret) {
+       if (unlikely(ret)) {
                u32 val = iwl_read32(trans, CSR_GP_CNTRL);
-               IWL_ERR(trans,
-                       "MAC is in deep sleep!. CSR_GP_CNTRL = 0x%08X\n", val);
+               WARN_ONCE(1, "Timeout waiting for hardware access "
+                            "(CSR_GP_CNTRL 0x%08x)\n", val);
+               return false;
        }
 
-       return ret;
+       return true;
 }
 
 void iwl_release_nic_access(struct iwl_trans *trans)
@@ -135,6 +136,13 @@ void iwl_release_nic_access(struct iwl_trans *trans)
        lockdep_assert_held(&trans->reg_lock);
        __iwl_clear_bit(trans, CSR_GP_CNTRL,
                        CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+       /*
+        * Above we read the CSR_GP_CNTRL register, which will flush
+        * any previous writes, but we need the write that clears the
+        * MAC_ACCESS_REQ bit to be performed before any other writes
+        * scheduled on different CPUs (after we drop reg_lock).
+        */
+       mmiowb();
 }
 
 u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg)
@@ -156,7 +164,7 @@ void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value)
        unsigned long flags;
 
        spin_lock_irqsave(&trans->reg_lock, flags);
-       if (!iwl_grab_nic_access(trans)) {
+       if (likely(iwl_grab_nic_access(trans))) {
                iwl_write32(trans, reg, value);
                iwl_release_nic_access(trans);
        }
@@ -181,7 +189,6 @@ int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask,
 static inline u32 __iwl_read_prph(struct iwl_trans *trans, u32 reg)
 {
        iwl_write32(trans, HBUS_TARG_PRPH_RADDR, reg | (3 << 24));
-       rmb();
        return iwl_read32(trans, HBUS_TARG_PRPH_RDAT);
 }
 
@@ -189,7 +196,6 @@ static inline void __iwl_write_prph(struct iwl_trans *trans, u32 addr, u32 val)
 {
        iwl_write32(trans, HBUS_TARG_PRPH_WADDR,
                    ((addr & 0x0000FFFF) | (3 << 24)));
-       wmb();
        iwl_write32(trans, HBUS_TARG_PRPH_WDAT, val);
 }
 
@@ -211,7 +217,7 @@ void iwl_write_prph(struct iwl_trans *trans, u32 addr, u32 val)
        unsigned long flags;
 
        spin_lock_irqsave(&trans->reg_lock, flags);
-       if (!iwl_grab_nic_access(trans)) {
+       if (likely(iwl_grab_nic_access(trans))) {
                __iwl_write_prph(trans, addr, val);
                iwl_release_nic_access(trans);
        }
@@ -223,9 +229,11 @@ void iwl_set_bits_prph(struct iwl_trans *trans, u32 reg, u32 mask)
        unsigned long flags;
 
        spin_lock_irqsave(&trans->reg_lock, flags);
-       iwl_grab_nic_access(trans);
-       __iwl_write_prph(trans, reg, __iwl_read_prph(trans, reg) | mask);
-       iwl_release_nic_access(trans);
+       if (likely(iwl_grab_nic_access(trans))) {
+               __iwl_write_prph(trans, reg,
+                                __iwl_read_prph(trans, reg) | mask);
+               iwl_release_nic_access(trans);
+       }
        spin_unlock_irqrestore(&trans->reg_lock, flags);
 }
 
@@ -235,10 +243,11 @@ void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 reg,
        unsigned long flags;
 
        spin_lock_irqsave(&trans->reg_lock, flags);
-       iwl_grab_nic_access(trans);
-       __iwl_write_prph(trans, reg,
-                        (__iwl_read_prph(trans, reg) & mask) | bits);
-       iwl_release_nic_access(trans);
+       if (likely(iwl_grab_nic_access(trans))) {
+               __iwl_write_prph(trans, reg,
+                                (__iwl_read_prph(trans, reg) & mask) | bits);
+               iwl_release_nic_access(trans);
+       }
        spin_unlock_irqrestore(&trans->reg_lock, flags);
 }
 
@@ -248,10 +257,11 @@ void iwl_clear_bits_prph(struct iwl_trans *trans, u32 reg, u32 mask)
        u32 val;
 
        spin_lock_irqsave(&trans->reg_lock, flags);
-       iwl_grab_nic_access(trans);
-       val = __iwl_read_prph(trans, reg);
-       __iwl_write_prph(trans, reg, (val & ~mask));
-       iwl_release_nic_access(trans);
+       if (likely(iwl_grab_nic_access(trans))) {
+               val = __iwl_read_prph(trans, reg);
+               __iwl_write_prph(trans, reg, (val & ~mask));
+               iwl_release_nic_access(trans);
+       }
        spin_unlock_irqrestore(&trans->reg_lock, flags);
 }
 
@@ -263,15 +273,12 @@ void _iwl_read_targ_mem_words(struct iwl_trans *trans, u32 addr,
        u32 *vals = buf;
 
        spin_lock_irqsave(&trans->reg_lock, flags);
-       iwl_grab_nic_access(trans);
-
-       iwl_write32(trans, HBUS_TARG_MEM_RADDR, addr);
-       rmb();
-
-       for (offs = 0; offs < words; offs++)
-               vals[offs] = iwl_read32(trans, HBUS_TARG_MEM_RDAT);
-
-       iwl_release_nic_access(trans);
+       if (likely(iwl_grab_nic_access(trans))) {
+               iwl_write32(trans, HBUS_TARG_MEM_RADDR, addr);
+               for (offs = 0; offs < words; offs++)
+                       vals[offs] = iwl_read32(trans, HBUS_TARG_MEM_RDAT);
+               iwl_release_nic_access(trans);
+       }
        spin_unlock_irqrestore(&trans->reg_lock, flags);
 }
 
@@ -292,10 +299,8 @@ int _iwl_write_targ_mem_words(struct iwl_trans *trans, u32 addr,
        u32 *vals = buf;
 
        spin_lock_irqsave(&trans->reg_lock, flags);
-       if (!iwl_grab_nic_access(trans)) {
+       if (likely(iwl_grab_nic_access(trans))) {
                iwl_write32(trans, HBUS_TARG_MEM_WADDR, addr);
-               wmb();
-
                for (offs = 0; offs < words; offs++)
                        iwl_write32(trans, HBUS_TARG_MEM_WDAT, vals[offs]);
                iwl_release_nic_access(trans);
index 782486fc2f8f8a042acc84231d13e0370258664a..09b856768f628bb5aad2d00a09c4ffe360db6b7a 100644 (file)
 
 static inline void iwl_write8(struct iwl_trans *trans, u32 ofs, u8 val)
 {
-       trace_iwlwifi_dev_iowrite8(priv(trans), ofs, val);
+       trace_iwlwifi_dev_iowrite8(trans->dev, ofs, val);
        iwl_trans_write8(trans, ofs, val);
 }
 
 static inline void iwl_write32(struct iwl_trans *trans, u32 ofs, u32 val)
 {
-       trace_iwlwifi_dev_iowrite32(priv(trans), ofs, val);
+       trace_iwlwifi_dev_iowrite32(trans->dev, ofs, val);
        iwl_trans_write32(trans, ofs, val);
 }
 
 static inline u32 iwl_read32(struct iwl_trans *trans, u32 ofs)
 {
        u32 val = iwl_trans_read32(trans, ofs);
-       trace_iwlwifi_dev_ioread32(priv(trans), ofs, val);
+       trace_iwlwifi_dev_ioread32(trans->dev, ofs, val);
        return val;
 }
 
@@ -61,7 +61,7 @@ int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask,
                        int timeout);
 
 int iwl_grab_nic_access_silent(struct iwl_trans *trans);
-int iwl_grab_nic_access(struct iwl_trans *trans);
+bool iwl_grab_nic_access(struct iwl_trans *trans);
 void iwl_release_nic_access(struct iwl_trans *trans);
 
 u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg);
index 5c7741f07aa0c491ba388fc78749380d17dc9656..1993a2b7ae63ce0a844b233254daf6d488d06cf9 100644 (file)
@@ -112,7 +112,7 @@ static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd)
                iwl_write32(trans(priv), CSR_LED_REG,
                            reg & CSR_LED_BSM_CTRL_MSK);
 
-       return iwl_trans_send_cmd(trans(priv), &cmd);
+       return iwl_dvm_send_cmd(priv, &cmd);
 }
 
 /* Set led pattern command */
@@ -126,7 +126,7 @@ static int iwl_led_cmd(struct iwl_priv *priv,
        };
        int ret;
 
-       if (!test_bit(STATUS_READY, &priv->shrd->status))
+       if (!test_bit(STATUS_READY, &priv->status))
                return -EBUSY;
 
        if (priv->blink_on == on && priv->blink_off == off)
index d8025fee7e0d56e7d8bf3ce434d2fd9991b3de66..9212ee3bef9b5b702121575078bb3dccf1684015 100644 (file)
 
 #include <asm/div64.h>
 
-#include "iwl-ucode.h"
 #include "iwl-eeprom.h"
-#include "iwl-wifi.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"
+#include "iwl-op-mode.h"
 
 /*****************************************************************************
  *
@@ -136,7 +134,7 @@ iwlagn_iface_combinations_p2p[] = {
  * other mac80211 functions grouped here.
  */
 int iwlagn_mac_setup_register(struct iwl_priv *priv,
-                                 struct iwlagn_ucode_capabilities *capa)
+                             const struct iwl_ucode_capabilities *capa)
 {
        int ret;
        struct ieee80211_hw *hw = priv->hw;
@@ -161,11 +159,14 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
        hw->flags |= IEEE80211_HW_SUPPORTS_PS |
                     IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
 
-       if (cfg(priv)->sku & EEPROM_SKU_CAP_11N_ENABLE)
+       if (hw_params(priv).sku & EEPROM_SKU_CAP_11N_ENABLE)
                hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
                             IEEE80211_HW_SUPPORTS_STATIC_SMPS;
 
+#ifndef CONFIG_IWLWIFI_EXPERIMENTAL_MFP
+       /* enable 11w if the uCode advertise */
        if (capa->flags & IWL_UCODE_TLV_FLAGS_MFP)
+#endif /* !CONFIG_IWLWIFI_EXPERIMENTAL_MFP */
                hw->flags |= IEEE80211_HW_MFP_CAPABLE;
 
        hw->sta_data_size = sizeof(struct iwl_station_priv);
@@ -195,7 +196,8 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
                            WIPHY_FLAG_DISABLE_BEACON_HINTS |
                            WIPHY_FLAG_IBSS_RSN;
 
-       if (trans(priv)->ucode_wowlan.code.len &&
+       if (priv->fw->ucode_wowlan.code.len &&
+           trans(priv)->ops->wowlan_suspend &&
            device_can_wakeup(trans(priv)->dev)) {
                hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
                                          WIPHY_WOWLAN_DISCONNECT |
@@ -262,9 +264,9 @@ static int __iwl_up(struct iwl_priv *priv)
        struct iwl_rxon_context *ctx;
        int ret;
 
-       lockdep_assert_held(&priv->shrd->mutex);
+       lockdep_assert_held(&priv->mutex);
 
-       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) {
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
                IWL_WARN(priv, "Exit pending; will not bring the NIC up\n");
                return -EIO;
        }
@@ -277,13 +279,13 @@ static int __iwl_up(struct iwl_priv *priv)
                }
        }
 
-       ret = iwl_run_init_ucode(trans(priv));
+       ret = iwl_run_init_ucode(priv);
        if (ret) {
                IWL_ERR(priv, "Failed to run INIT ucode: %d\n", ret);
                goto error;
        }
 
-       ret = iwl_load_ucode_wait_alive(trans(priv), IWL_UCODE_REGULAR);
+       ret = iwl_load_ucode_wait_alive(priv, IWL_UCODE_REGULAR);
        if (ret) {
                IWL_ERR(priv, "Failed to start RT ucode: %d\n", ret);
                goto error;
@@ -295,9 +297,9 @@ static int __iwl_up(struct iwl_priv *priv)
        return 0;
 
  error:
-       set_bit(STATUS_EXIT_PENDING, &priv->shrd->status);
-       __iwl_down(priv);
-       clear_bit(STATUS_EXIT_PENDING, &priv->shrd->status);
+       set_bit(STATUS_EXIT_PENDING, &priv->status);
+       iwl_down(priv);
+       clear_bit(STATUS_EXIT_PENDING, &priv->status);
 
        IWL_ERR(priv, "Unable to initialize device.\n");
        return ret;
@@ -305,22 +307,22 @@ static int __iwl_up(struct iwl_priv *priv)
 
 static int iwlagn_mac_start(struct ieee80211_hw *hw)
 {
-       struct iwl_priv *priv = hw->priv;
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
        int ret;
 
        IWL_DEBUG_MAC80211(priv, "enter\n");
 
        /* we should be verifying the device is ready to be opened */
-       mutex_lock(&priv->shrd->mutex);
+       mutex_lock(&priv->mutex);
        ret = __iwl_up(priv);
-       mutex_unlock(&priv->shrd->mutex);
+       mutex_unlock(&priv->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)))
+       if (WARN_ON(!test_bit(STATUS_READY, &priv->status)))
                ret = -EIO;
 
        iwlagn_led_enable(priv);
@@ -332,7 +334,7 @@ static int iwlagn_mac_start(struct ieee80211_hw *hw)
 
 static void iwlagn_mac_stop(struct ieee80211_hw *hw)
 {
-       struct iwl_priv *priv = hw->priv;
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 
        IWL_DEBUG_MAC80211(priv, "enter\n");
 
@@ -341,9 +343,13 @@ static void iwlagn_mac_stop(struct ieee80211_hw *hw)
 
        priv->is_open = 0;
 
+       mutex_lock(&priv->mutex);
        iwl_down(priv);
+       mutex_unlock(&priv->mutex);
+
+       iwl_cancel_deferred_work(priv);
 
-       flush_workqueue(priv->shrd->workqueue);
+       flush_workqueue(priv->workqueue);
 
        /* User space software may expect getting rfkill changes
         * even if interface is down, trans->down will leave the RF
@@ -358,13 +364,13 @@ 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;
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 
        if (iwlagn_mod_params.sw_crypto)
                return;
 
        IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->shrd->mutex);
+       mutex_lock(&priv->mutex);
 
        if (priv->contexts[IWL_RXON_CTX_BSS].vif != vif)
                goto out;
@@ -376,7 +382,7 @@ static void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw,
        priv->have_rekey_data = true;
 
  out:
-       mutex_unlock(&priv->shrd->mutex);
+       mutex_unlock(&priv->mutex);
        IWL_DEBUG_MAC80211(priv, "leave\n");
 }
 
@@ -385,7 +391,7 @@ static void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw,
 static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
                              struct cfg80211_wowlan *wowlan)
 {
-       struct iwl_priv *priv = hw->priv;
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
        struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
        int ret;
 
@@ -393,7 +399,7 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
                return -EINVAL;
 
        IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->shrd->mutex);
+       mutex_lock(&priv->mutex);
 
        /* Don't attempt WoWLAN when not associated, tear down instead. */
        if (!ctx->vif || ctx->vif->type != NL80211_IFTYPE_STATION ||
@@ -402,24 +408,22 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
                goto out;
        }
 
-       ret = iwlagn_suspend(priv, hw, wowlan);
+       ret = iwlagn_suspend(priv, wowlan);
        if (ret)
                goto error;
 
        device_set_wakeup_enable(trans(priv)->dev, true);
 
-       /* Now let the ucode operate on its own */
-       iwl_write32(trans(priv), CSR_UCODE_DRV_GP1_SET,
-                         CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
+       iwl_trans_wowlan_suspend(trans(priv));
 
        goto out;
 
  error:
-       priv->shrd->wowlan = false;
+       priv->wowlan = false;
        iwlagn_prepare_restart(priv);
        ieee80211_restart_hw(priv->hw);
  out:
-       mutex_unlock(&priv->shrd->mutex);
+       mutex_unlock(&priv->mutex);
        IWL_DEBUG_MAC80211(priv, "leave\n");
 
        return ret;
@@ -427,7 +431,7 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
 
 static int iwlagn_mac_resume(struct ieee80211_hw *hw)
 {
-       struct iwl_priv *priv = hw->priv;
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
        struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
        struct ieee80211_vif *vif;
        unsigned long flags;
@@ -435,7 +439,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)
        int ret = -EIO;
 
        IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->shrd->mutex);
+       mutex_lock(&priv->mutex);
 
        iwl_write32(trans(priv), CSR_UCODE_DRV_GP1_CLR,
                          CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
@@ -444,7 +448,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)
        if (iwlagn_hw_valid_rtc_data_addr(base)) {
                spin_lock_irqsave(&trans(priv)->reg_lock, flags);
                ret = iwl_grab_nic_access_silent(trans(priv));
-               if (ret == 0) {
+               if (likely(ret == 0)) {
                        iwl_write32(trans(priv), HBUS_TARG_MEM_RADDR, base);
                        status = iwl_read32(trans(priv), HBUS_TARG_MEM_RDAT);
                        iwl_release_nic_access(trans(priv));
@@ -453,17 +457,16 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)
 
 #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,
+                                       kzalloc(priv->fw->ucode_wowlan.data.len,
                                                GFP_KERNEL);
 
                        if (priv->wowlan_sram)
                                _iwl_read_targ_mem_words(
                                        trans(priv), 0x800000,
                                        priv->wowlan_sram,
-                                       trans->ucode_wowlan.data.len / 4);
+                                       priv->fw->ucode_wowlan.data.len / 4);
                }
 #endif
        }
@@ -471,7 +474,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)
        /* we'll clear ctx->vif during iwlagn_prepare_restart() */
        vif = ctx->vif;
 
-       priv->shrd->wowlan = false;
+       priv->wowlan = false;
 
        device_set_wakeup_enable(trans(priv)->dev, false);
 
@@ -481,7 +484,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)
        iwl_connection_init_rx_config(priv, ctx);
        iwlagn_set_rxon_chain(priv, ctx);
 
-       mutex_unlock(&priv->shrd->mutex);
+       mutex_unlock(&priv->mutex);
        IWL_DEBUG_MAC80211(priv, "leave\n");
 
        ieee80211_resume_disconnect(vif);
@@ -493,7 +496,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)
 
 static void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
-       struct iwl_priv *priv = hw->priv;
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 
        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);
@@ -508,7 +511,7 @@ static void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw,
                                       struct ieee80211_sta *sta,
                                       u32 iv32, u16 *phase1key)
 {
-       struct iwl_priv *priv = hw->priv;
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 
        iwl_update_tkip_key(priv, vif, keyconf, sta, iv32, phase1key);
 }
@@ -518,7 +521,7 @@ static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                              struct ieee80211_sta *sta,
                              struct ieee80211_key_conf *key)
 {
-       struct iwl_priv *priv = hw->priv;
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
        struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
        struct iwl_rxon_context *ctx = vif_priv->ctx;
        int ret;
@@ -559,7 +562,7 @@ static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
        if (cmd == DISABLE_KEY && key->hw_key_idx == WEP_INVALID_OFFSET)
                return 0;
 
-       mutex_lock(&priv->shrd->mutex);
+       mutex_lock(&priv->mutex);
        iwl_scan_cancel_timeout(priv, 100);
 
        BUILD_BUG_ON(WEP_INVALID_OFFSET == IWLAGN_HW_KEY_DEFAULT);
@@ -610,7 +613,7 @@ static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                ret = -EINVAL;
        }
 
-       mutex_unlock(&priv->shrd->mutex);
+       mutex_unlock(&priv->mutex);
        IWL_DEBUG_MAC80211(priv, "leave\n");
 
        return ret;
@@ -622,18 +625,18 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
                                   struct ieee80211_sta *sta, u16 tid, u16 *ssn,
                                   u8 buf_size)
 {
-       struct iwl_priv *priv = hw->priv;
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
        int ret = -EINVAL;
        struct iwl_station_priv *sta_priv = (void *) sta->drv_priv;
 
        IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n",
                     sta->addr, tid);
 
-       if (!(cfg(priv)->sku & EEPROM_SKU_CAP_11N_ENABLE))
+       if (!(hw_params(priv).sku & EEPROM_SKU_CAP_11N_ENABLE))
                return -EACCES;
 
        IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->shrd->mutex);
+       mutex_lock(&priv->mutex);
 
        switch (action) {
        case IEEE80211_AMPDU_RX_START:
@@ -645,8 +648,6 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
        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:
                if (iwlagn_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG)
@@ -662,10 +663,8 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
                        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 && cfg(priv)->ht_params &&
-                   cfg(priv)->ht_params->use_rts_for_aggregation) {
+               if (!priv->agg_tids_count &&
+                   hw_params(priv).use_rts_for_aggregation) {
                        /*
                         * switch off RTS/CTS if it was previously enabled
                         */
@@ -679,7 +678,7 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
                ret = iwlagn_tx_agg_oper(priv, vif, sta, tid, buf_size);
                break;
        }
-       mutex_unlock(&priv->shrd->mutex);
+       mutex_unlock(&priv->mutex);
        IWL_DEBUG_MAC80211(priv, "leave\n");
        return ret;
 }
@@ -688,16 +687,13 @@ 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_priv *priv = IWL_MAC80211_GET_DVM(hw);
        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;
+       int ret;
        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;
@@ -712,17 +708,119 @@ static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
                IWL_ERR(priv, "Unable to add station %pM (%d)\n",
                        sta->addr, ret);
                /* Should we return success if return code is EEXIST ? */
-               goto out;
+               return ret;
        }
 
        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);
+       return 0;
+}
+
+static int iwlagn_mac_sta_remove(struct ieee80211_hw *hw,
+                                struct ieee80211_vif *vif,
+                                struct ieee80211_sta *sta)
+{
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+       int ret;
+
+       IWL_DEBUG_INFO(priv, "proceeding to remove station %pM\n", sta->addr);
+
+       if (vif->type == NL80211_IFTYPE_STATION) {
+               /*
+                * Station will be removed from device when the RXON
+                * is set to unassociated -- just deactivate it here
+                * to avoid re-programming it.
+                */
+               ret = 0;
+               iwl_deactivate_station(priv, sta_priv->sta_id, sta->addr);
+       } else {
+               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);
+       }
+       return ret;
+}
+
+static int iwlagn_mac_sta_state(struct ieee80211_hw *hw,
+                               struct ieee80211_vif *vif,
+                               struct ieee80211_sta *sta,
+                               enum ieee80211_sta_state old_state,
+                               enum ieee80211_sta_state new_state)
+{
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+       enum {
+               NONE, ADD, REMOVE, HT_RATE_INIT, ADD_RATE_INIT,
+       } op = NONE;
+       int ret;
+
+       IWL_DEBUG_MAC80211(priv, "station %pM state change %d->%d\n",
+                          sta->addr, old_state, new_state);
+
+       mutex_lock(&priv->mutex);
+       if (vif->type == NL80211_IFTYPE_STATION) {
+               if (old_state == IEEE80211_STA_NOTEXIST &&
+                   new_state == IEEE80211_STA_NONE)
+                       op = ADD;
+               else if (old_state == IEEE80211_STA_NONE &&
+                        new_state == IEEE80211_STA_NOTEXIST)
+                       op = REMOVE;
+               else if (old_state == IEEE80211_STA_AUTH &&
+                        new_state == IEEE80211_STA_ASSOC)
+                       op = HT_RATE_INIT;
+       } else {
+               if (old_state == IEEE80211_STA_AUTH &&
+                   new_state == IEEE80211_STA_ASSOC)
+                       op = ADD_RATE_INIT;
+               else if (old_state == IEEE80211_STA_ASSOC &&
+                        new_state == IEEE80211_STA_AUTH)
+                       op = REMOVE;
+       }
+
+       switch (op) {
+       case ADD:
+               ret = iwlagn_mac_sta_add(hw, vif, sta);
+               break;
+       case REMOVE:
+               ret = iwlagn_mac_sta_remove(hw, vif, sta);
+               break;
+       case ADD_RATE_INIT:
+               ret = iwlagn_mac_sta_add(hw, vif, sta);
+               if (ret)
+                       break;
+               /* Initialize rate scaling */
+               IWL_DEBUG_INFO(priv,
+                              "Initializing rate scaling for station %pM\n",
+                              sta->addr);
+               iwl_rs_rate_init(priv, sta, iwl_sta_id(sta));
+               ret = 0;
+               break;
+       case HT_RATE_INIT:
+               /* Initialize rate scaling */
+               ret = iwl_sta_update_ht(priv, vif_priv->ctx, sta);
+               if (ret)
+                       break;
+               IWL_DEBUG_INFO(priv,
+                              "Initializing rate scaling for station %pM\n",
+                              sta->addr);
+               iwl_rs_rate_init(priv, sta, iwl_sta_id(sta));
+               ret = 0;
+               break;
+       default:
+               ret = 0;
+               break;
+       }
+
+       /*
+        * mac80211 might WARN if we fail, but due the way we
+        * (badly) handle hard rfkill, we might fail here
+        */
+       if (iwl_is_rfkill(priv))
+               ret = 0;
+
+       mutex_unlock(&priv->mutex);
        IWL_DEBUG_MAC80211(priv, "leave\n");
 
        return ret;
@@ -731,7 +829,7 @@ static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
 static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
                                struct ieee80211_channel_switch *ch_switch)
 {
-       struct iwl_priv *priv = hw->priv;
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
        const struct iwl_channel_info *ch_info;
        struct ieee80211_conf *conf = &hw->conf;
        struct ieee80211_channel *channel = ch_switch->channel;
@@ -749,14 +847,14 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
 
        IWL_DEBUG_MAC80211(priv, "enter\n");
 
-       mutex_lock(&priv->shrd->mutex);
+       mutex_lock(&priv->mutex);
 
-       if (iwl_is_rfkill(priv->shrd))
+       if (iwl_is_rfkill(priv))
                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))
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
+           test_bit(STATUS_SCANNING, &priv->status) ||
+           test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
                goto out;
 
        if (!iwl_is_associated_ctx(ctx))
@@ -775,8 +873,6 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
                goto out;
        }
 
-       spin_lock_irq(&priv->shrd->lock);
-
        priv->current_ht_config.smps = conf->smps_mode;
 
        /* Configure HT40 channels */
@@ -793,23 +889,21 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
        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);
+       set_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status);
        priv->switch_channel = cpu_to_le16(ch);
        if (cfg(priv)->lib->set_channel_switch(priv, ch_switch)) {
-               clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status);
+               clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status);
                priv->switch_channel = 0;
                ieee80211_chswitch_done(ctx->vif, false);
        }
 
 out:
-       mutex_unlock(&priv->shrd->mutex);
+       mutex_unlock(&priv->mutex);
        IWL_DEBUG_MAC80211(priv, "leave\n");
 }
 
@@ -818,7 +912,7 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw,
                                    unsigned int *total_flags,
                                    u64 multicast)
 {
-       struct iwl_priv *priv = hw->priv;
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
        __le32 filter_or = 0, filter_nand = 0;
        struct iwl_rxon_context *ctx;
 
@@ -839,7 +933,7 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw,
 
 #undef CHK
 
-       mutex_lock(&priv->shrd->mutex);
+       mutex_lock(&priv->mutex);
 
        for_each_context(priv, ctx) {
                ctx->staging.filter_flags &= ~filter_nand;
@@ -851,7 +945,7 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw,
                 */
        }
 
-       mutex_unlock(&priv->shrd->mutex);
+       mutex_unlock(&priv->mutex);
 
        /*
         * Receiving all multicast frames is always enabled by the
@@ -865,16 +959,16 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw,
 
 static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop)
 {
-       struct iwl_priv *priv = hw->priv;
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 
-       mutex_lock(&priv->shrd->mutex);
+       mutex_lock(&priv->mutex);
        IWL_DEBUG_MAC80211(priv, "enter\n");
 
-       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) {
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
                IWL_DEBUG_TX(priv, "Aborting flush due to device shutdown\n");
                goto done;
        }
-       if (iwl_is_rfkill(priv->shrd)) {
+       if (iwl_is_rfkill(priv)) {
                IWL_DEBUG_TX(priv, "Aborting flush due to RF Kill\n");
                goto done;
        }
@@ -893,7 +987,7 @@ static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop)
        IWL_DEBUG_MAC80211(priv, "wait transmit/flush all frames\n");
        iwl_trans_wait_tx_queue_empty(trans(priv));
 done:
-       mutex_unlock(&priv->shrd->mutex);
+       mutex_unlock(&priv->mutex);
        IWL_DEBUG_MAC80211(priv, "leave\n");
 }
 
@@ -902,7 +996,7 @@ static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw,
                                     enum nl80211_channel_type channel_type,
                                     int duration)
 {
-       struct iwl_priv *priv = hw->priv;
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
        struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
        int err = 0;
 
@@ -913,9 +1007,9 @@ static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw,
                return -EOPNOTSUPP;
 
        IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->shrd->mutex);
+       mutex_lock(&priv->mutex);
 
-       if (test_bit(STATUS_SCAN_HW, &priv->shrd->status)) {
+       if (test_bit(STATUS_SCAN_HW, &priv->status)) {
                err = -EBUSY;
                goto out;
        }
@@ -984,7 +1078,7 @@ static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw,
                iwlagn_disable_roc(priv);
 
  out:
-       mutex_unlock(&priv->shrd->mutex);
+       mutex_unlock(&priv->mutex);
        IWL_DEBUG_MAC80211(priv, "leave\n");
 
        return err;
@@ -992,108 +1086,28 @@ static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw,
 
 static int iwlagn_mac_cancel_remain_on_channel(struct ieee80211_hw *hw)
 {
-       struct iwl_priv *priv = hw->priv;
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 
        if (!(priv->shrd->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
                return -EOPNOTSUPP;
 
        IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->shrd->mutex);
+       mutex_lock(&priv->mutex);
        iwl_scan_cancel_timeout(priv, priv->hw_roc_duration);
        iwlagn_disable_roc(priv);
-       mutex_unlock(&priv->shrd->mutex);
+       mutex_unlock(&priv->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;
-
-       if (ctx->ctxid != IWL_RXON_CTX_PAN)
-               return 0;
-
-       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;
-
-       if (ctx->ctxid != IWL_RXON_CTX_PAN)
-               return;
-
-       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;
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 
        IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->shrd->mutex);
+       mutex_lock(&priv->mutex);
 
        if (cfg(priv)->bt_params &&
                        cfg(priv)->bt_params->advanced_bt_coexist) {
@@ -1108,16 +1122,16 @@ static void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw,
                                "ignoring RSSI callback\n");
        }
 
-       mutex_unlock(&priv->shrd->mutex);
+       mutex_unlock(&priv->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;
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 
-       queue_work(priv->shrd->workqueue, &priv->beacon_update);
+       queue_work(priv->workqueue, &priv->beacon_update);
 
        return 0;
 }
@@ -1126,10 +1140,9 @@ 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_priv *priv = IWL_MAC80211_GET_DVM(hw);
        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))
@@ -1137,7 +1150,7 @@ static int iwlagn_mac_conf_tx(struct ieee80211_hw *hw,
 
        IWL_DEBUG_MAC80211(priv, "enter\n");
 
-       if (!iwl_is_ready_rf(priv->shrd)) {
+       if (!iwl_is_ready_rf(priv)) {
                IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
                return -EIO;
        }
@@ -1149,7 +1162,7 @@ static int iwlagn_mac_conf_tx(struct ieee80211_hw *hw,
 
        q = AC_NUM - 1 - queue;
 
-       spin_lock_irqsave(&priv->shrd->lock, flags);
+       mutex_lock(&priv->mutex);
 
        ctx->qos_data.def_qos_parm.ac[q].cw_min =
                cpu_to_le16(params->cw_min);
@@ -1161,7 +1174,7 @@ static int iwlagn_mac_conf_tx(struct ieee80211_hw *hw,
 
        ctx->qos_data.def_qos_parm.ac[q].reserved1 = 0;
 
-       spin_unlock_irqrestore(&priv->shrd->lock, flags);
+       mutex_unlock(&priv->mutex);
 
        IWL_DEBUG_MAC80211(priv, "leave\n");
        return 0;
@@ -1169,7 +1182,7 @@ static int iwlagn_mac_conf_tx(struct ieee80211_hw *hw,
 
 static int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw)
 {
-       struct iwl_priv *priv = hw->priv;
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 
        return priv->ibss_manager == IWL_IBSS_MANAGER;
 }
@@ -1189,7 +1202,7 @@ static int iwl_setup_interface(struct iwl_priv *priv,
        struct ieee80211_vif *vif = ctx->vif;
        int err;
 
-       lockdep_assert_held(&priv->shrd->mutex);
+       lockdep_assert_held(&priv->mutex);
 
        /*
         * This variable will be correct only when there's just
@@ -1223,7 +1236,7 @@ static int iwl_setup_interface(struct iwl_priv *priv,
 static int iwlagn_mac_add_interface(struct ieee80211_hw *hw,
                             struct ieee80211_vif *vif)
 {
-       struct iwl_priv *priv = hw->priv;
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
        struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
        struct iwl_rxon_context *tmp, *ctx = NULL;
        int err;
@@ -1234,11 +1247,11 @@ static int iwlagn_mac_add_interface(struct ieee80211_hw *hw,
 
        cancel_delayed_work_sync(&priv->hw_roc_disable_work);
 
-       mutex_lock(&priv->shrd->mutex);
+       mutex_lock(&priv->mutex);
 
        iwlagn_disable_roc(priv);
 
-       if (!iwl_is_ready_rf(priv->shrd)) {
+       if (!iwl_is_ready_rf(priv)) {
                IWL_WARN(priv, "Try to add interface when device not ready\n");
                err = -EINVAL;
                goto out;
@@ -1281,7 +1294,7 @@ static int iwlagn_mac_add_interface(struct ieee80211_hw *hw,
        ctx->vif = NULL;
        priv->iw_mode = NL80211_IFTYPE_STATION;
  out:
-       mutex_unlock(&priv->shrd->mutex);
+       mutex_unlock(&priv->mutex);
 
        IWL_DEBUG_MAC80211(priv, "leave\n");
        return err;
@@ -1293,7 +1306,7 @@ static void iwl_teardown_interface(struct iwl_priv *priv,
 {
        struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
 
-       lockdep_assert_held(&priv->shrd->mutex);
+       lockdep_assert_held(&priv->mutex);
 
        if (priv->scan_vif == vif) {
                iwl_scan_cancel_timeout(priv, 200);
@@ -1320,12 +1333,12 @@ static void iwl_teardown_interface(struct iwl_priv *priv,
 static void iwlagn_mac_remove_interface(struct ieee80211_hw *hw,
                              struct ieee80211_vif *vif)
 {
-       struct iwl_priv *priv = hw->priv;
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
        struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
 
        IWL_DEBUG_MAC80211(priv, "enter\n");
 
-       mutex_lock(&priv->shrd->mutex);
+       mutex_lock(&priv->mutex);
 
        if (WARN_ON(ctx->vif != vif)) {
                struct iwl_rxon_context *tmp;
@@ -1338,7 +1351,7 @@ static void iwlagn_mac_remove_interface(struct ieee80211_hw *hw,
 
        iwl_teardown_interface(priv, vif, false);
 
-       mutex_unlock(&priv->shrd->mutex);
+       mutex_unlock(&priv->mutex);
 
        IWL_DEBUG_MAC80211(priv, "leave\n");
 
@@ -1348,7 +1361,7 @@ 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_priv *priv = IWL_MAC80211_GET_DVM(hw);
        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;
@@ -1360,9 +1373,9 @@ static int iwlagn_mac_change_interface(struct ieee80211_hw *hw,
 
        newtype = ieee80211_iftype_p2p(newtype, newp2p);
 
-       mutex_lock(&priv->shrd->mutex);
+       mutex_lock(&priv->mutex);
 
-       if (!ctx->vif || !iwl_is_ready_rf(priv->shrd)) {
+       if (!ctx->vif || !iwl_is_ready_rf(priv)) {
                /*
                 * Huh? But wait ... this can maybe happen when
                 * we're in the middle of a firmware restart!
@@ -1424,7 +1437,7 @@ static int iwlagn_mac_change_interface(struct ieee80211_hw *hw,
        err = 0;
 
  out:
-       mutex_unlock(&priv->shrd->mutex);
+       mutex_unlock(&priv->mutex);
        IWL_DEBUG_MAC80211(priv, "leave\n");
 
        return err;
@@ -1434,7 +1447,7 @@ 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;
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
        int ret;
 
        IWL_DEBUG_MAC80211(priv, "enter\n");
@@ -1442,7 +1455,7 @@ static int iwlagn_mac_hw_scan(struct ieee80211_hw *hw,
        if (req->n_channels == 0)
                return -EINVAL;
 
-       mutex_lock(&priv->shrd->mutex);
+       mutex_lock(&priv->mutex);
 
        /*
         * If an internal scan is in progress, just set
@@ -1471,47 +1484,20 @@ static int iwlagn_mac_hw_scan(struct ieee80211_hw *hw,
 
        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");
+       mutex_unlock(&priv->mutex);
 
        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);
+       struct iwl_addsta_cmd cmd = {
+               .mode = STA_CONTROL_MODIFY_MSK,
+               .station_flags_msk = STA_FLG_PWR_SAVE_MSK,
+               .sta.sta_id = sta_id,
+       };
 
+       iwl_send_add_sta(priv, &cmd, CMD_ASYNC);
 }
 
 static void iwlagn_mac_sta_notify(struct ieee80211_hw *hw,
@@ -1519,7 +1505,7 @@ static void iwlagn_mac_sta_notify(struct ieee80211_hw *hw,
                           enum sta_notify_cmd cmd,
                           struct ieee80211_sta *sta)
 {
-       struct iwl_priv *priv = hw->priv;
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
        struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
        int sta_id;
 
@@ -1568,8 +1554,7 @@ struct ieee80211_ops iwlagn_hw_ops = {
        .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,
+       .sta_state = iwlagn_mac_sta_state,
        .channel_switch = iwlagn_mac_channel_switch,
        .flush = iwlagn_mac_flush,
        .tx_last_beacon = iwlagn_mac_tx_last_beacon,
@@ -1578,8 +1563,6 @@ struct ieee80211_ops iwlagn_hw_ops = {
        .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,
 };
 
@@ -1587,15 +1570,18 @@ struct ieee80211_ops iwlagn_hw_ops = {
 struct ieee80211_hw *iwl_alloc_all(void)
 {
        struct iwl_priv *priv;
+       struct iwl_op_mode *op_mode;
        /* 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);
+       hw = ieee80211_alloc_hw(sizeof(struct iwl_priv) +
+                               sizeof(struct iwl_op_mode), &iwlagn_hw_ops);
        if (!hw)
                goto out;
 
-       priv = hw->priv;
+       op_mode = hw->priv;
+       priv = IWL_OP_MODE_GET_DVM(op_mode);
        priv->hw = hw;
 
 out:
diff --git a/drivers/net/wireless/iwlwifi/iwl-notif-wait.c b/drivers/net/wireless/iwlwifi/iwl-notif-wait.c
new file mode 100644 (file)
index 0000000..88dc4a0
--- /dev/null
@@ -0,0 +1,157 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ *
+ * 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.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+#include <linux/sched.h>
+
+#include "iwl-notif-wait.h"
+
+
+void iwl_notification_wait_init(struct iwl_notif_wait_data *notif_wait)
+{
+       spin_lock_init(&notif_wait->notif_wait_lock);
+       INIT_LIST_HEAD(&notif_wait->notif_waits);
+       init_waitqueue_head(&notif_wait->notif_waitq);
+}
+
+void iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_wait,
+                                 struct iwl_rx_packet *pkt)
+{
+       if (!list_empty(&notif_wait->notif_waits)) {
+               struct iwl_notification_wait *w;
+
+               spin_lock(&notif_wait->notif_wait_lock);
+               list_for_each_entry(w, &notif_wait->notif_waits, list) {
+                       if (w->cmd != pkt->hdr.cmd)
+                               continue;
+                       w->triggered = true;
+                       if (w->fn)
+                               w->fn(notif_wait, pkt, w->fn_data);
+               }
+               spin_unlock(&notif_wait->notif_wait_lock);
+
+               wake_up_all(&notif_wait->notif_waitq);
+       }
+}
+
+void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_wait)
+{
+       unsigned long flags;
+       struct iwl_notification_wait *wait_entry;
+
+       spin_lock_irqsave(&notif_wait->notif_wait_lock, flags);
+       list_for_each_entry(wait_entry, &notif_wait->notif_waits, list)
+               wait_entry->aborted = true;
+       spin_unlock_irqrestore(&notif_wait->notif_wait_lock, flags);
+
+       wake_up_all(&notif_wait->notif_waitq);
+}
+
+
+void
+iwl_init_notification_wait(struct iwl_notif_wait_data *notif_wait,
+                          struct iwl_notification_wait *wait_entry,
+                          u8 cmd,
+                          void (*fn)(struct iwl_notif_wait_data *notif_wait,
+                                     struct iwl_rx_packet *pkt, void *data),
+                          void *fn_data)
+{
+       wait_entry->fn = fn;
+       wait_entry->fn_data = fn_data;
+       wait_entry->cmd = cmd;
+       wait_entry->triggered = false;
+       wait_entry->aborted = false;
+
+       spin_lock_bh(&notif_wait->notif_wait_lock);
+       list_add(&wait_entry->list, &notif_wait->notif_waits);
+       spin_unlock_bh(&notif_wait->notif_wait_lock);
+}
+
+int iwl_wait_notification(struct iwl_notif_wait_data *notif_wait,
+                         struct iwl_notification_wait *wait_entry,
+                         unsigned long timeout)
+{
+       int ret;
+
+       ret = wait_event_timeout(notif_wait->notif_waitq,
+                                wait_entry->triggered || wait_entry->aborted,
+                                timeout);
+
+       spin_lock_bh(&notif_wait->notif_wait_lock);
+       list_del(&wait_entry->list);
+       spin_unlock_bh(&notif_wait->notif_wait_lock);
+
+       if (wait_entry->aborted)
+               return -EIO;
+
+       /* return value is always >= 0 */
+       if (ret <= 0)
+               return -ETIMEDOUT;
+       return 0;
+}
+
+void iwl_remove_notification(struct iwl_notif_wait_data *notif_wait,
+                            struct iwl_notification_wait *wait_entry)
+{
+       spin_lock_bh(&notif_wait->notif_wait_lock);
+       list_del(&wait_entry->list);
+       spin_unlock_bh(&notif_wait->notif_wait_lock);
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-notif-wait.h b/drivers/net/wireless/iwlwifi/iwl-notif-wait.h
new file mode 100644 (file)
index 0000000..5e8af95
--- /dev/null
@@ -0,0 +1,129 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ *
+ * 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.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+#ifndef __iwl_notif_wait_h__
+#define __iwl_notif_wait_h__
+
+#include <linux/wait.h>
+
+#include "iwl-trans.h"
+
+struct iwl_notif_wait_data {
+       struct list_head notif_waits;
+       spinlock_t notif_wait_lock;
+       wait_queue_head_t notif_waitq;
+};
+
+/**
+ * struct iwl_notification_wait - notification wait entry
+ * @list: list head for global list
+ * @fn: function called with the notification
+ * @cmd: command ID
+ *
+ * This structure is not used directly, to wait for a
+ * notification declare it on the stack, and call
+ * iwlagn_init_notification_wait() with appropriate
+ * parameters. Then do whatever will cause the ucode
+ * to notify the driver, and to wait for that then
+ * call iwlagn_wait_notification().
+ *
+ * Each notification is one-shot. If at some point we
+ * need to support multi-shot notifications (which
+ * can't be allocated on the stack) we need to modify
+ * the code for them.
+ */
+struct iwl_notification_wait {
+       struct list_head list;
+
+       void (*fn)(struct iwl_notif_wait_data *notif_data,
+                  struct iwl_rx_packet *pkt, void *data);
+       void *fn_data;
+
+       u8 cmd;
+       bool triggered, aborted;
+};
+
+
+/* caller functions */
+void iwl_notification_wait_init(struct iwl_notif_wait_data *notif_data);
+void iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_data,
+                                 struct iwl_rx_packet *pkt);
+void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_data);
+
+/* user functions */
+void __acquires(wait_entry)
+iwl_init_notification_wait(struct iwl_notif_wait_data *notif_data,
+                          struct iwl_notification_wait *wait_entry,
+                          u8 cmd,
+                          void (*fn)(struct iwl_notif_wait_data *notif_data,
+                                     struct iwl_rx_packet *pkt, void *data),
+                          void *fn_data);
+
+int __must_check __releases(wait_entry)
+iwl_wait_notification(struct iwl_notif_wait_data *notif_data,
+                     struct iwl_notification_wait *wait_entry,
+                     unsigned long timeout);
+
+void __releases(wait_entry)
+iwl_remove_notification(struct iwl_notif_wait_data *notif_data,
+                       struct iwl_notification_wait *wait_entry);
+
+#endif /* __iwl_notif_wait_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/iwlwifi/iwl-op-mode.h
new file mode 100644 (file)
index 0000000..6ea4163
--- /dev/null
@@ -0,0 +1,216 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ *
+ * 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.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+#ifndef __iwl_op_mode_h__
+#define __iwl_op_mode_h__
+
+struct iwl_op_mode;
+struct iwl_trans;
+struct sk_buff;
+struct iwl_device_cmd;
+struct iwl_rx_cmd_buffer;
+struct iwl_fw;
+
+/**
+ * DOC: Operational mode - what is it ?
+ *
+ * The operational mode (a.k.a. op_mode) is the layer that implements
+ * mac80211's handlers. It knows two APIs: mac80211's and the fw's. It uses
+ * the transport API to access the HW. The op_mode doesn't need to know how the
+ * underlying HW works, since the transport layer takes care of that.
+ *
+ * There can be several op_mode: i.e. different fw APIs will require two
+ * different op_modes. This is why the op_mode is virtualized.
+ */
+
+/**
+ * DOC: Life cycle of the Operational mode
+ *
+ * The operational mode has a very simple life cycle.
+ *
+ *     1) The driver layer (iwl-drv.c) chooses the op_mode based on the
+ *        capabilities advertized by the fw file (in TLV format).
+ *     2) The driver layer starts the op_mode (ops->start)
+ *     3) The op_mode registers registers mac80211
+ *     4) The op_mode is governed by mac80211
+ *     5) The driver layer stops the op_mode
+ */
+
+/**
+ * struct iwl_op_mode_ops - op_mode specific operations
+ *
+ * The op_mode exports its ops so that external components can start it and
+ * interact with it. The driver layer typically calls the start and stop
+ * handlers, the transport layer calls the others.
+ *
+ * All the handlers MUST be implemented
+ *
+ * @start: start the op_mode. The transport layer is already allocated.
+ *     May sleep
+ * @stop: stop the op_mode. Must free all the memory allocated.
+ *     May sleep
+ * @rx: Rx notification to the op_mode. rxb is the Rx buffer itself. Cmd is the
+ *     HCMD the this Rx responds to.
+ *     Must be atomic.
+ * @queue_full: notifies that a HW queue is full. Ac is the ac of the queue
+ *     Must be atomic
+ * @queue_not_full: notifies that a HW queue is not full any more.
+ *     Ac is the ac of the queue. Must be atomic
+ * @hw_rf_kill:notifies of a change in the HW rf kill switch. True means that
+ *     the radio is killed. Must be atomic.
+ * @free_skb: allows the transport layer to free skbs that haven't been
+ *     reclaimed by the op_mode. This can happen when the driver is freed and
+ *     there are Tx packets pending in the transport layer.
+ *     Must be atomic
+ * @nic_error: error notification. Must be atomic
+ * @cmd_queue_full: Called when the command queue gets full. Must be atomic.
+ * @nic_config: configure NIC, called before firmware is started.
+ *     May sleep
+ */
+struct iwl_op_mode_ops {
+       struct iwl_op_mode *(*start)(struct iwl_trans *trans,
+                                    const struct iwl_fw *fw);
+       void (*stop)(struct iwl_op_mode *op_mode);
+       int (*rx)(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb,
+                 struct iwl_device_cmd *cmd);
+       void (*queue_full)(struct iwl_op_mode *op_mode, u8 ac);
+       void (*queue_not_full)(struct iwl_op_mode *op_mode, u8 ac);
+       void (*hw_rf_kill)(struct iwl_op_mode *op_mode, bool state);
+       void (*free_skb)(struct iwl_op_mode *op_mode, struct sk_buff *skb);
+       void (*nic_error)(struct iwl_op_mode *op_mode);
+       void (*cmd_queue_full)(struct iwl_op_mode *op_mode);
+       void (*nic_config)(struct iwl_op_mode *op_mode);
+};
+
+/**
+ * struct iwl_op_mode - operational mode
+ *
+ * This holds an implementation of the mac80211 / fw API.
+ *
+ * @ops - pointer to its own ops
+ */
+struct iwl_op_mode {
+       const struct iwl_op_mode_ops *ops;
+       const struct iwl_trans *trans;
+
+       char op_mode_specific[0] __aligned(sizeof(void *));
+};
+
+static inline void iwl_op_mode_stop(struct iwl_op_mode *op_mode)
+{
+       might_sleep();
+
+       op_mode->ops->stop(op_mode);
+}
+
+static inline int iwl_op_mode_rx(struct iwl_op_mode *op_mode,
+                                 struct iwl_rx_cmd_buffer *rxb,
+                                 struct iwl_device_cmd *cmd)
+{
+       return op_mode->ops->rx(op_mode, rxb, cmd);
+}
+
+static inline void iwl_op_mode_queue_full(struct iwl_op_mode *op_mode, u8 ac)
+{
+       op_mode->ops->queue_full(op_mode, ac);
+}
+
+static inline void iwl_op_mode_queue_not_full(struct iwl_op_mode *op_mode,
+                                             u8 ac)
+{
+       op_mode->ops->queue_not_full(op_mode, ac);
+}
+
+static inline void iwl_op_mode_hw_rf_kill(struct iwl_op_mode *op_mode,
+                                         bool state)
+{
+       op_mode->ops->hw_rf_kill(op_mode, state);
+}
+
+static inline void iwl_op_mode_free_skb(struct iwl_op_mode *op_mode,
+                                       struct sk_buff *skb)
+{
+       op_mode->ops->free_skb(op_mode, skb);
+}
+
+static inline void iwl_op_mode_nic_error(struct iwl_op_mode *op_mode)
+{
+       op_mode->ops->nic_error(op_mode);
+}
+
+static inline void iwl_op_mode_cmd_queue_full(struct iwl_op_mode *op_mode)
+{
+       op_mode->ops->cmd_queue_full(op_mode);
+}
+
+static inline void iwl_op_mode_nic_config(struct iwl_op_mode *op_mode)
+{
+       might_sleep();
+       op_mode->ops->nic_config(op_mode);
+}
+
+/*****************************************************
+* Op mode layers implementations
+******************************************************/
+extern const struct iwl_op_mode_ops iwl_dvm_ops;
+
+#endif /* __iwl_op_mode_h__ */
index 3e2fce4ce00c6c0768380313f5958a0ae6f01dce..c5e339ee918b03bb49c689eca7f33b0fc7ad592a 100644 (file)
 #include <linux/pci.h>
 #include <linux/pci-aspm.h>
 
-#include "iwl-bus.h"
 #include "iwl-io.h"
 #include "iwl-shared.h"
 #include "iwl-trans.h"
 #include "iwl-csr.h"
 #include "iwl-cfg.h"
+#include "iwl-drv.h"
+#include "iwl-trans.h"
 
 #define IWL_PCI_DEVICE(dev, subdev, cfg) \
        .vendor = PCI_VENDOR_ID_INTEL,  .device = (dev), \
@@ -157,9 +158,9 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
        {IWL_PCI_DEVICE(0x0085, 0x1316, iwl6005_2abg_cfg)},
        {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 */
+       {IWL_PCI_DEVICE(0x0082, 0x4820, iwl6005_2agn_d_cfg)},
+       {IWL_PCI_DEVICE(0x0082, 0x1304, iwl6005_2agn_mow1_cfg)},/* low 5GHz active */
+       {IWL_PCI_DEVICE(0x0082, 0x1305, iwl6005_2agn_mow2_cfg)},/* high 5GHz active */
 
 /* 6x30 Series */
        {IWL_PCI_DEVICE(0x008A, 0x5305, iwl1030_bgn_cfg)},
@@ -240,6 +241,7 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
        {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, 0x4860, iwl6035_2agn_cfg)},
 
 /* 105 Series */
        {IWL_PCI_DEVICE(0x0894, 0x0022, iwl105_bgn_cfg)},
@@ -261,72 +263,57 @@ MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
 
 static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-       struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data);
-       struct iwl_bus *bus;
+       const struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data);
+       struct iwl_shared *shrd;
+       struct iwl_trans *iwl_trans;
        int err;
 
-       bus = kzalloc(sizeof(*bus), GFP_KERNEL);
-       if (!bus) {
-               dev_printk(KERN_ERR, &pdev->dev,
-                          "Couldn't allocate iwl_pci_bus");
-               return -ENOMEM;
-       }
-
-       bus->shrd = kzalloc(sizeof(*bus->shrd), GFP_KERNEL);
-       if (!bus->shrd) {
+       shrd = kzalloc(sizeof(*iwl_trans->shrd), GFP_KERNEL);
+       if (!shrd) {
                dev_printk(KERN_ERR, &pdev->dev,
                           "Couldn't allocate iwl_shared");
                err = -ENOMEM;
                goto out_free_bus;
        }
 
-       bus->shrd->bus = bus;
-
-       pci_set_drvdata(pdev, bus);
-
 #ifdef CONFIG_IWLWIFI_IDI
-       trans(bus) = iwl_trans_idi_alloc(bus->shrd, pdev, ent);
-       if (trans(bus) == NULL) {
-               err = -ENOMEM;
-               goto out_free_bus;
-       }
-
-       err = iwl_probe(bus, &trans_ops_idi, cfg);
+       iwl_trans = iwl_trans_idi_alloc(shrd, pdev, ent);
 #else
-       trans(bus) = iwl_trans_pcie_alloc(bus->shrd, pdev, ent);
-       if (trans(bus) == NULL) {
+       iwl_trans = iwl_trans_pcie_alloc(shrd, pdev, ent);
+#endif
+       if (iwl_trans == NULL) {
                err = -ENOMEM;
                goto out_free_bus;
        }
 
-       err = iwl_probe(bus, &trans_ops_pcie, cfg);
-#endif
+       shrd->trans = iwl_trans;
+       pci_set_drvdata(pdev, iwl_trans);
+
+       err = iwl_drv_start(shrd, iwl_trans, cfg);
        if (err)
                goto out_free_trans;
 
        return 0;
 
 out_free_trans:
-       iwl_trans_free(trans(bus));
+       iwl_trans_free(iwl_trans);
        pci_set_drvdata(pdev, NULL);
 out_free_bus:
-       kfree(bus->shrd);
-       kfree(bus);
+       kfree(shrd);
        return err;
 }
 
 static void __devexit iwl_pci_remove(struct pci_dev *pdev)
 {
-       struct iwl_bus *bus = pci_get_drvdata(pdev);
-       struct iwl_shared *shrd = bus->shrd;
+       struct iwl_trans *iwl_trans = pci_get_drvdata(pdev);
+       struct iwl_shared *shrd = iwl_trans->shrd;
 
-       iwl_remove(shrd->priv);
+       iwl_drv_stop(shrd);
        iwl_trans_free(shrd->trans);
 
        pci_set_drvdata(pdev, NULL);
 
-       kfree(bus->shrd);
-       kfree(bus);
+       kfree(shrd);
 }
 
 #ifdef CONFIG_PM_SLEEP
@@ -334,22 +321,20 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
 static int iwl_pci_suspend(struct device *device)
 {
        struct pci_dev *pdev = to_pci_dev(device);
-       struct iwl_bus *bus = pci_get_drvdata(pdev);
-       struct iwl_shared *shrd = bus->shrd;
+       struct iwl_trans *iwl_trans = pci_get_drvdata(pdev);
 
        /* Before you put code here, think about WoWLAN. You cannot check here
         * whether WoWLAN is enabled or not, and your code will run even if
         * WoWLAN is enabled - don't kill the NIC, someone may need it in Sx.
         */
 
-       return iwl_trans_suspend(shrd->trans);
+       return iwl_trans_suspend(iwl_trans);
 }
 
 static int iwl_pci_resume(struct device *device)
 {
        struct pci_dev *pdev = to_pci_dev(device);
-       struct iwl_bus *bus = pci_get_drvdata(pdev);
-       struct iwl_shared *shrd = bus->shrd;
+       struct iwl_trans *iwl_trans = pci_get_drvdata(pdev);
 
        /* Before you put code here, think about WoWLAN. You cannot check here
         * whether WoWLAN is enabled or not, and your code will run even if
@@ -362,7 +347,7 @@ static int iwl_pci_resume(struct device *device)
         */
        pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00);
 
-       return iwl_trans_resume(shrd->trans);
+       return iwl_trans_resume(iwl_trans);
 }
 
 static SIMPLE_DEV_PM_OPS(iwl_dev_pm_ops, iwl_pci_suspend, iwl_pci_resume);
index fd008c4e41fd749eec780f98ce9ab988827373f9..958d9d09aee3f0e55137ac58b7095a535481591d 100644 (file)
@@ -215,7 +215,7 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv,
        else
                cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK;
 
-       if (hw_params(priv).shadow_reg_enable)
+       if (cfg(priv)->base_params->shadow_reg_enable)
                cmd->flags |= IWL_POWER_SHADOW_REG_ENA;
        else
                cmd->flags &= ~IWL_POWER_SHADOW_REG_ENA;
@@ -301,7 +301,7 @@ static void iwl_power_fill_sleep_cmd(struct iwl_priv *priv,
        if (priv->power_data.bus_pm)
                cmd->flags |= IWL_POWER_PCI_PM_MSK;
 
-       if (hw_params(priv).shadow_reg_enable)
+       if (cfg(priv)->base_params->shadow_reg_enable)
                cmd->flags |= IWL_POWER_SHADOW_REG_ENA;
        else
                cmd->flags &= ~IWL_POWER_SHADOW_REG_ENA;
@@ -336,7 +336,7 @@ static int iwl_set_power(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd)
                        le32_to_cpu(cmd->sleep_interval[3]),
                        le32_to_cpu(cmd->sleep_interval[4]));
 
-       return iwl_trans_send_cmd_pdu(trans(priv), POWER_TABLE_CMD, CMD_SYNC,
+       return iwl_dvm_send_cmd_pdu(priv, POWER_TABLE_CMD, CMD_SYNC,
                                sizeof(struct iwl_powertable_cmd), cmd);
 }
 
@@ -348,7 +348,7 @@ static void iwl_power_build_cmd(struct iwl_priv *priv,
 
        dtimper = priv->hw->conf.ps_dtim_period ?: 1;
 
-       if (priv->shrd->wowlan)
+       if (priv->wowlan)
                iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, dtimper);
        else if (!cfg(priv)->base_params->no_idle_support &&
                 priv->hw->conf.flags & IEEE80211_CONF_IDLE)
@@ -383,7 +383,7 @@ int iwl_power_set_mode(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd,
        int ret;
        bool update_chains;
 
-       lockdep_assert_held(&priv->shrd->mutex);
+       lockdep_assert_held(&priv->mutex);
 
        /* Don't update the RX chain when chain noise calibration is running */
        update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE ||
@@ -392,12 +392,12 @@ int iwl_power_set_mode(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd,
        if (!memcmp(&priv->power_data.sleep_cmd, cmd, sizeof(*cmd)) && !force)
                return 0;
 
-       if (!iwl_is_ready_rf(priv->shrd))
+       if (!iwl_is_ready_rf(priv))
                return -EIO;
 
        /* scan complete use sleep_power_next, need to be updated */
        memcpy(&priv->power_data.sleep_cmd_next, cmd, sizeof(*cmd));
-       if (test_bit(STATUS_SCANNING, &priv->shrd->status) && !force) {
+       if (test_bit(STATUS_SCANNING, &priv->status) && !force) {
                IWL_DEBUG_INFO(priv, "Defer power set mode while scanning\n");
                return 0;
        }
index a4d11016c3b46a9eea12c80180bc06d66e95b466..75dc20bd965b4d80715881b5657d099c75274854 100644 (file)
 #define SCD_TRANS_TBL_OFFSET_QUEUE(x) \
        ((SCD_TRANS_TBL_MEM_LOWER_BOUND + ((x) * 2)) & 0xfffc)
 
-#define SCD_QUEUECHAIN_SEL_ALL(priv)   \
-       (((1<<hw_params(priv).max_txq_num) - 1) &\
-       (~(1<<(priv)->shrd->cmd_queue)))
-
 #define SCD_BASE                       (PRPH_BASE + 0xa02c00)
 
 #define SCD_SRAM_BASE_ADDR     (SCD_BASE + 0x0)
index 7f2e3a1c80efeaea0ae6b7828cd05f6866c19173..902efe4bc89845e578a352d9f2565958f88d5e7a 100644 (file)
 static int iwl_send_scan_abort(struct iwl_priv *priv)
 {
        int ret;
-       struct iwl_rx_packet *pkt;
        struct iwl_host_cmd cmd = {
                .id = REPLY_SCAN_ABORT_CMD,
                .flags = CMD_SYNC | CMD_WANT_SKB,
        };
+       __le32 *status;
 
        /* Exit instantly with error when device is not ready
         * to receive scan abort command or it does not perform
         * hardware scan currently */
-       if (!test_bit(STATUS_READY, &priv->shrd->status) ||
-           !test_bit(STATUS_GEO_CONFIGURED, &priv->shrd->status) ||
-           !test_bit(STATUS_SCAN_HW, &priv->shrd->status) ||
-           test_bit(STATUS_FW_ERROR, &priv->shrd->status) ||
-           test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
+       if (!test_bit(STATUS_READY, &priv->status) ||
+           !test_bit(STATUS_GEO_CONFIGURED, &priv->status) ||
+           !test_bit(STATUS_SCAN_HW, &priv->status) ||
+           test_bit(STATUS_FW_ERROR, &priv->shrd->status))
                return -EIO;
 
-       ret = iwl_trans_send_cmd(trans(priv), &cmd);
+       ret = iwl_dvm_send_cmd(priv, &cmd);
        if (ret)
                return ret;
 
-       pkt = (struct iwl_rx_packet *)cmd.reply_page;
-       if (pkt->u.status != CAN_ABORT_STATUS) {
+       status = (void *)cmd.resp_pkt->data;
+       if (*status != CAN_ABORT_STATUS) {
                /* The scan abort will return 1 for success or
                 * 2 for "failure".  A failure condition can be
                 * due to simply not being in an active scan which
                 * can occur if we send the scan abort before we
                 * the microcode has notified us that a scan is
                 * completed. */
-               IWL_DEBUG_SCAN(priv, "SCAN_ABORT ret %d.\n", pkt->u.status);
+               IWL_DEBUG_SCAN(priv, "SCAN_ABORT ret %d.\n",
+                              le32_to_cpu(*status));
                ret = -EIO;
        }
 
-       iwl_free_pages(priv->shrd, cmd.reply_page);
+       iwl_free_resp(&cmd);
        return ret;
 }
 
@@ -116,20 +116,20 @@ static void iwl_process_scan_complete(struct iwl_priv *priv)
 {
        bool aborted;
 
-       lockdep_assert_held(&priv->shrd->mutex);
+       lockdep_assert_held(&priv->mutex);
 
-       if (!test_and_clear_bit(STATUS_SCAN_COMPLETE, &priv->shrd->status))
+       if (!test_and_clear_bit(STATUS_SCAN_COMPLETE, &priv->status))
                return;
 
        IWL_DEBUG_SCAN(priv, "Completed scan.\n");
 
        cancel_delayed_work(&priv->scan_check);
 
-       aborted = test_and_clear_bit(STATUS_SCAN_ABORTING, &priv->shrd->status);
+       aborted = test_and_clear_bit(STATUS_SCAN_ABORTING, &priv->status);
        if (aborted)
                IWL_DEBUG_SCAN(priv, "Aborted scan completed.\n");
 
-       if (!test_and_clear_bit(STATUS_SCANNING, &priv->shrd->status)) {
+       if (!test_and_clear_bit(STATUS_SCANNING, &priv->status)) {
                IWL_DEBUG_SCAN(priv, "Scan already completed.\n");
                goto out_settings;
        }
@@ -165,7 +165,7 @@ out_complete:
 
 out_settings:
        /* Can we still talk to firmware ? */
-       if (!iwl_is_ready_rf(priv->shrd))
+       if (!iwl_is_ready_rf(priv))
                return;
 
        iwlagn_post_scan(priv);
@@ -173,18 +173,18 @@ out_settings:
 
 void iwl_force_scan_end(struct iwl_priv *priv)
 {
-       lockdep_assert_held(&priv->shrd->mutex);
+       lockdep_assert_held(&priv->mutex);
 
-       if (!test_bit(STATUS_SCANNING, &priv->shrd->status)) {
+       if (!test_bit(STATUS_SCANNING, &priv->status)) {
                IWL_DEBUG_SCAN(priv, "Forcing scan end while not scanning\n");
                return;
        }
 
        IWL_DEBUG_SCAN(priv, "Forcing scan end\n");
-       clear_bit(STATUS_SCANNING, &priv->shrd->status);
-       clear_bit(STATUS_SCAN_HW, &priv->shrd->status);
-       clear_bit(STATUS_SCAN_ABORTING, &priv->shrd->status);
-       clear_bit(STATUS_SCAN_COMPLETE, &priv->shrd->status);
+       clear_bit(STATUS_SCANNING, &priv->status);
+       clear_bit(STATUS_SCAN_HW, &priv->status);
+       clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+       clear_bit(STATUS_SCAN_COMPLETE, &priv->status);
        iwl_complete_scan(priv, true);
 }
 
@@ -192,14 +192,14 @@ static void iwl_do_scan_abort(struct iwl_priv *priv)
 {
        int ret;
 
-       lockdep_assert_held(&priv->shrd->mutex);
+       lockdep_assert_held(&priv->mutex);
 
-       if (!test_bit(STATUS_SCANNING, &priv->shrd->status)) {
+       if (!test_bit(STATUS_SCANNING, &priv->status)) {
                IWL_DEBUG_SCAN(priv, "Not performing scan to abort\n");
                return;
        }
 
-       if (test_and_set_bit(STATUS_SCAN_ABORTING, &priv->shrd->status)) {
+       if (test_and_set_bit(STATUS_SCAN_ABORTING, &priv->status)) {
                IWL_DEBUG_SCAN(priv, "Scan abort in progress\n");
                return;
        }
@@ -218,7 +218,7 @@ static void iwl_do_scan_abort(struct iwl_priv *priv)
 int iwl_scan_cancel(struct iwl_priv *priv)
 {
        IWL_DEBUG_SCAN(priv, "Queuing abort scan\n");
-       queue_work(priv->shrd->workqueue, &priv->abort_scan);
+       queue_work(priv->workqueue, &priv->abort_scan);
        return 0;
 }
 
@@ -231,14 +231,14 @@ void iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
 {
        unsigned long timeout = jiffies + msecs_to_jiffies(ms);
 
-       lockdep_assert_held(&priv->shrd->mutex);
+       lockdep_assert_held(&priv->mutex);
 
        IWL_DEBUG_SCAN(priv, "Scan cancel timeout\n");
 
        iwl_do_scan_abort(priv);
 
        while (time_before_eq(jiffies, timeout)) {
-               if (!test_bit(STATUS_SCAN_HW, &priv->shrd->status))
+               if (!test_bit(STATUS_SCAN_HW, &priv->status))
                        goto finished;
                msleep(20);
        }
@@ -261,13 +261,12 @@ void iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
 
 /* Service response to REPLY_SCAN_CMD (0x80) */
 static int iwl_rx_reply_scan(struct iwl_priv *priv,
-                             struct iwl_rx_mem_buffer *rxb,
+                             struct iwl_rx_cmd_buffer *rxb,
                              struct iwl_device_cmd *cmd)
 {
 #ifdef CONFIG_IWLWIFI_DEBUG
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_scanreq_notification *notif =
-           (struct iwl_scanreq_notification *)pkt->u.raw;
+       struct iwl_scanreq_notification *notif = (void *)pkt->data;
 
        IWL_DEBUG_SCAN(priv, "Scan request status = 0x%x\n", notif->status);
 #endif
@@ -276,12 +275,12 @@ static int iwl_rx_reply_scan(struct iwl_priv *priv,
 
 /* Service SCAN_START_NOTIFICATION (0x82) */
 static int iwl_rx_scan_start_notif(struct iwl_priv *priv,
-                                   struct iwl_rx_mem_buffer *rxb,
+                                   struct iwl_rx_cmd_buffer *rxb,
                                    struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_scanstart_notification *notif =
-           (struct iwl_scanstart_notification *)pkt->u.raw;
+       struct iwl_scanstart_notification *notif = (void *)pkt->data;
+
        priv->scan_start_tsf = le32_to_cpu(notif->tsf_low);
        IWL_DEBUG_SCAN(priv, "Scan start: "
                       "%d [802.11%s] "
@@ -303,13 +302,12 @@ static int iwl_rx_scan_start_notif(struct iwl_priv *priv,
 
 /* Service SCAN_RESULTS_NOTIFICATION (0x83) */
 static int iwl_rx_scan_results_notif(struct iwl_priv *priv,
-                                     struct iwl_rx_mem_buffer *rxb,
+                                     struct iwl_rx_cmd_buffer *rxb,
                                      struct iwl_device_cmd *cmd)
 {
 #ifdef CONFIG_IWLWIFI_DEBUG
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_scanresults_notification *notif =
-           (struct iwl_scanresults_notification *)pkt->u.raw;
+       struct iwl_scanresults_notification *notif = (void *)pkt->data;
 
        IWL_DEBUG_SCAN(priv, "Scan ch.res: "
                       "%d [802.11%s] "
@@ -329,11 +327,11 @@ static int iwl_rx_scan_results_notif(struct iwl_priv *priv,
 
 /* Service SCAN_COMPLETE_NOTIFICATION (0x84) */
 static int iwl_rx_scan_complete_notif(struct iwl_priv *priv,
-                                      struct iwl_rx_mem_buffer *rxb,
+                                      struct iwl_rx_cmd_buffer *rxb,
                                       struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw;
+       struct iwl_scancomplete_notification *scan_notif = (void *)pkt->data;
 
        IWL_DEBUG_SCAN(priv, "Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n",
                       scan_notif->scanned_channels,
@@ -352,9 +350,9 @@ static int iwl_rx_scan_complete_notif(struct iwl_priv *priv,
         * to clear, we need to set SCAN_COMPLETE before clearing SCAN_HW
         * to avoid a race there.
         */
-       set_bit(STATUS_SCAN_COMPLETE, &priv->shrd->status);
-       clear_bit(STATUS_SCAN_HW, &priv->shrd->status);
-       queue_work(priv->shrd->workqueue, &priv->scan_completed);
+       set_bit(STATUS_SCAN_COMPLETE, &priv->status);
+       clear_bit(STATUS_SCAN_HW, &priv->status);
+       queue_work(priv->workqueue, &priv->scan_completed);
 
        if (priv->iw_mode != NL80211_IFTYPE_ADHOC &&
            iwl_advanced_bt_coexist(priv) &&
@@ -374,7 +372,7 @@ static int iwl_rx_scan_complete_notif(struct iwl_priv *priv,
                                IWL_BT_COEX_TRAFFIC_LOAD_NONE;
                }
                priv->bt_status = scan_notif->bt_status;
-               queue_work(priv->shrd->workqueue,
+               queue_work(priv->workqueue,
                           &priv->bt_traffic_change_work);
        }
        return 0;
@@ -574,6 +572,53 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
        return added;
 }
 
+/**
+ * iwl_fill_probe_req - fill in all required fields and IE for probe request
+ */
+
+static u16 iwl_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta,
+                             const u8 *ies, int ie_len, int left)
+{
+       int len = 0;
+       u8 *pos = NULL;
+
+       /* Make sure there is enough space for the probe request,
+        * two mandatory IEs and the data */
+       left -= 24;
+       if (left < 0)
+               return 0;
+
+       frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
+       memcpy(frame->da, iwl_bcast_addr, ETH_ALEN);
+       memcpy(frame->sa, ta, ETH_ALEN);
+       memcpy(frame->bssid, iwl_bcast_addr, ETH_ALEN);
+       frame->seq_ctrl = 0;
+
+       len += 24;
+
+       /* ...next IE... */
+       pos = &frame->u.probe_req.variable[0];
+
+       /* fill in our indirect SSID IE */
+       left -= 2;
+       if (left < 0)
+               return 0;
+       *pos++ = WLAN_EID_SSID;
+       *pos++ = 0;
+
+       len += 2;
+
+       if (WARN_ON(left < ie_len))
+               return len;
+
+       if (ies && ie_len) {
+               memcpy(pos, ies, ie_len);
+               len += ie_len;
+       }
+
+       return (u16)len;
+}
+
 static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
        struct iwl_host_cmd cmd = {
@@ -596,7 +641,7 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
        u8 scan_tx_antennas = hw_params(priv).valid_tx_ant;
        int ret;
 
-       lockdep_assert_held(&priv->shrd->mutex);
+       lockdep_assert_held(&priv->mutex);
 
        if (vif)
                ctx = iwl_rxon_ctx_from_vif(vif);
@@ -793,7 +838,7 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
        scan->rx_chain = cpu_to_le16(rx_chain);
        switch (priv->scan_type) {
        case IWL_SCAN_NORMAL:
-               cmd_len = iwl_fill_probe_req(priv,
+               cmd_len = iwl_fill_probe_req(
                                        (struct ieee80211_mgmt *)scan->data,
                                        vif->addr,
                                        priv->scan_request->ie,
@@ -803,7 +848,7 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
        case IWL_SCAN_RADIO_RESET:
        case IWL_SCAN_ROC:
                /* use bcast addr, will not be transmitted but must be valid */
-               cmd_len = iwl_fill_probe_req(priv,
+               cmd_len = iwl_fill_probe_req(
                                        (struct ieee80211_mgmt *)scan->data,
                                        iwl_bcast_addr, NULL, 0,
                                        IWL_MAX_SCAN_SIZE - sizeof(*scan));
@@ -882,15 +927,15 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
        scan->len = cpu_to_le16(cmd.len[0]);
 
        /* set scan bit here for PAN params */
-       set_bit(STATUS_SCAN_HW, &priv->shrd->status);
+       set_bit(STATUS_SCAN_HW, &priv->status);
 
        ret = iwlagn_set_pan_params(priv);
        if (ret)
                return ret;
 
-       ret = iwl_trans_send_cmd(trans(priv), &cmd);
+       ret = iwl_dvm_send_cmd(priv, &cmd);
        if (ret) {
-               clear_bit(STATUS_SCAN_HW, &priv->shrd->status);
+               clear_bit(STATUS_SCAN_HW, &priv->status);
                iwlagn_set_pan_params(priv);
        }
 
@@ -913,22 +958,22 @@ int __must_check iwl_scan_initiate(struct iwl_priv *priv,
 {
        int ret;
 
-       lockdep_assert_held(&priv->shrd->mutex);
+       lockdep_assert_held(&priv->mutex);
 
        cancel_delayed_work(&priv->scan_check);
 
-       if (!iwl_is_ready_rf(priv->shrd)) {
+       if (!iwl_is_ready_rf(priv)) {
                IWL_WARN(priv, "Request scan called when driver not ready.\n");
                return -EIO;
        }
 
-       if (test_bit(STATUS_SCAN_HW, &priv->shrd->status)) {
+       if (test_bit(STATUS_SCAN_HW, &priv->status)) {
                IWL_DEBUG_SCAN(priv,
                        "Multiple concurrent scan requests in parallel.\n");
                return -EBUSY;
        }
 
-       if (test_bit(STATUS_SCAN_ABORTING, &priv->shrd->status)) {
+       if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
                IWL_DEBUG_SCAN(priv, "Scan request while abort pending.\n");
                return -EBUSY;
        }
@@ -938,19 +983,19 @@ int __must_check iwl_scan_initiate(struct iwl_priv *priv,
                        scan_type == IWL_SCAN_ROC ? "remain-on-channel " :
                        "internal short ");
 
-       set_bit(STATUS_SCANNING, &priv->shrd->status);
+       set_bit(STATUS_SCANNING, &priv->status);
        priv->scan_type = scan_type;
        priv->scan_start = jiffies;
        priv->scan_band = band;
 
        ret = iwlagn_request_scan(priv, vif);
        if (ret) {
-               clear_bit(STATUS_SCANNING, &priv->shrd->status);
+               clear_bit(STATUS_SCANNING, &priv->status);
                priv->scan_type = IWL_SCAN_NORMAL;
                return ret;
        }
 
-       queue_delayed_work(priv->shrd->workqueue, &priv->scan_check,
+       queue_delayed_work(priv->workqueue, &priv->scan_check,
                           IWL_SCAN_CHECK_WATCHDOG);
 
        return 0;
@@ -963,7 +1008,7 @@ int __must_check iwl_scan_initiate(struct iwl_priv *priv,
  */
 void iwl_internal_short_hw_scan(struct iwl_priv *priv)
 {
-       queue_work(priv->shrd->workqueue, &priv->start_internal_scan);
+       queue_work(priv->workqueue, &priv->start_internal_scan);
 }
 
 static void iwl_bg_start_internal_scan(struct work_struct *work)
@@ -973,14 +1018,14 @@ static void iwl_bg_start_internal_scan(struct work_struct *work)
 
        IWL_DEBUG_SCAN(priv, "Start internal scan\n");
 
-       mutex_lock(&priv->shrd->mutex);
+       mutex_lock(&priv->mutex);
 
        if (priv->scan_type == IWL_SCAN_RADIO_RESET) {
                IWL_DEBUG_SCAN(priv, "Internal scan already in progress\n");
                goto unlock;
        }
 
-       if (test_bit(STATUS_SCANNING, &priv->shrd->status)) {
+       if (test_bit(STATUS_SCANNING, &priv->status)) {
                IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
                goto unlock;
        }
@@ -988,7 +1033,7 @@ static void iwl_bg_start_internal_scan(struct work_struct *work)
        if (iwl_scan_initiate(priv, NULL, IWL_SCAN_RADIO_RESET, priv->band))
                IWL_DEBUG_SCAN(priv, "failed to start internal short scan\n");
  unlock:
-       mutex_unlock(&priv->shrd->mutex);
+       mutex_unlock(&priv->mutex);
 }
 
 static void iwl_bg_scan_check(struct work_struct *data)
@@ -1001,56 +1046,9 @@ static void iwl_bg_scan_check(struct work_struct *data)
        /* Since we are here firmware does not finish scan and
         * most likely is in bad shape, so we don't bother to
         * send abort command, just force scan complete to mac80211 */
-       mutex_lock(&priv->shrd->mutex);
+       mutex_lock(&priv->mutex);
        iwl_force_scan_end(priv);
-       mutex_unlock(&priv->shrd->mutex);
-}
-
-/**
- * iwl_fill_probe_req - fill in all required fields and IE for probe request
- */
-
-u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
-                      const u8 *ta, const u8 *ies, int ie_len, int left)
-{
-       int len = 0;
-       u8 *pos = NULL;
-
-       /* Make sure there is enough space for the probe request,
-        * two mandatory IEs and the data */
-       left -= 24;
-       if (left < 0)
-               return 0;
-
-       frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
-       memcpy(frame->da, iwl_bcast_addr, ETH_ALEN);
-       memcpy(frame->sa, ta, ETH_ALEN);
-       memcpy(frame->bssid, iwl_bcast_addr, ETH_ALEN);
-       frame->seq_ctrl = 0;
-
-       len += 24;
-
-       /* ...next IE... */
-       pos = &frame->u.probe_req.variable[0];
-
-       /* fill in our indirect SSID IE */
-       left -= 2;
-       if (left < 0)
-               return 0;
-       *pos++ = WLAN_EID_SSID;
-       *pos++ = 0;
-
-       len += 2;
-
-       if (WARN_ON(left < ie_len))
-               return len;
-
-       if (ies && ie_len) {
-               memcpy(pos, ies, ie_len);
-               len += ie_len;
-       }
-
-       return (u16)len;
+       mutex_unlock(&priv->mutex);
 }
 
 static void iwl_bg_abort_scan(struct work_struct *work)
@@ -1061,9 +1059,9 @@ static void iwl_bg_abort_scan(struct work_struct *work)
 
        /* We keep scan_check work queued in case when firmware will not
         * report back scan completed notification */
-       mutex_lock(&priv->shrd->mutex);
+       mutex_lock(&priv->mutex);
        iwl_scan_cancel_timeout(priv, 200);
-       mutex_unlock(&priv->shrd->mutex);
+       mutex_unlock(&priv->mutex);
 }
 
 static void iwl_bg_scan_completed(struct work_struct *work)
@@ -1071,9 +1069,9 @@ static void iwl_bg_scan_completed(struct work_struct *work)
        struct iwl_priv *priv =
                container_of(work, struct iwl_priv, scan_completed);
 
-       mutex_lock(&priv->shrd->mutex);
+       mutex_lock(&priv->mutex);
        iwl_process_scan_complete(priv);
-       mutex_unlock(&priv->shrd->mutex);
+       mutex_unlock(&priv->mutex);
 }
 
 void iwl_setup_scan_deferred_work(struct iwl_priv *priv)
@@ -1091,8 +1089,8 @@ void iwl_cancel_scan_deferred_work(struct iwl_priv *priv)
        cancel_work_sync(&priv->scan_completed);
 
        if (cancel_delayed_work_sync(&priv->scan_check)) {
-               mutex_lock(&priv->shrd->mutex);
+               mutex_lock(&priv->mutex);
                iwl_force_scan_end(priv);
-               mutex_unlock(&priv->shrd->mutex);
+               mutex_unlock(&priv->mutex);
        }
 }
index 63d4a4fc5b9e38586389a6ead2eae59f50730e66..cf34087aa2fe8445a714b3a916fb5dfb3dc59c1b 100644 (file)
 
 #include <linux/types.h>
 #include <linux/spinlock.h>
-#include <linux/mutex.h>
 #include <linux/gfp.h>
-#include <linux/mm.h> /* for page_address */
 #include <net/mac80211.h>
 
 #include "iwl-commands.h"
+#include "iwl-fw.h"
 
 /**
  * DOC: shared area - role and goal
@@ -94,7 +93,6 @@
  * This implementation is iwl-pci.c
  */
 
-struct iwl_bus;
 struct iwl_priv;
 struct iwl_trans;
 struct iwl_sensitivity_ranges;
@@ -117,7 +115,6 @@ extern struct iwl_mod_params iwlagn_mod_params;
  * Holds the module parameters
  *
  * @sw_crypto: using hardware encryption, default = 0
- * @num_of_queues: number of tx queue, HW dependent
  * @disable_11n: disable 11n capabilities, default = 0,
  *     use IWL_DISABLE_HT_* constants
  * @amsdu_size_8K: enable 8K amsdu size, default = 1
@@ -139,7 +136,6 @@ extern struct iwl_mod_params iwlagn_mod_params;
  */
 struct iwl_mod_params {
        int sw_crypto;
-       int num_of_queues;
        unsigned int disable_11n;
        int amsdu_size_8K;
        int antenna;
@@ -164,7 +160,6 @@ struct iwl_mod_params {
  *
  * Holds the module parameters
  *
- * @max_txq_num: Max # Tx queues supported
  * @num_ampdu_queues: num of ampdu queues
  * @tx_chains_num: Number of TX chains
  * @rx_chains_num: Number of RX chains
@@ -173,27 +168,23 @@ struct iwl_mod_params {
  * @ht40_channel: is 40MHz width possible: BIT(IEEE80211_BAND_XXX)
  * @sku: sku read from EEPROM
  * @rx_page_order: Rx buffer page order
- * @max_inst_size: for ucode use
- * @max_data_size: for ucode use
  * @ct_kill_threshold: temperature threshold - in hw dependent unit
  * @ct_kill_exit_threshold: when to reeable the device - in hw dependent unit
  *     relevant for 1000, 6000 and up
  * @wd_timeout: TX queues watchdog timeout
  * @struct iwl_sensitivity_ranges: range of sensitivity values
+ * @use_rts_for_aggregation: use rts/cts protection for HT traffic
  */
 struct iwl_hw_params {
-       u8  max_txq_num;
        u8  num_ampdu_queues;
        u8  tx_chains_num;
        u8  rx_chains_num;
        u8  valid_tx_ant;
        u8  valid_rx_ant;
        u8  ht40_channel;
-       bool shadow_reg_enable;
+       bool use_rts_for_aggregation;
        u16 sku;
        u32 rx_page_order;
-       u32 max_inst_size;
-       u32 max_data_size;
        u32 ct_kill_threshold;
        u32 ct_kill_exit_threshold;
        unsigned int wd_timeout;
@@ -218,45 +209,6 @@ enum iwl_ucode_type {
        IWL_UCODE_WOWLAN,
 };
 
-/**
- * struct iwl_notification_wait - notification wait entry
- * @list: list head for global list
- * @fn: function called with the notification
- * @cmd: command ID
- *
- * This structure is not used directly, to wait for a
- * notification declare it on the stack, and call
- * iwlagn_init_notification_wait() with appropriate
- * parameters. Then do whatever will cause the ucode
- * to notify the driver, and to wait for that then
- * call iwlagn_wait_notification().
- *
- * Each notification is one-shot. If at some point we
- * need to support multi-shot notifications (which
- * can't be allocated on the stack) we need to modify
- * the code for them.
- */
-struct iwl_notification_wait {
-       struct list_head list;
-
-       void (*fn)(struct iwl_trans *trans, struct iwl_rx_packet *pkt,
-                  void *data);
-       void *fn_data;
-
-       u8 cmd;
-       bool triggered, aborted;
-};
-
-/**
- * enum iwl_pa_type - Power Amplifier type
- * @IWL_PA_SYSTEM:  based on uCode configuration
- * @IWL_PA_INTERNAL: use Internal only
- */
-enum iwl_pa_type {
-       IWL_PA_SYSTEM = 0,
-       IWL_PA_INTERNAL = 1,
-};
-
 /*
  * LED mode
  *    IWL_LED_DEFAULT:  use device default
@@ -273,6 +225,73 @@ enum iwl_led_mode {
        IWL_LED_DISABLE,
 };
 
+/*
+ * @max_ll_items: max number of OTP blocks
+ * @shadow_ram_support: shadow support for OTP memory
+ * @led_compensation: compensate on the led on/off time per HW according
+ *     to the deviation to achieve the desired led frequency.
+ *     The detail algorithm is described in iwl-led.c
+ * @chain_noise_num_beacons: number of beacons used to compute chain noise
+ * @adv_thermal_throttle: support advance thermal throttle
+ * @support_ct_kill_exit: support ct kill exit condition
+ * @support_wimax_coexist: support wimax/wifi co-exist
+ * @plcp_delta_threshold: plcp error rate threshold used to trigger
+ *     radio tuning when there is a high receiving plcp error rate
+ * @chain_noise_scale: default chain noise scale used for gain computation
+ * @wd_timeout: TX queues watchdog timeout
+ * @max_event_log_size: size of event log buffer size for ucode event logging
+ * @shadow_reg_enable: HW shadhow register bit
+ * @hd_v2: v2 of enhanced sensitivity value, used for 2000 series and up
+ * @no_idle_support: do not support idle mode
+ * wd_disable: disable watchdog timer
+ */
+struct iwl_base_params {
+       int eeprom_size;
+       int num_of_queues;      /* def: HW dependent */
+       int num_of_ampdu_queues;/* def: HW dependent */
+       /* for iwl_apm_init() */
+       u32 pll_cfg_val;
+
+       const u16 max_ll_items;
+       const bool shadow_ram_support;
+       u16 led_compensation;
+       bool adv_thermal_throttle;
+       bool support_ct_kill_exit;
+       const bool support_wimax_coexist;
+       u8 plcp_delta_threshold;
+       s32 chain_noise_scale;
+       unsigned int wd_timeout;
+       u32 max_event_log_size;
+       const bool shadow_reg_enable;
+       const bool hd_v2;
+       const bool no_idle_support;
+       const bool wd_disable;
+};
+
+/*
+ * @advanced_bt_coexist: support advanced bt coexist
+ * @bt_init_traffic_load: specify initial bt traffic load
+ * @bt_prio_boost: default bt priority boost value
+ * @agg_time_limit: maximum number of uSec in aggregation
+ * @bt_sco_disable: uCode should not response to BT in SCO/ESCO mode
+ */
+struct iwl_bt_params {
+       bool advanced_bt_coexist;
+       u8 bt_init_traffic_load;
+       u8 bt_prio_boost;
+       u16 agg_time_limit;
+       bool bt_sco_disable;
+       bool bt_session_2;
+};
+/*
+ * @use_rts_for_aggregation: use rts/cts protection for HT traffic
+ */
+struct iwl_ht_params {
+       const bool ht_greenfield_support; /* if used set to true */
+       bool use_rts_for_aggregation;
+       enum ieee80211_smps_mode smps_mode;
+};
+
 /**
  * struct iwl_cfg
  * @name: Offical name of the device
@@ -283,9 +302,10 @@ enum iwl_led_mode {
  * @ucode_api_ok: oldest version of the uCode API that is OK to load
  *     without a warning, for use in transitions
  * @ucode_api_min: Lowest version of uCode API supported by driver.
+ * @max_inst_size: The maximal length of the fw inst section
+ * @max_data_size: The maximal length of the fw data section
  * @valid_tx_ant: valid transmit antenna
  * @valid_rx_ant: valid receive antenna
- * @sku: sku information from EEPROM
  * @eeprom_ver: EEPROM version
  * @eeprom_calib_ver: EEPROM calibration version
  * @lib: pointer to the lib ops
@@ -293,7 +313,6 @@ enum iwl_led_mode {
  * @base_params: pointer to basic parameters
  * @ht_params: point to ht patameters
  * @bt_params: pointer to bt parameters
- * @pa_type: used by 6000 series only to identify the type of Power Amplifier
  * @need_temp_offset_calib: need to perform temperature offset calibration
  * @no_xtal_calib: some devices do not need crystal calibration data,
  *     don't send it to those
@@ -320,19 +339,19 @@ struct iwl_cfg {
        const unsigned int ucode_api_max;
        const unsigned int ucode_api_ok;
        const unsigned int ucode_api_min;
+       const u32 max_data_size;
+       const u32 max_inst_size;
        u8   valid_tx_ant;
        u8   valid_rx_ant;
-       u16  sku;
        u16  eeprom_ver;
        u16  eeprom_calib_ver;
        const struct iwl_lib_ops *lib;
        void (*additional_nic_config)(struct iwl_priv *priv);
        /* params not likely to change within a device family */
-       struct iwl_base_params *base_params;
+       const struct iwl_base_params *base_params;
        /* params likely to change within a device family */
-       struct iwl_ht_params *ht_params;
-       struct iwl_bt_params *bt_params;
-       enum iwl_pa_type pa_type;         /* if used set to IWL_PA_SYSTEM */
+       const struct iwl_ht_params *ht_params;
+       const struct iwl_bt_params *bt_params;
        const bool need_temp_offset_calib; /* if used set to true */
        const bool no_xtal_calib;
        u8 scan_rx_antennas[IEEE80211_NUM_BANDS];
@@ -347,10 +366,6 @@ struct iwl_cfg {
 /**
  * struct iwl_shared - shared fields for all the layers of the driver
  *
- * @dbg_level_dev: dbg level set per device. Prevails on
- *     iwlagn_mod_params.debug_level if set (!= 0)
- * @ucode_owner: IWL_OWNERSHIP_*
- * @cmd_queue: command queue number
  * @status: STATUS_*
  * @wowlan: are we running wowlan uCode
  * @valid_contexts: microcode/device supports multiple contexts
@@ -358,43 +373,23 @@ struct iwl_cfg {
  * @cfg: see struct iwl_cfg
  * @priv: pointer to the upper layer data
  * @trans: pointer to the transport layer data
+ * @nic: pointer to the nic data
  * @hw_params: see struct iwl_hw_params
- * @workqueue: the workqueue used by all the layers of the driver
  * @lock: protect general shared data
- * @sta_lock: protects the station table.
- *     If lock and sta_lock are needed, lock must be acquired first.
- * @mutex:
- * @wait_command_queue: the wait_queue for SYNC host command nad uCode load
+ * @wait_command_queue: the wait_queue for SYNC host commands
  * @eeprom: pointer to the eeprom/OTP image
  * @ucode_type: indicator of loaded ucode image
- * @notif_waits: things waiting for notification
- * @notif_wait_lock: lock protecting notification
- * @notif_waitq: head of notification wait queue
  * @device_pointers: pointers to ucode event tables
  */
 struct iwl_shared {
-#ifdef CONFIG_IWLWIFI_DEBUG
-       u32 dbg_level_dev;
-#endif /* CONFIG_IWLWIFI_DEBUG */
-
-#define IWL_OWNERSHIP_DRIVER   0
-#define IWL_OWNERSHIP_TM       1
-       u8 ucode_owner;
-       u8 cmd_queue;
        unsigned long status;
-       bool wowlan;
        u8 valid_contexts;
 
-       struct iwl_bus *bus;
-       struct iwl_cfg *cfg;
-       struct iwl_priv *priv;
+       const struct iwl_cfg *cfg;
        struct iwl_trans *trans;
+       void *drv;
        struct iwl_hw_params hw_params;
-
-       struct workqueue_struct *workqueue;
-       spinlock_t lock;
-       spinlock_t sta_lock;
-       struct mutex mutex;
+       const struct iwl_fw *fw;
 
        wait_queue_head_t wait_command_queue;
 
@@ -404,11 +399,6 @@ struct iwl_shared {
        /* ucode related variables */
        enum iwl_ucode_type ucode_type;
 
-       /* notification wait support */
-       struct list_head notif_waits;
-       spinlock_t notif_wait_lock;
-       wait_queue_head_t notif_waitq;
-
        struct {
                u32 error_event_table;
                u32 log_event_table;
@@ -416,112 +406,14 @@ struct iwl_shared {
 
 };
 
-/*Whatever _m is (iwl_trans, iwl_priv, iwl_bus, these macros will work */
-#define priv(_m)       ((_m)->shrd->priv)
+/*Whatever _m is (iwl_trans, iwl_priv, these macros will work */
 #define cfg(_m)                ((_m)->shrd->cfg)
-#define bus(_m)                ((_m)->shrd->bus)
 #define trans(_m)      ((_m)->shrd->trans)
 #define hw_params(_m)  ((_m)->shrd->hw_params)
 
-#ifdef CONFIG_IWLWIFI_DEBUG
-/*
- * iwl_get_debug_level: Return active debug level for device
- *
- * Using sysfs it is possible to set per device debug level. This debug
- * level will be used if set, otherwise the global debug level which can be
- * set via module parameter is used.
- */
-static inline u32 iwl_get_debug_level(struct iwl_shared *shrd)
-{
-       if (shrd->dbg_level_dev)
-               return shrd->dbg_level_dev;
-       else
-               return iwlagn_mod_params.debug_level;
-}
-#else
-static inline u32 iwl_get_debug_level(struct iwl_shared *shrd)
-{
-       return iwlagn_mod_params.debug_level;
-}
-#endif
-
-static inline void iwl_free_pages(struct iwl_shared *shrd, unsigned long page)
-{
-       free_pages(page, shrd->hw_params.rx_page_order);
-}
-
-/**
- * iwl_queue_inc_wrap - increment queue index, wrap back to beginning
- * @index -- current index
- * @n_bd -- total number of entries in queue (must be power of 2)
- */
-static inline int iwl_queue_inc_wrap(int index, int n_bd)
-{
-       return ++index & (n_bd - 1);
-}
-
-/**
- * iwl_queue_dec_wrap - decrement queue index, wrap back to end
- * @index -- current index
- * @n_bd -- total number of entries in queue (must be power of 2)
- */
-static inline int iwl_queue_dec_wrap(int index, int n_bd)
-{
-       return --index & (n_bd - 1);
-}
-
-struct iwl_rx_mem_buffer {
-       dma_addr_t page_dma;
-       struct page *page;
-       struct list_head list;
-};
-
-#define rxb_addr(r) page_address(r->page)
-
-/*
- * mac80211 queues, ACs, hardware queues, FIFOs.
- *
- * Cf. http://wireless.kernel.org/en/developers/Documentation/mac80211/queues
- *
- * Mac80211 uses the following numbers, which we get as from it
- * by way of skb_get_queue_mapping(skb):
- *
- *     VO      0
- *     VI      1
- *     BE      2
- *     BK      3
- *
- *
- * Regular (not A-MPDU) frames are put into hardware queues corresponding
- * to the FIFOs, see comments in iwl-prph.h. Aggregated frames get their
- * own queue per aggregation session (RA/TID combination), such queues are
- * set up to map into FIFOs too, for which we need an AC->FIFO mapping. In
- * order to map frames to the right queue, we also need an AC->hw queue
- * mapping. This is implemented here.
- *
- * Due to the way hw queues are set up (by the hw specific modules like
- * iwl-4965.c, iwl-5000.c etc.), the AC->hw queue mapping is the identity
- * mapping.
- */
-
-static const u8 tid_to_ac[] = {
-       IEEE80211_AC_BE,
-       IEEE80211_AC_BK,
-       IEEE80211_AC_BK,
-       IEEE80211_AC_BE,
-       IEEE80211_AC_VI,
-       IEEE80211_AC_VI,
-       IEEE80211_AC_VO,
-       IEEE80211_AC_VO
-};
-
-static inline int get_ac_from_tid(u16 tid)
+static inline bool iwl_have_debug_level(u32 level)
 {
-       if (likely(tid < ARRAY_SIZE(tid_to_ac)))
-               return tid_to_ac[tid];
-
-       /* no support for TIDs 8-15 yet */
-       return -EINVAL;
+       return iwlagn_mod_params.debug_level & level;
 }
 
 enum iwl_rxon_context_id {
@@ -531,62 +423,10 @@ enum iwl_rxon_context_id {
        NUM_IWL_RXON_CTX
 };
 
-int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops,
-               struct iwl_cfg *cfg);
-void __devexit iwl_remove(struct iwl_priv * priv);
-struct iwl_device_cmd;
-int __must_check iwl_rx_dispatch(struct iwl_priv *priv,
-                                struct iwl_rx_mem_buffer *rxb,
-                                struct iwl_device_cmd *cmd);
-
 int iwlagn_hw_valid_rtc_data_addr(u32 addr);
-void iwl_set_hw_rfkill_state(struct iwl_priv *priv, bool state);
-void iwl_nic_config(struct iwl_priv *priv);
-void iwl_free_skb(struct iwl_priv *priv, struct sk_buff *skb);
-void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand);
 const char *get_cmd_string(u8 cmd);
-bool iwl_check_for_ct_kill(struct iwl_priv *priv);
-
-void iwl_stop_sw_queue(struct iwl_priv *priv, u8 ac);
-void iwl_wake_sw_queue(struct iwl_priv *priv, u8 ac);
-
-/* notification wait support */
-void iwl_abort_notification_waits(struct iwl_shared *shrd);
-void __acquires(wait_entry)
-iwl_init_notification_wait(struct iwl_shared *shrd,
-                             struct iwl_notification_wait *wait_entry,
-                             u8 cmd,
-                             void (*fn)(struct iwl_trans *trans,
-                                        struct iwl_rx_packet *pkt,
-                                        void *data),
-                             void *fn_data);
-int __must_check __releases(wait_entry)
-iwl_wait_notification(struct iwl_shared *shrd,
-                        struct iwl_notification_wait *wait_entry,
-                        unsigned long timeout);
-void __releases(wait_entry)
-iwl_remove_notification(struct iwl_shared *shrd,
-                          struct iwl_notification_wait *wait_entry);
-
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-void iwl_reset_traffic_log(struct iwl_priv *priv);
-#endif /* CONFIG_IWLWIFI_DEBUGFS */
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-void iwl_print_rx_config_cmd(struct iwl_priv *priv,
-                            enum iwl_rxon_context_id ctxid);
-#else
-static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv,
-                                          enum iwl_rxon_context_id ctxid)
-{
-}
-#endif
 
 #define IWL_CMD(x) case x: return #x
-#define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo))))
-
-#define IWL_TRAFFIC_ENTRIES    (256)
-#define IWL_TRAFFIC_ENTRY_SIZE  (64)
 
 /*****************************************************
 * DRIVER STATUS FUNCTIONS
@@ -612,46 +452,4 @@ static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv,
 #define STATUS_CHANNEL_SWITCH_PENDING 19
 #define STATUS_SCAN_COMPLETE   20
 
-static inline int iwl_is_ready(struct iwl_shared *shrd)
-{
-       /* The adapter is 'ready' if READY and GEO_CONFIGURED bits are
-        * set but EXIT_PENDING is not */
-       return test_bit(STATUS_READY, &shrd->status) &&
-              test_bit(STATUS_GEO_CONFIGURED, &shrd->status) &&
-              !test_bit(STATUS_EXIT_PENDING, &shrd->status);
-}
-
-static inline int iwl_is_alive(struct iwl_shared *shrd)
-{
-       return test_bit(STATUS_ALIVE, &shrd->status);
-}
-
-static inline int iwl_is_init(struct iwl_shared *shrd)
-{
-       return test_bit(STATUS_INIT, &shrd->status);
-}
-
-static inline int iwl_is_rfkill_hw(struct iwl_shared *shrd)
-{
-       return test_bit(STATUS_RF_KILL_HW, &shrd->status);
-}
-
-static inline int iwl_is_rfkill(struct iwl_shared *shrd)
-{
-       return iwl_is_rfkill_hw(shrd);
-}
-
-static inline int iwl_is_ctkill(struct iwl_shared *shrd)
-{
-       return test_bit(STATUS_CT_KILL, &shrd->status);
-}
-
-static inline int iwl_is_ready_rf(struct iwl_shared *shrd)
-{
-       if (iwl_is_rfkill(shrd))
-               return 0;
-
-       return iwl_is_ready(shrd);
-}
-
 #endif /* #__iwl_shared_h__ */
index df7ab332c833a38e41e5dc213d8a1221792b3cd2..b06c6763cb7aac9023181eb77ab77a237aadafeb 100644 (file)
@@ -70,7 +70,6 @@
 #include <net/mac80211.h>
 #include <net/netlink.h>
 
-#include "iwl-wifi.h"
 #include "iwl-dev.h"
 #include "iwl-core.h"
 #include "iwl-debug.h"
 #include "iwl-agn.h"
 #include "iwl-testmode.h"
 #include "iwl-trans.h"
-#include "iwl-bus.h"
 #include "iwl-fh.h"
+#include "iwl-prph.h"
+
+
+/* Periphery registers absolute lower bound. This is used in order to
+ * differentiate registery access through HBUS_TARG_PRPH_* and
+ * HBUS_TARG_MEM_* accesses.
+ */
+#define IWL_TM_ABS_PRPH_START (0xA00000)
 
 /* The TLVs used in the gnl message policy between the kernel module and
  * user space application. iwl_testmode_gnl_msg_policy is to be carried
@@ -110,22 +116,24 @@ struct nla_policy iwl_testmode_gnl_msg_policy[IWL_TM_ATTR_MAX] = {
 
        [IWL_TM_ATTR_UCODE_OWNER] = { .type = NLA_U8, },
 
-       [IWL_TM_ATTR_SRAM_ADDR] = { .type = NLA_U32, },
-       [IWL_TM_ATTR_SRAM_SIZE] = { .type = NLA_U32, },
-       [IWL_TM_ATTR_SRAM_DUMP] = { .type = NLA_UNSPEC, },
+       [IWL_TM_ATTR_MEM_ADDR] = { .type = NLA_U32, },
+       [IWL_TM_ATTR_BUFFER_SIZE] = { .type = NLA_U32, },
+       [IWL_TM_ATTR_BUFFER_DUMP] = { .type = NLA_UNSPEC, },
 
        [IWL_TM_ATTR_FW_VERSION] = { .type = NLA_U32, },
        [IWL_TM_ATTR_DEVICE_ID] = { .type = NLA_U32, },
        [IWL_TM_ATTR_FW_TYPE] = { .type = NLA_U32, },
        [IWL_TM_ATTR_FW_INST_SIZE] = { .type = NLA_U32, },
        [IWL_TM_ATTR_FW_DATA_SIZE] = { .type = NLA_U32, },
+
+       [IWL_TM_ATTR_ENABLE_NOTIFICATION] = {.type = NLA_FLAG, },
 };
 
 /*
  * See the struct iwl_rx_packet in iwl-commands.h for the format of the
  * received events from the device
  */
-static inline int get_event_length(struct iwl_rx_mem_buffer *rxb)
+static inline int get_event_length(struct iwl_rx_cmd_buffer *rxb)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        if (pkt)
@@ -156,7 +164,7 @@ static inline int get_event_length(struct iwl_rx_mem_buffer *rxb)
  */
 
 static void iwl_testmode_ucode_rx_pkt(struct iwl_priv *priv,
-                               struct iwl_rx_mem_buffer *rxb)
+                                     struct iwl_rx_cmd_buffer *rxb)
 {
        struct ieee80211_hw *hw = priv->hw;
        struct sk_buff *skb;
@@ -172,35 +180,36 @@ static void iwl_testmode_ucode_rx_pkt(struct iwl_priv *priv,
        skb = cfg80211_testmode_alloc_event_skb(hw->wiphy, 20 + length,
                                                                GFP_ATOMIC);
        if (skb == NULL) {
-               IWL_DEBUG_INFO(priv,
+               IWL_ERR(priv,
                         "Run out of memory for messages to user space ?\n");
                return;
        }
        NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND, IWL_TM_CMD_DEV2APP_UCODE_RX_PKT);
-       NLA_PUT(skb, IWL_TM_ATTR_UCODE_RX_PKT, length, data);
+       /* the length doesn't include len_n_flags field, so add it manually */
+       NLA_PUT(skb, IWL_TM_ATTR_UCODE_RX_PKT, length + sizeof(__le32), data);
        cfg80211_testmode_event(skb, GFP_ATOMIC);
        return;
 
 nla_put_failure:
        kfree_skb(skb);
-       IWL_DEBUG_INFO(priv, "Ouch, overran buffer, check allocation!\n");
+       IWL_ERR(priv, "Ouch, overran buffer, check allocation!\n");
 }
 
 void iwl_testmode_init(struct iwl_priv *priv)
 {
-       priv->pre_rx_handler = iwl_testmode_ucode_rx_pkt;
+       priv->pre_rx_handler = NULL;
        priv->testmode_trace.trace_enabled = false;
-       priv->testmode_sram.sram_readed = false;
+       priv->testmode_mem.read_in_progress = false;
 }
 
-static void iwl_sram_cleanup(struct iwl_priv *priv)
+static void iwl_mem_cleanup(struct iwl_priv *priv)
 {
-       if (priv->testmode_sram.sram_readed) {
-               kfree(priv->testmode_sram.buff_addr);
-               priv->testmode_sram.buff_addr = NULL;
-               priv->testmode_sram.buff_size = 0;
-               priv->testmode_sram.num_chunks = 0;
-               priv->testmode_sram.sram_readed = false;
+       if (priv->testmode_mem.read_in_progress) {
+               kfree(priv->testmode_mem.buff_addr);
+               priv->testmode_mem.buff_addr = NULL;
+               priv->testmode_mem.buff_size = 0;
+               priv->testmode_mem.num_chunks = 0;
+               priv->testmode_mem.read_in_progress = false;
        }
 }
 
@@ -226,9 +235,10 @@ static void iwl_trace_cleanup(struct iwl_priv *priv)
 void iwl_testmode_cleanup(struct iwl_priv *priv)
 {
        iwl_trace_cleanup(priv);
-       iwl_sram_cleanup(priv);
+       iwl_mem_cleanup(priv);
 }
 
+
 /*
  * This function handles the user application commands to the ucode.
  *
@@ -237,35 +247,80 @@ void iwl_testmode_cleanup(struct iwl_priv *priv)
  * host command to the ucode.
  *
  * If any mandatory field is missing, -ENOMSG is replied to the user space
- * application; otherwise, the actual execution result of the host command to
- * ucode is replied.
+ * application; otherwise, waits for the host command to be sent and checks
+ * the return code. In case or error, it is returned, otherwise a reply is
+ * allocated and the reply RX packet
+ * is returned.
  *
  * @hw: ieee80211_hw object that represents the device
  * @tb: gnl message fields from the user space
  */
 static int iwl_testmode_ucode(struct ieee80211_hw *hw, struct nlattr **tb)
 {
-       struct iwl_priv *priv = hw->priv;
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
        struct iwl_host_cmd cmd;
+       struct iwl_rx_packet *pkt;
+       struct sk_buff *skb;
+       void *reply_buf;
+       u32 reply_len;
+       int ret;
+       bool cmd_want_skb;
 
        memset(&cmd, 0, sizeof(struct iwl_host_cmd));
 
        if (!tb[IWL_TM_ATTR_UCODE_CMD_ID] ||
            !tb[IWL_TM_ATTR_UCODE_CMD_DATA]) {
-               IWL_DEBUG_INFO(priv,
-                       "Error finding ucode command mandatory fields\n");
+               IWL_ERR(priv, "Missing ucode command mandatory fields\n");
                return -ENOMSG;
        }
 
-       cmd.flags = CMD_ON_DEMAND;
+       cmd.flags = CMD_ON_DEMAND | CMD_SYNC;
+       cmd_want_skb = nla_get_flag(tb[IWL_TM_ATTR_UCODE_CMD_SKB]);
+       if (cmd_want_skb)
+               cmd.flags |= CMD_WANT_SKB;
+
        cmd.id = nla_get_u8(tb[IWL_TM_ATTR_UCODE_CMD_ID]);
        cmd.data[0] = nla_data(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);
        cmd.len[0] = nla_len(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);
        cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
-       IWL_INFO(priv, "testmode ucode command ID 0x%x, flags 0x%x,"
+       IWL_DEBUG_INFO(priv, "testmode ucode command ID 0x%x, flags 0x%x,"
                                " len %d\n", cmd.id, cmd.flags, cmd.len[0]);
-       /* ok, let's submit the command to ucode */
-       return iwl_trans_send_cmd(trans(priv), &cmd);
+
+       ret = iwl_dvm_send_cmd(priv, &cmd);
+       if (ret) {
+               IWL_ERR(priv, "Failed to send hcmd\n");
+               return ret;
+       }
+       if (!cmd_want_skb)
+               return ret;
+
+       /* Handling return of SKB to the user */
+       pkt = cmd.resp_pkt;
+       if (!pkt) {
+               IWL_ERR(priv, "HCMD received a null response packet\n");
+               return ret;
+       }
+
+       reply_len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+       skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, reply_len + 20);
+       reply_buf = kmalloc(reply_len, GFP_KERNEL);
+       if (!skb || !reply_buf) {
+               kfree_skb(skb);
+               kfree(reply_buf);
+               return -ENOMEM;
+       }
+
+       /* The reply is in a page, that we cannot send to user space. */
+       memcpy(reply_buf, &(pkt->hdr), reply_len);
+       iwl_free_resp(&cmd);
+
+       NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND, IWL_TM_CMD_DEV2APP_UCODE_RX_PKT);
+       NLA_PUT(skb, IWL_TM_ATTR_UCODE_RX_PKT, reply_len, reply_buf);
+       return cfg80211_testmode_reply(skb);
+
+nla_put_failure:
+       IWL_DEBUG_INFO(priv, "Failed creating NL attributes\n");
+       return -ENOMSG;
 }
 
 
@@ -288,14 +343,14 @@ static int iwl_testmode_ucode(struct ieee80211_hw *hw, struct nlattr **tb)
  */
 static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb)
 {
-       struct iwl_priv *priv = hw->priv;
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
        u32 ofs, val32, cmd;
        u8 val8;
        struct sk_buff *skb;
        int status = 0;
 
        if (!tb[IWL_TM_ATTR_REG_OFFSET]) {
-               IWL_DEBUG_INFO(priv, "Error finding register offset\n");
+               IWL_ERR(priv, "Missing register offset\n");
                return -ENOMSG;
        }
        ofs = nla_get_u32(tb[IWL_TM_ATTR_REG_OFFSET]);
@@ -309,7 +364,7 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb)
                cmd == IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32 ||
                cmd == IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8) &&
                (ofs >= FH_MEM_UPPER_BOUND)) {
-               IWL_DEBUG_INFO(priv, "offset out of segment (0x0 - 0x%x)\n",
+               IWL_ERR(priv, "offset out of segment (0x0 - 0x%x)\n",
                        FH_MEM_UPPER_BOUND);
                return -EINVAL;
        }
@@ -321,19 +376,17 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb)
 
                skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);
                if (!skb) {
-                       IWL_DEBUG_INFO(priv, "Error allocating memory\n");
+                       IWL_ERR(priv, "Memory allocation fail\n");
                        return -ENOMEM;
                }
                NLA_PUT_U32(skb, IWL_TM_ATTR_REG_VALUE32, val32);
                status = cfg80211_testmode_reply(skb);
                if (status < 0)
-                       IWL_DEBUG_INFO(priv,
-                                      "Error sending msg : %d\n", status);
+                       IWL_ERR(priv, "Error sending msg : %d\n", status);
                break;
        case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32:
                if (!tb[IWL_TM_ATTR_REG_VALUE32]) {
-                       IWL_DEBUG_INFO(priv,
-                                      "Error finding value to write\n");
+                       IWL_ERR(priv, "Missing value to write\n");
                        return -ENOMSG;
                } else {
                        val32 = nla_get_u32(tb[IWL_TM_ATTR_REG_VALUE32]);
@@ -343,7 +396,7 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb)
                break;
        case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8:
                if (!tb[IWL_TM_ATTR_REG_VALUE8]) {
-                       IWL_DEBUG_INFO(priv, "Error finding value to write\n");
+                       IWL_ERR(priv, "Missing value to write\n");
                        return -ENOMSG;
                } else {
                        val8 = nla_get_u8(tb[IWL_TM_ATTR_REG_VALUE8]);
@@ -351,34 +404,8 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb)
                        iwl_write8(trans(priv), ofs, val8);
                }
                break;
-       case IWL_TM_CMD_APP2DEV_INDIRECT_REG_READ32:
-               val32 = iwl_read_prph(trans(priv), ofs);
-               IWL_INFO(priv, "32bit value to read 0x%x\n", val32);
-
-               skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);
-               if (!skb) {
-                       IWL_DEBUG_INFO(priv, "Error allocating memory\n");
-                       return -ENOMEM;
-               }
-               NLA_PUT_U32(skb, IWL_TM_ATTR_REG_VALUE32, val32);
-               status = cfg80211_testmode_reply(skb);
-               if (status < 0)
-                       IWL_DEBUG_INFO(priv,
-                                       "Error sending msg : %d\n", status);
-               break;
-       case IWL_TM_CMD_APP2DEV_INDIRECT_REG_WRITE32:
-               if (!tb[IWL_TM_ATTR_REG_VALUE32]) {
-                       IWL_DEBUG_INFO(priv,
-                                       "Error finding value to write\n");
-                       return -ENOMSG;
-               } else {
-                       val32 = nla_get_u32(tb[IWL_TM_ATTR_REG_VALUE32]);
-                       IWL_INFO(priv, "32bit value to write 0x%x\n", val32);
-                       iwl_write_prph(trans(priv), ofs, val32);
-               }
-               break;
        default:
-               IWL_DEBUG_INFO(priv, "Unknown testmode register command ID\n");
+               IWL_ERR(priv, "Unknown testmode register command ID\n");
                return -ENOSYS;
        }
 
@@ -395,24 +422,23 @@ static int iwl_testmode_cfg_init_calib(struct iwl_priv *priv)
        struct iwl_notification_wait calib_wait;
        int ret;
 
-       iwl_init_notification_wait(priv->shrd, &calib_wait,
-                                     CALIBRATION_COMPLETE_NOTIFICATION,
-                                     NULL, NULL);
-       ret = iwl_init_alive_start(trans(priv));
+       iwl_init_notification_wait(&priv->notif_wait, &calib_wait,
+                                  CALIBRATION_COMPLETE_NOTIFICATION,
+                                  NULL, NULL);
+       ret = iwl_init_alive_start(priv);
        if (ret) {
-               IWL_DEBUG_INFO(priv,
-                       "Error configuring init calibration: %d\n", ret);
+               IWL_ERR(priv, "Fail init calibration: %d\n", ret);
                goto cfg_init_calib_error;
        }
 
-       ret = iwl_wait_notification(priv->shrd, &calib_wait, 2 * HZ);
+       ret = iwl_wait_notification(&priv->notif_wait, &calib_wait, 2 * HZ);
        if (ret)
-               IWL_DEBUG_INFO(priv, "Error detecting"
+               IWL_ERR(priv, "Error detecting"
                        " CALIBRATION_COMPLETE_NOTIFICATION: %d\n", ret);
        return ret;
 
 cfg_init_calib_error:
-       iwl_remove_notification(priv->shrd, &calib_wait);
+       iwl_remove_notification(&priv->notif_wait, &calib_wait);
        return ret;
 }
 
@@ -434,7 +460,7 @@ cfg_init_calib_error:
  */
 static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
 {
-       struct iwl_priv *priv = hw->priv;
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
        struct iwl_trans *trans = trans(priv);
        struct sk_buff *skb;
        unsigned char *rsp_data_ptr = NULL;
@@ -448,8 +474,7 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
                skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
                                                        rsp_data_len + 20);
                if (!skb) {
-                       IWL_DEBUG_INFO(priv,
-                                      "Error allocating memory\n");
+                       IWL_ERR(priv, "Memory allocation fail\n");
                        return -ENOMEM;
                }
                NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND,
@@ -458,15 +483,13 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
                        rsp_data_len, rsp_data_ptr);
                status = cfg80211_testmode_reply(skb);
                if (status < 0)
-                       IWL_DEBUG_INFO(priv, "Error sending msg : %d\n",
-                                      status);
+                       IWL_ERR(priv, "Error sending msg : %d\n", status);
                break;
 
        case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW:
-               status = iwl_load_ucode_wait_alive(trans, IWL_UCODE_INIT);
+               status = iwl_load_ucode_wait_alive(priv, IWL_UCODE_INIT);
                if (status)
-                       IWL_DEBUG_INFO(priv,
-                               "Error loading init ucode: %d\n", status);
+                       IWL_ERR(priv, "Error loading init ucode: %d\n", status);
                break;
 
        case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB:
@@ -475,30 +498,30 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
                break;
 
        case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW:
-               status = iwl_load_ucode_wait_alive(trans, IWL_UCODE_REGULAR);
+               status = iwl_load_ucode_wait_alive(priv, IWL_UCODE_REGULAR);
                if (status) {
-                       IWL_DEBUG_INFO(priv,
+                       IWL_ERR(priv,
                                "Error loading runtime ucode: %d\n", status);
                        break;
                }
                status = iwl_alive_start(priv);
                if (status)
-                       IWL_DEBUG_INFO(priv,
+                       IWL_ERR(priv,
                                "Error starting the device: %d\n", status);
                break;
 
        case IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW:
                iwl_scan_cancel_timeout(priv, 200);
                iwl_trans_stop_device(trans);
-               status = iwl_load_ucode_wait_alive(trans, IWL_UCODE_WOWLAN);
+               status = iwl_load_ucode_wait_alive(priv, IWL_UCODE_WOWLAN);
                if (status) {
-                       IWL_DEBUG_INFO(priv,
+                       IWL_ERR(priv,
                                "Error loading WOWLAN ucode: %d\n", status);
                        break;
                }
                status = iwl_alive_start(priv);
                if (status)
-                       IWL_DEBUG_INFO(priv,
+                       IWL_ERR(priv,
                                "Error starting the device: %d\n", status);
                break;
 
@@ -507,8 +530,7 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
                        skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
                                cfg(priv)->base_params->eeprom_size + 20);
                        if (!skb) {
-                               IWL_DEBUG_INFO(priv,
-                                      "Error allocating memory\n");
+                               IWL_ERR(priv, "Memory allocation fail\n");
                                return -ENOMEM;
                        }
                        NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND,
@@ -518,35 +540,34 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
                                priv->shrd->eeprom);
                        status = cfg80211_testmode_reply(skb);
                        if (status < 0)
-                               IWL_DEBUG_INFO(priv,
-                                              "Error sending msg : %d\n",
-                                              status);
+                               IWL_ERR(priv, "Error sending msg : %d\n",
+                                       status);
                } else
                        return -EFAULT;
                break;
 
        case IWL_TM_CMD_APP2DEV_FIXRATE_REQ:
                if (!tb[IWL_TM_ATTR_FIXRATE]) {
-                       IWL_DEBUG_INFO(priv,
-                                      "Error finding fixrate setting\n");
+                       IWL_ERR(priv, "Missing fixrate setting\n");
                        return -ENOMSG;
                }
                priv->tm_fixed_rate = nla_get_u32(tb[IWL_TM_ATTR_FIXRATE]);
                break;
 
        case IWL_TM_CMD_APP2DEV_GET_FW_VERSION:
-               IWL_INFO(priv, "uCode version raw: 0x%x\n", priv->ucode_ver);
+               IWL_INFO(priv, "uCode version raw: 0x%x\n",
+                        priv->fw->ucode_ver);
 
                skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);
                if (!skb) {
-                       IWL_DEBUG_INFO(priv, "Error allocating memory\n");
+                       IWL_ERR(priv, "Memory allocation fail\n");
                        return -ENOMEM;
                }
-               NLA_PUT_U32(skb, IWL_TM_ATTR_FW_VERSION, priv->ucode_ver);
+               NLA_PUT_U32(skb, IWL_TM_ATTR_FW_VERSION,
+                           priv->fw->ucode_ver);
                status = cfg80211_testmode_reply(skb);
                if (status < 0)
-                       IWL_DEBUG_INFO(priv,
-                                       "Error sending msg : %d\n", status);
+                       IWL_ERR(priv, "Error sending msg : %d\n", status);
                break;
 
        case IWL_TM_CMD_APP2DEV_GET_DEVICE_ID:
@@ -555,40 +576,39 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
 
                skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);
                if (!skb) {
-                       IWL_DEBUG_INFO(priv, "Error allocating memory\n");
+                       IWL_ERR(priv, "Memory allocation fail\n");
                        return -ENOMEM;
                }
                NLA_PUT_U32(skb, IWL_TM_ATTR_DEVICE_ID, devid);
                status = cfg80211_testmode_reply(skb);
                if (status < 0)
-                       IWL_DEBUG_INFO(priv,
-                                       "Error sending msg : %d\n", status);
+                       IWL_ERR(priv, "Error sending msg : %d\n", status);
                break;
 
        case IWL_TM_CMD_APP2DEV_GET_FW_INFO:
                skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20 + 8);
                if (!skb) {
-                       IWL_DEBUG_INFO(priv, "Error allocating memory\n");
+                       IWL_ERR(priv, "Memory allocation fail\n");
                        return -ENOMEM;
                }
                switch (priv->shrd->ucode_type) {
                case IWL_UCODE_REGULAR:
-                       inst_size = trans(priv)->ucode_rt.code.len;
-                       data_size = trans(priv)->ucode_rt.data.len;
+                       inst_size = priv->fw->ucode_rt.code.len;
+                       data_size = priv->fw->ucode_rt.data.len;
                        break;
                case IWL_UCODE_INIT:
-                       inst_size = trans(priv)->ucode_init.code.len;
-                       data_size = trans(priv)->ucode_init.data.len;
+                       inst_size = priv->fw->ucode_init.code.len;
+                       data_size = priv->fw->ucode_init.data.len;
                        break;
                case IWL_UCODE_WOWLAN:
-                       inst_size = trans(priv)->ucode_wowlan.code.len;
-                       data_size = trans(priv)->ucode_wowlan.data.len;
+                       inst_size = priv->fw->ucode_wowlan.code.len;
+                       data_size = priv->fw->ucode_wowlan.data.len;
                        break;
                case IWL_UCODE_NONE:
-                       IWL_DEBUG_INFO(priv, "The uCode has not been loaded\n");
+                       IWL_ERR(priv, "No uCode has not been loaded\n");
                        break;
                default:
-                       IWL_DEBUG_INFO(priv, "Unsupported uCode type\n");
+                       IWL_ERR(priv, "Unsupported uCode type\n");
                        break;
                }
                NLA_PUT_U32(skb, IWL_TM_ATTR_FW_TYPE, priv->shrd->ucode_type);
@@ -596,12 +616,11 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
                NLA_PUT_U32(skb, IWL_TM_ATTR_FW_DATA_SIZE, data_size);
                status = cfg80211_testmode_reply(skb);
                if (status < 0)
-                       IWL_DEBUG_INFO(priv,
-                                       "Error sending msg : %d\n", status);
+                       IWL_ERR(priv, "Error sending msg : %d\n", status);
                break;
 
        default:
-               IWL_DEBUG_INFO(priv, "Unknown testmode driver command ID\n");
+               IWL_ERR(priv, "Unknown testmode driver command ID\n");
                return -ENOSYS;
        }
        return status;
@@ -626,7 +645,7 @@ nla_put_failure:
  */
 static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb)
 {
-       struct iwl_priv *priv = hw->priv;
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
        struct sk_buff *skb;
        int status = 0;
        struct device *dev = trans(priv)->dev;
@@ -664,8 +683,7 @@ static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb)
                skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
                        sizeof(priv->testmode_trace.dma_addr) + 20);
                if (!skb) {
-                       IWL_DEBUG_INFO(priv,
-                               "Error allocating memory\n");
+                       IWL_ERR(priv, "Memory allocation fail\n");
                        iwl_trace_cleanup(priv);
                        return -ENOMEM;
                }
@@ -674,9 +692,7 @@ static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb)
                        (u64 *)&priv->testmode_trace.dma_addr);
                status = cfg80211_testmode_reply(skb);
                if (status < 0) {
-                       IWL_DEBUG_INFO(priv,
-                                      "Error sending msg : %d\n",
-                                      status);
+                       IWL_ERR(priv, "Error sending msg : %d\n", status);
                }
                priv->testmode_trace.num_chunks =
                        DIV_ROUND_UP(priv->testmode_trace.buff_size,
@@ -687,7 +703,7 @@ static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb)
                iwl_trace_cleanup(priv);
                break;
        default:
-               IWL_DEBUG_INFO(priv, "Unknown testmode mem command ID\n");
+               IWL_ERR(priv, "Unknown testmode mem command ID\n");
                return -ENOSYS;
        }
        return status;
@@ -700,11 +716,11 @@ nla_put_failure:
        return -EMSGSIZE;
 }
 
-static int iwl_testmode_trace_dump(struct ieee80211_hw *hw, struct nlattr **tb,
+static int iwl_testmode_trace_dump(struct ieee80211_hw *hw,
                                   struct sk_buff *skb,
                                   struct netlink_callback *cb)
 {
-       struct iwl_priv *priv = hw->priv;
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
        int idx, length;
 
        if (priv->testmode_trace.trace_enabled &&
@@ -748,21 +764,102 @@ static int iwl_testmode_trace_dump(struct ieee80211_hw *hw, struct nlattr **tb,
  */
 static int iwl_testmode_ownership(struct ieee80211_hw *hw, struct nlattr **tb)
 {
-       struct iwl_priv *priv = hw->priv;
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
        u8 owner;
 
        if (!tb[IWL_TM_ATTR_UCODE_OWNER]) {
-               IWL_DEBUG_INFO(priv, "Error finding ucode owner\n");
+               IWL_ERR(priv, "Missing ucode owner\n");
                return -ENOMSG;
        }
 
        owner = nla_get_u8(tb[IWL_TM_ATTR_UCODE_OWNER]);
-       if ((owner == IWL_OWNERSHIP_DRIVER) || (owner == IWL_OWNERSHIP_TM))
-               priv->shrd->ucode_owner = owner;
-       else {
-               IWL_DEBUG_INFO(priv, "Invalid owner\n");
+       if (owner == IWL_OWNERSHIP_DRIVER) {
+               priv->ucode_owner = owner;
+               priv->pre_rx_handler = NULL;
+       } else if (owner == IWL_OWNERSHIP_TM) {
+               priv->pre_rx_handler = iwl_testmode_ucode_rx_pkt;
+               priv->ucode_owner = owner;
+       } else {
+               IWL_ERR(priv, "Invalid owner\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int iwl_testmode_indirect_read(struct iwl_priv *priv, u32 addr, u32 size)
+{
+       struct iwl_trans *trans = trans(priv);
+       unsigned long flags;
+       int i;
+
+       if (size & 0x3)
                return -EINVAL;
+       priv->testmode_mem.buff_size = size;
+       priv->testmode_mem.buff_addr =
+               kmalloc(priv->testmode_mem.buff_size, GFP_KERNEL);
+       if (priv->testmode_mem.buff_addr == NULL)
+               return -ENOMEM;
+
+       /* Hard-coded periphery absolute address */
+       if (IWL_TM_ABS_PRPH_START <= addr &&
+               addr < IWL_TM_ABS_PRPH_START + PRPH_END) {
+                       spin_lock_irqsave(&trans->reg_lock, flags);
+                       iwl_grab_nic_access(trans);
+                       iwl_write32(trans, HBUS_TARG_PRPH_RADDR,
+                               addr | (3 << 24));
+                       for (i = 0; i < size; i += 4)
+                               *(u32 *)(priv->testmode_mem.buff_addr + i) =
+                                       iwl_read32(trans, HBUS_TARG_PRPH_RDAT);
+                       iwl_release_nic_access(trans);
+                       spin_unlock_irqrestore(&trans->reg_lock, flags);
+       } else { /* target memory (SRAM) */
+               _iwl_read_targ_mem_words(trans, addr,
+                       priv->testmode_mem.buff_addr,
+                       priv->testmode_mem.buff_size / 4);
        }
+
+       priv->testmode_mem.num_chunks =
+               DIV_ROUND_UP(priv->testmode_mem.buff_size, DUMP_CHUNK_SIZE);
+       priv->testmode_mem.read_in_progress = true;
+       return 0;
+
+}
+
+static int iwl_testmode_indirect_write(struct iwl_priv *priv, u32 addr,
+       u32 size, unsigned char *buf)
+{
+       struct iwl_trans *trans = trans(priv);
+       u32 val, i;
+       unsigned long flags;
+
+       if (IWL_TM_ABS_PRPH_START <= addr &&
+               addr < IWL_TM_ABS_PRPH_START + PRPH_END) {
+                       /* Periphery writes can be 1-3 bytes long, or DWORDs */
+                       if (size < 4) {
+                               memcpy(&val, buf, size);
+                               spin_lock_irqsave(&trans->reg_lock, flags);
+                               iwl_grab_nic_access(trans);
+                               iwl_write32(trans, HBUS_TARG_PRPH_WADDR,
+                                           (addr & 0x0000FFFF) |
+                                           ((size - 1) << 24));
+                               iwl_write32(trans, HBUS_TARG_PRPH_WDAT, val);
+                               iwl_release_nic_access(trans);
+                               /* needed after consecutive writes w/o read */
+                               mmiowb();
+                               spin_unlock_irqrestore(&trans->reg_lock, flags);
+                       } else {
+                               if (size % 4)
+                                       return -EINVAL;
+                               for (i = 0; i < size; i += 4)
+                                       iwl_write_prph(trans, addr+i,
+                                               *(u32 *)(buf+i));
+                       }
+       } else if (iwlagn_hw_valid_rtc_data_addr(addr) ||
+               (IWLAGN_RTC_INST_LOWER_BOUND <= addr &&
+               addr < IWLAGN_RTC_INST_UPPER_BOUND)) {
+                       _iwl_write_targ_mem_words(trans, addr, buf, size/4);
+       } else
+               return -EINVAL;
        return 0;
 }
 
@@ -782,82 +879,60 @@ static int iwl_testmode_ownership(struct ieee80211_hw *hw, struct nlattr **tb)
  * @hw: ieee80211_hw object that represents the device
  * @tb: gnl message fields from the user space
  */
-static int iwl_testmode_sram(struct ieee80211_hw *hw, struct nlattr **tb)
+static int iwl_testmode_indirect_mem(struct ieee80211_hw *hw,
+       struct nlattr **tb)
 {
-       struct iwl_priv *priv = hw->priv;
-       u32 ofs, size, maxsize;
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+       u32 addr, size, cmd;
+       unsigned char *buf;
 
-       if (priv->testmode_sram.sram_readed)
+       /* Both read and write should be blocked, for atomicity */
+       if (priv->testmode_mem.read_in_progress)
                return -EBUSY;
 
-       if (!tb[IWL_TM_ATTR_SRAM_ADDR]) {
-               IWL_DEBUG_INFO(priv, "Error finding SRAM offset address\n");
+       cmd = nla_get_u32(tb[IWL_TM_ATTR_COMMAND]);
+       if (!tb[IWL_TM_ATTR_MEM_ADDR]) {
+               IWL_ERR(priv, "Error finding memory offset address\n");
                return -ENOMSG;
        }
-       ofs = nla_get_u32(tb[IWL_TM_ATTR_SRAM_ADDR]);
-       if (!tb[IWL_TM_ATTR_SRAM_SIZE]) {
-               IWL_DEBUG_INFO(priv, "Error finding size for SRAM reading\n");
+       addr = nla_get_u32(tb[IWL_TM_ATTR_MEM_ADDR]);
+       if (!tb[IWL_TM_ATTR_BUFFER_SIZE]) {
+               IWL_ERR(priv, "Error finding size for memory reading\n");
                return -ENOMSG;
        }
-       size = nla_get_u32(tb[IWL_TM_ATTR_SRAM_SIZE]);
-       switch (priv->shrd->ucode_type) {
-       case IWL_UCODE_REGULAR:
-               maxsize = trans(priv)->ucode_rt.data.len;
-               break;
-       case IWL_UCODE_INIT:
-               maxsize = trans(priv)->ucode_init.data.len;
-               break;
-       case IWL_UCODE_WOWLAN:
-               maxsize = trans(priv)->ucode_wowlan.data.len;
-               break;
-       case IWL_UCODE_NONE:
-               IWL_ERR(priv, "Error, uCode does not been loaded\n");
-               return -ENOSYS;
-       default:
-               IWL_ERR(priv, "Error, unsupported uCode type\n");
-               return -ENOSYS;
-       }
-       if ((ofs + size) > (maxsize + SRAM_DATA_SEG_OFFSET)) {
-               IWL_ERR(priv, "Invalid offset/size: out of range\n");
-               return -EINVAL;
-       }
-       priv->testmode_sram.buff_size = (size / 4) * 4;
-       priv->testmode_sram.buff_addr =
-               kmalloc(priv->testmode_sram.buff_size, GFP_KERNEL);
-       if (priv->testmode_sram.buff_addr == NULL) {
-               IWL_ERR(priv, "Error allocating memory\n");
-               return -ENOMEM;
+       size = nla_get_u32(tb[IWL_TM_ATTR_BUFFER_SIZE]);
+
+       if (cmd == IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ)
+               return iwl_testmode_indirect_read(priv, addr,  size);
+       else {
+               if (!tb[IWL_TM_ATTR_BUFFER_DUMP])
+                       return -EINVAL;
+               buf = (unsigned char *) nla_data(tb[IWL_TM_ATTR_BUFFER_DUMP]);
+               return iwl_testmode_indirect_write(priv, addr, size, buf);
        }
-       _iwl_read_targ_mem_words(trans(priv), ofs,
-                                       priv->testmode_sram.buff_addr,
-                                       priv->testmode_sram.buff_size / 4);
-       priv->testmode_sram.num_chunks =
-               DIV_ROUND_UP(priv->testmode_sram.buff_size, DUMP_CHUNK_SIZE);
-       priv->testmode_sram.sram_readed = true;
-       return 0;
 }
 
-static int iwl_testmode_sram_dump(struct ieee80211_hw *hw, struct nlattr **tb,
-                                  struct sk_buff *skb,
-                                  struct netlink_callback *cb)
+static int iwl_testmode_buffer_dump(struct ieee80211_hw *hw,
+                                   struct sk_buff *skb,
+                                   struct netlink_callback *cb)
 {
-       struct iwl_priv *priv = hw->priv;
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
        int idx, length;
 
-       if (priv->testmode_sram.sram_readed) {
+       if (priv->testmode_mem.read_in_progress) {
                idx = cb->args[4];
-               if (idx >= priv->testmode_sram.num_chunks) {
-                       iwl_sram_cleanup(priv);
+               if (idx >= priv->testmode_mem.num_chunks) {
+                       iwl_mem_cleanup(priv);
                        return -ENOENT;
                }
                length = DUMP_CHUNK_SIZE;
-               if (((idx + 1) == priv->testmode_sram.num_chunks) &&
-                   (priv->testmode_sram.buff_size % DUMP_CHUNK_SIZE))
-                       length = priv->testmode_sram.buff_size %
+               if (((idx + 1) == priv->testmode_mem.num_chunks) &&
+                   (priv->testmode_mem.buff_size % DUMP_CHUNK_SIZE))
+                       length = priv->testmode_mem.buff_size %
                                DUMP_CHUNK_SIZE;
 
-               NLA_PUT(skb, IWL_TM_ATTR_SRAM_DUMP, length,
-                       priv->testmode_sram.buff_addr +
+               NLA_PUT(skb, IWL_TM_ATTR_BUFFER_DUMP, length,
+                       priv->testmode_mem.buff_addr +
                        (DUMP_CHUNK_SIZE * idx));
                idx++;
                cb->args[4] = idx;
@@ -869,6 +944,20 @@ static int iwl_testmode_sram_dump(struct ieee80211_hw *hw, struct nlattr **tb,
        return -ENOBUFS;
 }
 
+static int iwl_testmode_notifications(struct ieee80211_hw *hw,
+       struct nlattr **tb)
+{
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+       bool enable;
+
+       enable = nla_get_flag(tb[IWL_TM_ATTR_ENABLE_NOTIFICATION]);
+       if (enable)
+               priv->pre_rx_handler = iwl_testmode_ucode_rx_pkt;
+       else
+               priv->pre_rx_handler = NULL;
+       return 0;
+}
+
 
 /* The testmode gnl message handler that takes the gnl message from the
  * user space and parses it per the policy iwl_testmode_gnl_msg_policy, then
@@ -892,24 +981,23 @@ static int iwl_testmode_sram_dump(struct ieee80211_hw *hw, struct nlattr **tb,
 int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
 {
        struct nlattr *tb[IWL_TM_ATTR_MAX];
-       struct iwl_priv *priv = hw->priv;
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
        int result;
 
        result = nla_parse(tb, IWL_TM_ATTR_MAX - 1, data, len,
                        iwl_testmode_gnl_msg_policy);
        if (result != 0) {
-               IWL_DEBUG_INFO(priv,
-                              "Error parsing the gnl message : %d\n", result);
+               IWL_ERR(priv, "Error parsing the gnl message : %d\n", result);
                return result;
        }
 
        /* IWL_TM_ATTR_COMMAND is absolutely mandatory */
        if (!tb[IWL_TM_ATTR_COMMAND]) {
-               IWL_DEBUG_INFO(priv, "Error finding testmode command type\n");
+               IWL_ERR(priv, "Missing testmode command type\n");
                return -ENOMSG;
        }
        /* in case multiple accesses to the device happens */
-       mutex_lock(&priv->shrd->mutex);
+       mutex_lock(&priv->mutex);
 
        switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
        case IWL_TM_CMD_APP2DEV_UCODE:
@@ -919,8 +1007,6 @@ int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
        case IWL_TM_CMD_APP2DEV_DIRECT_REG_READ32:
        case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32:
        case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8:
-       case IWL_TM_CMD_APP2DEV_INDIRECT_REG_READ32:
-       case IWL_TM_CMD_APP2DEV_INDIRECT_REG_WRITE32:
                IWL_DEBUG_INFO(priv, "testmode cmd to register\n");
                result = iwl_testmode_reg(hw, tb);
                break;
@@ -950,18 +1036,26 @@ int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
                result = iwl_testmode_ownership(hw, tb);
                break;
 
-       case IWL_TM_CMD_APP2DEV_READ_SRAM:
-               IWL_DEBUG_INFO(priv, "testmode sram read cmd to driver\n");
-               result = iwl_testmode_sram(hw, tb);
+       case IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ:
+       case IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE:
+               IWL_DEBUG_INFO(priv, "testmode indirect memory cmd "
+                       "to driver\n");
+               result = iwl_testmode_indirect_mem(hw, tb);
+               break;
+
+       case IWL_TM_CMD_APP2DEV_NOTIFICATIONS:
+               IWL_DEBUG_INFO(priv, "testmode notifications cmd "
+                       "to driver\n");
+               result = iwl_testmode_notifications(hw, tb);
                break;
 
        default:
-               IWL_DEBUG_INFO(priv, "Unknown testmode command\n");
+               IWL_ERR(priv, "Unknown testmode command\n");
                result = -ENOSYS;
                break;
        }
 
-       mutex_unlock(&priv->shrd->mutex);
+       mutex_unlock(&priv->mutex);
        return result;
 }
 
@@ -970,7 +1064,7 @@ int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb,
                      void *data, int len)
 {
        struct nlattr *tb[IWL_TM_ATTR_MAX];
-       struct iwl_priv *priv = hw->priv;
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
        int result;
        u32 cmd;
 
@@ -981,15 +1075,14 @@ int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb,
                result = nla_parse(tb, IWL_TM_ATTR_MAX - 1, data, len,
                                iwl_testmode_gnl_msg_policy);
                if (result) {
-                       IWL_DEBUG_INFO(priv,
-                              "Error parsing the gnl message : %d\n", result);
+                       IWL_ERR(priv,
+                               "Error parsing the gnl message : %d\n", result);
                        return result;
                }
 
                /* IWL_TM_ATTR_COMMAND is absolutely mandatory */
                if (!tb[IWL_TM_ATTR_COMMAND]) {
-                       IWL_DEBUG_INFO(priv,
-                               "Error finding testmode command type\n");
+                       IWL_ERR(priv, "Missing testmode command type\n");
                        return -ENOMSG;
                }
                cmd = nla_get_u32(tb[IWL_TM_ATTR_COMMAND]);
@@ -997,21 +1090,21 @@ int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb,
        }
 
        /* in case multiple accesses to the device happens */
-       mutex_lock(&priv->shrd->mutex);
+       mutex_lock(&priv->mutex);
        switch (cmd) {
        case IWL_TM_CMD_APP2DEV_READ_TRACE:
                IWL_DEBUG_INFO(priv, "uCode trace cmd to driver\n");
-               result = iwl_testmode_trace_dump(hw, tb, skb, cb);
+               result = iwl_testmode_trace_dump(hw, skb, cb);
                break;
-       case IWL_TM_CMD_APP2DEV_DUMP_SRAM:
+       case IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_DUMP:
                IWL_DEBUG_INFO(priv, "testmode sram dump cmd to driver\n");
-               result = iwl_testmode_sram_dump(hw, tb, skb, cb);
+               result = iwl_testmode_buffer_dump(hw, skb, cb);
                break;
        default:
                result = -EINVAL;
                break;
        }
 
-       mutex_unlock(&priv->shrd->mutex);
+       mutex_unlock(&priv->mutex);
        return result;
 }
index f97d06169b4596d190e8578cc3f4497e5becde11..6ba211b09426044df2a6564ae4cb08a749aa2d06 100644 (file)
@@ -99,7 +99,7 @@
  *     to user application
  * @IWL_TM_CMD_DEV2APP_UCODE_RX_PKT:
  *     commands from kernel space to multicast the spontaneous messages
- *     to user application
+ *     to user application, or reply of host commands
  * @IWL_TM_CMD_DEV2APP_EEPROM_RSP:
  *     commands from kernel space to carry the eeprom response
  *     to user application
  *     if application has the ownership, the only host command from
  *     testmode will deliver to uCode. Default owner is driver
  *
- * @IWL_TM_CMD_APP2DEV_INDIRECT_REG_READ32:
- * @IWL_TM_CMD_APP2DEV_INDIRECT_REG_WRITE32:
- *     commands from user application to indirectly access peripheral register
- *
- * @IWL_TM_CMD_APP2DEV_READ_SRAM:
- * @IWL_TM_CMD_APP2DEV_DUMP_SRAM:
- *     commands from user application to read data in sram
- *
  * @IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW: load Wake On Wireless LAN uCode image
  * @IWL_TM_CMD_APP2DEV_GET_FW_VERSION: retrieve uCode version
  * @IWL_TM_CMD_APP2DEV_GET_DEVICE_ID: retrieve ID information in device
  * @IWL_TM_CMD_APP2DEV_GET_FW_INFO:
  *     retrieve information of existing loaded uCode image
  *
+ * @IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ:
+ * @IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_DUMP:
+ * @IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE:
+ *     Commands to read/write data from periphery or SRAM memory ranges.
+ *     Fore reading, a READ command is sent from the userspace and the data
+ *     is returned when the user calls a DUMP command.
+ *     For writing, only a WRITE command is used.
+ * @IWL_TM_CMD_APP2DEV_NOTIFICATIONS:
+ *     Command to enable/disable notifications (currently RX packets) from the
+ *     driver to userspace.
  */
 enum iwl_tm_cmd_t {
        IWL_TM_CMD_APP2DEV_UCODE                = 1,
@@ -142,15 +144,19 @@ enum iwl_tm_cmd_t {
        IWL_TM_CMD_DEV2APP_UCODE_RX_PKT         = 15,
        IWL_TM_CMD_DEV2APP_EEPROM_RSP           = 16,
        IWL_TM_CMD_APP2DEV_OWNERSHIP            = 17,
-       IWL_TM_CMD_APP2DEV_INDIRECT_REG_READ32  = 18,
-       IWL_TM_CMD_APP2DEV_INDIRECT_REG_WRITE32 = 19,
-       IWL_TM_CMD_APP2DEV_READ_SRAM            = 20,
-       IWL_TM_CMD_APP2DEV_DUMP_SRAM            = 21,
+       RESERVED_18                             = 18,
+       RESERVED_19                             = 19,
+       RESERVED_20                             = 20,
+       RESERVED_21                             = 21,
        IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW       = 22,
        IWL_TM_CMD_APP2DEV_GET_FW_VERSION       = 23,
        IWL_TM_CMD_APP2DEV_GET_DEVICE_ID        = 24,
        IWL_TM_CMD_APP2DEV_GET_FW_INFO          = 25,
-       IWL_TM_CMD_MAX                          = 26,
+       IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ = 26,
+       IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_DUMP = 27,
+       IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE = 28,
+       IWL_TM_CMD_APP2DEV_NOTIFICATIONS        = 29,
+       IWL_TM_CMD_MAX                          = 30,
 };
 
 /*
@@ -171,8 +177,6 @@ enum iwl_tm_cmd_t {
  *     When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_UCODE,
  *     The mandatory fields are :
  *     IWL_TM_ATTR_UCODE_CMD_ID for recognizable command ID;
- *     IWL_TM_ATTR_COMMAND_FLAG for the flags of the commands;
- *     The optional fields are:
  *     IWL_TM_ATTR_UCODE_CMD_DATA for the actual command payload
  *     to the ucode
  *
@@ -221,16 +225,19 @@ enum iwl_tm_cmd_t {
  *     The mandatory fields are:
  *     IWL_TM_ATTR_UCODE_OWNER for the new owner
  *
- * @IWL_TM_ATTR_SRAM_ADDR:
- * @IWL_TM_ATTR_SRAM_SIZE:
- *     When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_READ_SRAM,
+ * @IWL_TM_ATTR_MEM_ADDR:
+ * @IWL_TM_ATTR_BUFFER_SIZE:
+ *     When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ
+ *     or IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE.
  *     The mandatory fields are:
- *     IWL_TM_ATTR_SRAM_ADDR for the address in sram
- *     IWL_TM_ATTR_SRAM_SIZE for the buffer size of data reading
+ *     IWL_TM_ATTR_MEM_ADDR for the address in SRAM/periphery to read/write
+ *     IWL_TM_ATTR_BUFFER_SIZE for the buffer size of data to read/write.
  *
- * @IWL_TM_ATTR_SRAM_DUMP:
- *     When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_DUMP_SRAM,
- *     IWL_TM_ATTR_SRAM_DUMP for the data in sram
+ * @IWL_TM_ATTR_BUFFER_DUMP:
+ *     When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_DUMP,
+ *     IWL_TM_ATTR_BUFFER_DUMP is used for the data that was read.
+ *     When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE,
+ *     this attribute contains the data to write.
  *
  * @IWL_TM_ATTR_FW_VERSION:
  *     When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_GET_FW_VERSION,
@@ -249,6 +256,14 @@ enum iwl_tm_cmd_t {
  *     IWL_TM_ATTR_FW_INST_SIZE for the size of instruction section
  *     IWL_TM_ATTR_FW_DATA_SIZE for the size of data section
  *
+ * @IWL_TM_ATTR_UCODE_CMD_SKB:
+ *     When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_UCODE this flag
+ *     indicates that the user wants to receive the response of the command
+ *     in a reply SKB. If it's not present, the response is not returned.
+ * @IWL_TM_ATTR_ENABLE_NOTIFICATIONS:
+ *     When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_NOTIFICATIONS, this
+ *     flag enables (if present) or disables (if not) the forwarding
+ *     to userspace.
  */
 enum iwl_tm_attr_t {
        IWL_TM_ATTR_NOT_APPLICABLE              = 0,
@@ -266,15 +281,17 @@ enum iwl_tm_attr_t {
        IWL_TM_ATTR_TRACE_DUMP                  = 12,
        IWL_TM_ATTR_FIXRATE                     = 13,
        IWL_TM_ATTR_UCODE_OWNER                 = 14,
-       IWL_TM_ATTR_SRAM_ADDR                   = 15,
-       IWL_TM_ATTR_SRAM_SIZE                   = 16,
-       IWL_TM_ATTR_SRAM_DUMP                   = 17,
+       IWL_TM_ATTR_MEM_ADDR                    = 15,
+       IWL_TM_ATTR_BUFFER_SIZE                 = 16,
+       IWL_TM_ATTR_BUFFER_DUMP                 = 17,
        IWL_TM_ATTR_FW_VERSION                  = 18,
        IWL_TM_ATTR_DEVICE_ID                   = 19,
        IWL_TM_ATTR_FW_TYPE                     = 20,
        IWL_TM_ATTR_FW_INST_SIZE                = 21,
        IWL_TM_ATTR_FW_DATA_SIZE                = 22,
-       IWL_TM_ATTR_MAX                         = 23,
+       IWL_TM_ATTR_UCODE_CMD_SKB               = 23,
+       IWL_TM_ATTR_ENABLE_NOTIFICATION         = 24,
+       IWL_TM_ATTR_MAX                         = 25,
 };
 
 /* uCode trace buffer */
index 561865f29d56a370156c94e09b8de4908229a5b3..67965599bb30df83d5d7fd0ad7fce29f718fc685 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
 #include <linux/skbuff.h>
+#include <linux/wait.h>
 #include <linux/pci.h>
 
 #include "iwl-fh.h"
@@ -40,6 +41,7 @@
 #include "iwl-trans.h"
 #include "iwl-debug.h"
 #include "iwl-io.h"
+#include "iwl-op-mode.h"
 
 struct iwl_tx_queue;
 struct iwl_queue;
@@ -48,6 +50,12 @@ struct iwl_host_cmd;
 /*This file includes the declaration that are internal to the
  * trans_pcie layer */
 
+struct iwl_rx_mem_buffer {
+       dma_addr_t page_dma;
+       struct page *page;
+       struct list_head list;
+};
+
 /**
  * struct isr_statistics - interrupt statistics
  *
@@ -108,6 +116,26 @@ struct iwl_dma_ptr {
        size_t size;
 };
 
+/**
+ * iwl_queue_inc_wrap - increment queue index, wrap back to beginning
+ * @index -- current index
+ * @n_bd -- total number of entries in queue (must be power of 2)
+ */
+static inline int iwl_queue_inc_wrap(int index, int n_bd)
+{
+       return ++index & (n_bd - 1);
+}
+
+/**
+ * iwl_queue_dec_wrap - decrement queue index, wrap back to end
+ * @index -- current index
+ * @n_bd -- total number of entries in queue (must be power of 2)
+ */
+static inline int iwl_queue_dec_wrap(int index, int n_bd)
+{
+       return --index & (n_bd - 1);
+}
+
 /*
  * This queue number is required for proper operation
  * because the ucode will stop/start the scheduler as
@@ -168,6 +196,7 @@ struct iwl_queue {
  * @meta: array of meta data for each command/tx buffer
  * @dma_addr_cmd: physical address of cmd/tx buffer array
  * @txb: array of per-TFD driver data
+ * lock: queue lock
  * @time_stamp: time (in jiffies) of last read_ptr change
  * @need_update: indicates need to update read/write index
  * @sched_retry: indicates queue is high-throughput aggregation (HT AGG) enabled
@@ -186,6 +215,7 @@ struct iwl_tx_queue {
        struct iwl_device_cmd **cmd;
        struct iwl_cmd_meta *meta;
        struct sk_buff **skbs;
+       spinlock_t lock;
        unsigned long time_stamp;
        u8 need_update;
        u8 sched_retry;
@@ -201,6 +231,7 @@ struct iwl_tx_queue {
  * @rxq: all the RX queue data
  * @rx_replenish: work that will be called when buffers need to be allocated
  * @trans: pointer to the generic transport area
+ * @irq - the irq number for the device
  * @irq_requested: true when the irq has been requested
  * @scd_base_addr: scheduler sram base address in SRAM
  * @scd_bc_tbls: pointer to the byte count table of the scheduler
@@ -214,6 +245,10 @@ struct iwl_tx_queue {
  * queue_stop_count: tracks what SW queue is stopped
  * @pci_dev: basic pci-network driver stuff
  * @hw_base: pci hardware address support
+ * @ucode_write_complete: indicates that the ucode has been copied.
+ * @ucode_write_waitq: wait queue for uCode load
+ * @status - transport specific status flags
+ * @cmd_queue - command queue number
  */
 struct iwl_trans_pcie {
        struct iwl_rx_queue rxq;
@@ -230,6 +265,8 @@ struct iwl_trans_pcie {
        struct tasklet_struct irq_tasklet;
        struct isr_statistics isr_stats;
 
+       unsigned int irq;
+       spinlock_t irq_lock;
        u32 inta_mask;
        u32 scd_base_addr;
        struct iwl_dma_ptr scd_bc_tbls;
@@ -249,6 +286,11 @@ struct iwl_trans_pcie {
        /* PCI bus related data */
        struct pci_dev *pci_dev;
        void __iomem *hw_base;
+
+       bool ucode_write_complete;
+       wait_queue_head_t ucode_write_waitq;
+       unsigned long status;
+       u8 cmd_queue;
 };
 
 #define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \
@@ -283,7 +325,7 @@ int iwlagn_txq_attach_buf_to_tfd(struct iwl_trans *trans,
 int iwl_queue_init(struct iwl_queue *q, int count, int slots_num, u32 id);
 int iwl_trans_pcie_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd);
 void iwl_tx_cmd_complete(struct iwl_trans *trans,
-                        struct iwl_rx_mem_buffer *rxb, int handler_status);
+                        struct iwl_rx_cmd_buffer *rxb, int handler_status);
 void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_trans *trans,
                                           struct iwl_tx_queue *txq,
                                           u16 byte_cnt);
@@ -316,7 +358,8 @@ void iwl_dump_csr(struct iwl_trans *trans);
 ******************************************************/
 static inline void iwl_disable_interrupts(struct iwl_trans *trans)
 {
-       clear_bit(STATUS_INT_ENABLED, &trans->shrd->status);
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       clear_bit(STATUS_INT_ENABLED, &trans_pcie->status);
 
        /* disable interrupts from uCode/NIC to host */
        iwl_write32(trans, CSR_INT_MASK, 0x00000000);
@@ -330,14 +373,19 @@ static inline void iwl_disable_interrupts(struct iwl_trans *trans)
 
 static inline void iwl_enable_interrupts(struct iwl_trans *trans)
 {
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 
        IWL_DEBUG_ISR(trans, "Enabling interrupts\n");
-       set_bit(STATUS_INT_ENABLED, &trans->shrd->status);
+       set_bit(STATUS_INT_ENABLED, &trans_pcie->status);
        iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask);
 }
 
+static inline void iwl_enable_rfkill_int(struct iwl_trans *trans)
+{
+       IWL_DEBUG_ISR(trans, "Enabling rfkill interrupt\n");
+       iwl_write32(trans, CSR_INT_MASK, CSR_INT_BIT_RF_KILL);
+}
+
 /*
  * we have 8 bits used like this:
  *
@@ -363,7 +411,7 @@ static inline u8 iwl_get_queue_ac(struct iwl_tx_queue *txq)
 }
 
 static inline void iwl_wake_queue(struct iwl_trans *trans,
-                                 struct iwl_tx_queue *txq, const char *msg)
+                                 struct iwl_tx_queue *txq)
 {
        u8 queue = txq->swq_id;
        u8 ac = queue & 3;
@@ -373,20 +421,20 @@ static inline void iwl_wake_queue(struct iwl_trans *trans,
 
        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);
+                       iwl_op_mode_queue_not_full(trans->op_mode, ac);
+                       IWL_DEBUG_TX_QUEUES(trans, "Wake hwq %d ac %d",
+                                           hwq, ac);
                } 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);
+                       IWL_DEBUG_TX_QUEUES(trans,
+                               "Don't wake hwq %d ac %d stop count %d",
+                               hwq, ac,
+                               atomic_read(&trans_pcie->queue_stop_count[ac]));
                }
        }
 }
 
 static inline void iwl_stop_queue(struct iwl_trans *trans,
-                                 struct iwl_tx_queue *txq, const char *msg)
+                                 struct iwl_tx_queue *txq)
 {
        u8 queue = txq->swq_id;
        u8 ac = queue & 3;
@@ -396,35 +444,23 @@ static inline void iwl_stop_queue(struct iwl_trans *trans,
 
        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);
+                       iwl_op_mode_queue_full(trans->op_mode, ac);
+                       IWL_DEBUG_TX_QUEUES(trans,
+                               "Stop hwq %d ac %d stop count %d",
+                               hwq, ac,
+                               atomic_read(&trans_pcie->queue_stop_count[ac]));
                } 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);
+                       IWL_DEBUG_TX_QUEUES(trans,
+                               "Don't stop hwq %d ac %d stop count %d",
+                               hwq, ac,
+                               atomic_read(&trans_pcie->queue_stop_count[ac]));
                }
        } else {
-               IWL_DEBUG_TX_QUEUES(trans, "stop hwq %d, but it is stopped/ %s",
-                                   hwq, msg);
+               IWL_DEBUG_TX_QUEUES(trans, "stop hwq %d, but it is stopped",
+                                   hwq);
        }
 }
 
-#ifdef ieee80211_stop_queue
-#undef ieee80211_stop_queue
-#endif
-
-#define ieee80211_stop_queue DO_NOT_USE_ieee80211_stop_queue
-
-#ifdef ieee80211_wake_queue
-#undef ieee80211_wake_queue
-#endif
-
-#define ieee80211_wake_queue DO_NOT_USE_ieee80211_wake_queue
-
 static inline void iwl_txq_ctx_activate(struct iwl_trans_pcie *trans_pcie,
                                        int txq_id)
 {
index 3826852ec5f07e0f2d10712aa556bb806c6fe63a..9bc3c73af5e9a765402af64d6b3a1680773fe222 100644 (file)
 #include <linux/wait.h>
 #include <linux/gfp.h>
 
-/*TODO: Remove include to iwl-core.h*/
-#include "iwl-core.h"
+#include "iwl-prph.h"
 #include "iwl-io.h"
 #include "iwl-trans-pcie-int.h"
+#include "iwl-op-mode.h"
 
 #ifdef CONFIG_IWLWIFI_IDI
 #include "iwl-amfh.h"
@@ -140,7 +140,7 @@ void iwl_rx_queue_update_write_ptr(struct iwl_trans *trans,
        if (q->need_update == 0)
                goto exit_unlock;
 
-       if (hw_params(trans).shadow_reg_enable) {
+       if (cfg(trans)->base_params->shadow_reg_enable) {
                /* shadow register enabled */
                /* Device expects a multiple of 8 */
                q->write_actual = (q->write & ~0x7);
@@ -227,7 +227,7 @@ static void iwlagn_rx_queue_restock(struct iwl_trans *trans)
        /* If the pre-allocated buffer pool is dropping low, schedule to
         * refill it */
        if (rxq->free_count <= RX_LOW_WATERMARK)
-               queue_work(trans->shrd->workqueue, &trans_pcie->rx_replenish);
+               schedule_work(&trans_pcie->rx_replenish);
 
 
        /* If we've added more space for the firmware to place data, tell it.
@@ -331,13 +331,14 @@ static void iwlagn_rx_allocate(struct iwl_trans *trans, gfp_t priority)
 
 void iwlagn_rx_replenish(struct iwl_trans *trans)
 {
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        unsigned long flags;
 
        iwlagn_rx_allocate(trans, GFP_KERNEL);
 
-       spin_lock_irqsave(&trans->shrd->lock, flags);
+       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
        iwlagn_rx_queue_restock(trans);
-       spin_unlock_irqrestore(&trans->shrd->lock, flags);
+       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 }
 
 static void iwlagn_rx_replenish_now(struct iwl_trans *trans)
@@ -351,14 +352,115 @@ void iwl_bg_rx_replenish(struct work_struct *data)
 {
        struct iwl_trans_pcie *trans_pcie =
            container_of(data, struct iwl_trans_pcie, rx_replenish);
-       struct iwl_trans *trans = trans_pcie->trans;
 
-       if (test_bit(STATUS_EXIT_PENDING, &trans->shrd->status))
+       iwlagn_rx_replenish(trans_pcie->trans);
+}
+
+static void iwl_rx_handle_rxbuf(struct iwl_trans *trans,
+                               struct iwl_rx_mem_buffer *rxb)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
+       struct iwl_tx_queue *txq = &trans_pcie->txq[trans_pcie->cmd_queue];
+       struct iwl_device_cmd *cmd;
+       unsigned long flags;
+       int len, err;
+       u16 sequence;
+       struct iwl_rx_cmd_buffer rxcb;
+       struct iwl_rx_packet *pkt;
+       bool reclaim;
+       int index, cmd_index;
+
+       if (WARN_ON(!rxb))
                return;
 
-       mutex_lock(&trans->shrd->mutex);
-       iwlagn_rx_replenish(trans);
-       mutex_unlock(&trans->shrd->mutex);
+       dma_unmap_page(trans->dev, rxb->page_dma,
+                      PAGE_SIZE << hw_params(trans).rx_page_order,
+                      DMA_FROM_DEVICE);
+
+       rxcb._page = rxb->page;
+       pkt = rxb_addr(&rxcb);
+
+       IWL_DEBUG_RX(trans, "%s, 0x%02x\n",
+                    get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd);
+
+
+       len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+       len += sizeof(u32); /* account for status word */
+       trace_iwlwifi_dev_rx(trans->dev, pkt, len);
+
+       /* Reclaim a command buffer only if this packet is a response
+        *   to a (driver-originated) command.
+        * If the packet (e.g. Rx frame) originated from uCode,
+        *   there is no command buffer to reclaim.
+        * Ucode should set SEQ_RX_FRAME bit if ucode-originated,
+        *   but apparently a few don't get set; catch them here. */
+       reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) &&
+                 (pkt->hdr.cmd != REPLY_RX_PHY_CMD) &&
+                 (pkt->hdr.cmd != REPLY_RX) &&
+                 (pkt->hdr.cmd != REPLY_RX_MPDU_CMD) &&
+                 (pkt->hdr.cmd != REPLY_COMPRESSED_BA) &&
+                 (pkt->hdr.cmd != STATISTICS_NOTIFICATION) &&
+                 (pkt->hdr.cmd != REPLY_TX);
+
+       sequence = le16_to_cpu(pkt->hdr.sequence);
+       index = SEQ_TO_INDEX(sequence);
+       cmd_index = get_cmd_index(&txq->q, index);
+
+       if (reclaim)
+               cmd = txq->cmd[cmd_index];
+       else
+               cmd = NULL;
+
+       /* warn if this is cmd response / notification and the uCode
+        * didn't set the SEQ_RX_FRAME for a frame that is
+        * uCode-originated
+        * If you saw this code after the second half of 2012, then
+        * please remove it
+        */
+       WARN(pkt->hdr.cmd != REPLY_TX && reclaim == false &&
+            (!(pkt->hdr.sequence & SEQ_RX_FRAME)),
+            "reclaim is false, SEQ_RX_FRAME unset: %s\n",
+            get_cmd_string(pkt->hdr.cmd));
+
+       err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd);
+
+       /*
+        * XXX: After here, we should always check rxcb._page
+        * against NULL before touching it or its virtual
+        * memory (pkt). Because some rx_handler might have
+        * already taken or freed the pages.
+        */
+
+       if (reclaim) {
+               /* Invoke any callbacks, transfer the buffer to caller,
+                * and fire off the (possibly) blocking
+                * iwl_trans_send_cmd()
+                * as we reclaim the driver command queue */
+               if (rxcb._page)
+                       iwl_tx_cmd_complete(trans, &rxcb, err);
+               else
+                       IWL_WARN(trans, "Claim null rxb?\n");
+       }
+
+       /* page was stolen from us */
+       if (rxcb._page == NULL)
+               rxb->page = NULL;
+
+       /* Reuse the page if possible. For notification packets and
+        * SKBs that fail to Rx correctly, add them back into the
+        * rx_free list for reuse later. */
+       spin_lock_irqsave(&rxq->lock, flags);
+       if (rxb->page != NULL) {
+               rxb->page_dma =
+                       dma_map_page(trans->dev, rxb->page, 0,
+                               PAGE_SIZE << hw_params(trans).rx_page_order,
+                               DMA_FROM_DEVICE);
+               list_add_tail(&rxb->list, &rxq->rx_free);
+               rxq->free_count++;
+       } else
+               list_add_tail(&rxb->list, &rxq->rx_used);
+       spin_unlock_irqrestore(&rxq->lock, flags);
 }
 
 /**
@@ -370,20 +472,12 @@ void iwl_bg_rx_replenish(struct work_struct *data)
  */
 static void iwl_rx_handle(struct iwl_trans *trans)
 {
-       struct iwl_rx_mem_buffer *rxb;
-       struct iwl_rx_packet *pkt;
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct iwl_rx_queue *rxq = &trans_pcie->rxq;
-       struct iwl_tx_queue *txq = &trans_pcie->txq[trans->shrd->cmd_queue];
-       struct iwl_device_cmd *cmd;
        u32 r, i;
-       int reclaim;
-       unsigned long flags;
        u8 fill_rx = 0;
        u32 count = 8;
        int total_empty;
-       int index, cmd_index;
 
        /* uCode's read index (stored in shared DRAM) indicates the last Rx
         * buffer that the driver may process (last buffer filled by ucode). */
@@ -403,102 +497,14 @@ static void iwl_rx_handle(struct iwl_trans *trans)
                fill_rx = 1;
 
        while (i != r) {
-               int len, err;
-               u16 sequence;
+               struct iwl_rx_mem_buffer *rxb;
 
                rxb = rxq->queue[i];
-
-               /* If an RXB doesn't have a Rx queue slot associated with it,
-                * then a bug has been introduced in the queue refilling
-                * routines -- catch it here */
-               if (WARN_ON(rxb == NULL)) {
-                       i = (i + 1) & RX_QUEUE_MASK;
-                       continue;
-               }
-
                rxq->queue[i] = NULL;
 
-               dma_unmap_page(trans->dev, rxb->page_dma,
-                              PAGE_SIZE << hw_params(trans).rx_page_order,
-                              DMA_FROM_DEVICE);
-               pkt = rxb_addr(rxb);
-
-               IWL_DEBUG_RX(trans, "r = %d, i = %d, %s, 0x%02x\n", r,
-                       i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd);
-
-               len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
-               len += sizeof(u32); /* account for status word */
-               trace_iwlwifi_dev_rx(priv(trans), pkt, len);
-
-               /* Reclaim a command buffer only if this packet is a response
-                *   to a (driver-originated) command.
-                * If the packet (e.g. Rx frame) originated from uCode,
-                *   there is no command buffer to reclaim.
-                * Ucode should set SEQ_RX_FRAME bit if ucode-originated,
-                *   but apparently a few don't get set; catch them here. */
-               reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) &&
-                       (pkt->hdr.cmd != REPLY_RX_PHY_CMD) &&
-                       (pkt->hdr.cmd != REPLY_RX) &&
-                       (pkt->hdr.cmd != REPLY_RX_MPDU_CMD) &&
-                       (pkt->hdr.cmd != REPLY_COMPRESSED_BA) &&
-                       (pkt->hdr.cmd != STATISTICS_NOTIFICATION) &&
-                       (pkt->hdr.cmd != REPLY_TX);
-
-               sequence = le16_to_cpu(pkt->hdr.sequence);
-               index = SEQ_TO_INDEX(sequence);
-               cmd_index = get_cmd_index(&txq->q, index);
-
-               if (reclaim)
-                       cmd = txq->cmd[cmd_index];
-               else
-                       cmd = NULL;
-
-               /* warn if this is cmd response / notification and the uCode
-                * didn't set the SEQ_RX_FRAME for a frame that is
-                * uCode-originated
-                * If you saw this code after the second half of 2012, then
-                * please remove it
-                */
-               WARN(pkt->hdr.cmd != REPLY_TX && reclaim == false &&
-                    (!(pkt->hdr.sequence & SEQ_RX_FRAME)),
-                    "reclaim is false, SEQ_RX_FRAME unset: %s\n",
-                    get_cmd_string(pkt->hdr.cmd));
-
-               err = iwl_rx_dispatch(priv(trans), rxb, cmd);
+               IWL_DEBUG_RX(trans, "rxbuf: r = %d, i = %d (%p)\n", rxb);
 
-               /*
-                * XXX: After here, we should always check rxb->page
-                * against NULL before touching it or its virtual
-                * memory (pkt). Because some rx_handler might have
-                * already taken or freed the pages.
-                */
-
-               if (reclaim) {
-                       /* Invoke any callbacks, transfer the buffer to caller,
-                        * and fire off the (possibly) blocking
-                        * iwl_trans_send_cmd()
-                        * as we reclaim the driver command queue */
-                       if (rxb->page)
-                               iwl_tx_cmd_complete(trans, rxb, err);
-                       else
-                               IWL_WARN(trans, "Claim null rxb?\n");
-               }
-
-               /* Reuse the page if possible. For notification packets and
-                * SKBs that fail to Rx correctly, add them back into the
-                * rx_free list for reuse later. */
-               spin_lock_irqsave(&rxq->lock, flags);
-               if (rxb->page != NULL) {
-                       rxb->page_dma = dma_map_page(trans->dev, rxb->page,
-                               0, PAGE_SIZE <<
-                                   hw_params(trans).rx_page_order,
-                               DMA_FROM_DEVICE);
-                       list_add_tail(&rxb->list, &rxq->rx_free);
-                       rxq->free_count++;
-               } else
-                       list_add_tail(&rxb->list, &rxq->rx_used);
-
-               spin_unlock_irqrestore(&rxq->lock, flags);
+               iwl_rx_handle_rxbuf(trans, rxb);
 
                i = (i + 1) & RX_QUEUE_MASK;
                /* If there are a lot of unused frames,
@@ -594,17 +600,16 @@ static void iwl_dump_nic_error_log(struct iwl_trans *trans)
 {
        u32 base;
        struct iwl_error_event_table table;
-       struct iwl_priv *priv = priv(trans);
        struct iwl_trans_pcie *trans_pcie =
                IWL_TRANS_GET_PCIE_TRANS(trans);
 
        base = trans->shrd->device_pointers.error_event_table;
        if (trans->shrd->ucode_type == IWL_UCODE_INIT) {
                if (!base)
-                       base = priv->init_errlog_ptr;
+                       base = trans->shrd->fw->init_errlog_ptr;
        } else {
                if (!base)
-                       base = priv->inst_errlog_ptr;
+                       base = trans->shrd->fw->inst_errlog_ptr;
        }
 
        if (!iwlagn_hw_valid_rtc_data_addr(base)) {
@@ -616,7 +621,7 @@ static void iwl_dump_nic_error_log(struct iwl_trans *trans)
                return;
        }
 
-       iwl_read_targ_mem_words(trans(priv), base, &table, sizeof(table));
+       iwl_read_targ_mem_words(trans, base, &table, sizeof(table));
 
        if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
                IWL_ERR(trans, "Start IWL Error Log Dump:\n");
@@ -626,7 +631,7 @@ static void iwl_dump_nic_error_log(struct iwl_trans *trans)
 
        trans_pcie->isr_stats.err_code = table.error_id;
 
-       trace_iwlwifi_dev_ucode_error(priv, table.error_id, table.tsf_low,
+       trace_iwlwifi_dev_ucode_error(trans->dev, table.error_id, table.tsf_low,
                                      table.data1, table.data2, table.line,
                                      table.blink1, table.blink2, table.ilink1,
                                      table.ilink2, table.bcon_time, table.gp1,
@@ -674,9 +679,8 @@ static void iwl_dump_nic_error_log(struct iwl_trans *trans)
  */
 static void iwl_irq_handle_error(struct iwl_trans *trans)
 {
-       struct iwl_priv *priv = priv(trans);
        /* W/A for WiFi/WiMAX coex and WiMAX own the RF */
-       if (cfg(priv)->internal_wimax_coex &&
+       if (cfg(trans)->internal_wimax_coex &&
            (!(iwl_read_prph(trans, APMG_CLK_CTRL_REG) &
                        APMS_CLK_VAL_MRB_FUNC_MODE) ||
             (iwl_read_prph(trans, APMG_PS_CTRL_REG) &
@@ -687,24 +691,20 @@ static void iwl_irq_handle_error(struct iwl_trans *trans)
                 */
                clear_bit(STATUS_READY, &trans->shrd->status);
                clear_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status);
-               wake_up(&priv->shrd->wait_command_queue);
+               wake_up(&trans->shrd->wait_command_queue);
                IWL_ERR(trans, "RF is used by WiMAX\n");
                return;
        }
 
        IWL_ERR(trans, "Loaded firmware version: %s\n",
-               priv->hw->wiphy->fw_version);
+               trans->shrd->fw->fw_version);
 
        iwl_dump_nic_error_log(trans);
        iwl_dump_csr(trans);
        iwl_dump_fh(trans, NULL, false);
        iwl_dump_nic_event_log(trans, false, NULL, false);
-#ifdef CONFIG_IWLWIFI_DEBUG
-       if (iwl_get_debug_level(trans->shrd) & IWL_DL_FW_ERRORS)
-               iwl_print_rx_config_cmd(priv(trans), IWL_RXON_CTX_BSS);
-#endif
 
-       iwlagn_fw_error(priv, false);
+       iwl_op_mode_nic_error(trans->op_mode);
 }
 
 #define EVENT_START_OFFSET  (4 * sizeof(u32))
@@ -723,7 +723,6 @@ static int iwl_print_event_log(struct iwl_trans *trans, u32 start_idx,
        u32 ptr;        /* SRAM byte address of log data */
        u32 ev, time, data; /* event log data */
        unsigned long reg_flags;
-       struct iwl_priv *priv = priv(trans);
 
        if (num_events == 0)
                return pos;
@@ -731,10 +730,10 @@ static int iwl_print_event_log(struct iwl_trans *trans, u32 start_idx,
        base = trans->shrd->device_pointers.log_event_table;
        if (trans->shrd->ucode_type == IWL_UCODE_INIT) {
                if (!base)
-                       base = priv->init_evtlog_ptr;
+                       base = trans->shrd->fw->init_evtlog_ptr;
        } else {
                if (!base)
-                       base = priv->inst_evtlog_ptr;
+                       base = trans->shrd->fw->inst_evtlog_ptr;
        }
 
        if (mode == 0)
@@ -746,11 +745,11 @@ static int iwl_print_event_log(struct iwl_trans *trans, u32 start_idx,
 
        /* Make sure device is powered up for SRAM reads */
        spin_lock_irqsave(&trans->reg_lock, reg_flags);
-       iwl_grab_nic_access(trans);
+       if (unlikely(!iwl_grab_nic_access(trans)))
+               goto out_unlock;
 
        /* Set starting address; reads will auto-increment */
        iwl_write32(trans, HBUS_TARG_MEM_RADDR, ptr);
-       rmb();
 
        /* "time" is actually "data" for mode 0 (no timestamp).
        * place event id # at far right for easier visual parsing. */
@@ -764,7 +763,7 @@ static int iwl_print_event_log(struct iwl_trans *trans, u32 start_idx,
                                                "EVT_LOG:0x%08x:%04u\n",
                                                time, ev);
                        } else {
-                               trace_iwlwifi_dev_ucode_event(priv, 0,
+                               trace_iwlwifi_dev_ucode_event(trans->dev, 0,
                                        time, ev);
                                IWL_ERR(trans, "EVT_LOG:0x%08x:%04u\n",
                                        time, ev);
@@ -778,7 +777,7 @@ static int iwl_print_event_log(struct iwl_trans *trans, u32 start_idx,
                        } else {
                                IWL_ERR(trans, "EVT_LOGT:%010u:0x%08x:%04u\n",
                                        time, data, ev);
-                               trace_iwlwifi_dev_ucode_event(priv, time,
+                               trace_iwlwifi_dev_ucode_event(trans->dev, time,
                                        data, ev);
                        }
                }
@@ -786,6 +785,7 @@ static int iwl_print_event_log(struct iwl_trans *trans, u32 start_idx,
 
        /* Allow device to power down */
        iwl_release_nic_access(trans);
+out_unlock:
        spin_unlock_irqrestore(&trans->reg_lock, reg_flags);
        return pos;
 }
@@ -840,17 +840,16 @@ int iwl_dump_nic_event_log(struct iwl_trans *trans, bool full_log,
        u32 logsize;
        int pos = 0;
        size_t bufsz = 0;
-       struct iwl_priv *priv = priv(trans);
 
        base = trans->shrd->device_pointers.log_event_table;
        if (trans->shrd->ucode_type == IWL_UCODE_INIT) {
-               logsize = priv->init_evtlog_size;
+               logsize = trans->shrd->fw->init_evtlog_size;
                if (!base)
-                       base = priv->init_evtlog_ptr;
+                       base = trans->shrd->fw->init_evtlog_ptr;
        } else {
-               logsize = priv->inst_evtlog_size;
+               logsize = trans->shrd->fw->inst_evtlog_size;
                if (!base)
-                       base = priv->inst_evtlog_ptr;
+                       base = trans->shrd->fw->inst_evtlog_ptr;
        }
 
        if (!iwlagn_hw_valid_rtc_data_addr(base)) {
@@ -889,7 +888,7 @@ int iwl_dump_nic_event_log(struct iwl_trans *trans, bool full_log,
        }
 
 #ifdef CONFIG_IWLWIFI_DEBUG
-       if (!(iwl_get_debug_level(trans->shrd) & IWL_DL_FW_ERRORS) && !full_log)
+       if (!(iwl_have_debug_level(IWL_DL_FW_ERRORS)) && !full_log)
                size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES)
                        ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size;
 #else
@@ -909,7 +908,7 @@ int iwl_dump_nic_event_log(struct iwl_trans *trans, bool full_log,
                if (!*buf)
                        return -ENOMEM;
        }
-       if ((iwl_get_debug_level(trans->shrd) & IWL_DL_FW_ERRORS) || full_log) {
+       if (iwl_have_debug_level(IWL_DL_FW_ERRORS) || full_log) {
                /*
                 * if uCode has wrapped back to top of log,
                 * start at the oldest entry,
@@ -949,7 +948,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans)
        struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
 
 
-       spin_lock_irqsave(&trans->shrd->lock, flags);
+       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
 
        /* Ack/clear/reset pending uCode interrupts.
         * Note:  Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS,
@@ -968,7 +967,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans)
        inta = trans_pcie->inta;
 
 #ifdef CONFIG_IWLWIFI_DEBUG
-       if (iwl_get_debug_level(trans->shrd) & IWL_DL_ISR) {
+       if (iwl_have_debug_level(IWL_DL_ISR)) {
                /* just for debug */
                inta_mask = iwl_read32(trans, CSR_INT_MASK);
                IWL_DEBUG_ISR(trans, "inta 0x%08x, enabled 0x%08x\n ",
@@ -979,7 +978,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans)
        /* saved interrupt in inta variable now we can reset trans_pcie->inta */
        trans_pcie->inta = 0;
 
-       spin_unlock_irqrestore(&trans->shrd->lock, flags);
+       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 
        /* Now service all interrupt bits discovered above. */
        if (inta & CSR_INT_BIT_HW_ERR) {
@@ -997,7 +996,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans)
        }
 
 #ifdef CONFIG_IWLWIFI_DEBUG
-       if (iwl_get_debug_level(trans->shrd) & (IWL_DL_ISR)) {
+       if (iwl_have_debug_level(IWL_DL_ISR)) {
                /* NIC fires this, but we don't use it, redundant with WAKEUP */
                if (inta & CSR_INT_BIT_SCD) {
                        IWL_DEBUG_ISR(trans, "Scheduler finished to transmit "
@@ -1017,30 +1016,16 @@ void iwl_irq_tasklet(struct iwl_trans *trans)
 
        /* HW RF KILL switch toggled */
        if (inta & CSR_INT_BIT_RF_KILL) {
-               int hw_rf_kill = 0;
-               if (!(iwl_read32(trans, CSR_GP_CNTRL) &
-                               CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
-                       hw_rf_kill = 1;
+               bool hw_rfkill;
 
+               hw_rfkill = !(iwl_read32(trans, CSR_GP_CNTRL) &
+                               CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW);
                IWL_WARN(trans, "RF_KILL bit toggled to %s.\n",
-                               hw_rf_kill ? "disable radio" : "enable radio");
+                               hw_rfkill ? "disable radio" : "enable radio");
 
                isr_stats->rfkill++;
 
-               /* driver only loads ucode once setting the interface up.
-                * the driver allows loading the ucode even if the radio
-                * is killed. Hence update the killswitch state here. The
-                * rfkill handler will care about restarting if needed.
-                */
-               if (!test_bit(STATUS_ALIVE, &trans->shrd->status)) {
-                       if (hw_rf_kill)
-                               set_bit(STATUS_RF_KILL_HW,
-                                       &trans->shrd->status);
-                       else
-                               clear_bit(STATUS_RF_KILL_HW,
-                                         &trans->shrd->status);
-                       iwl_set_hw_rfkill_state(priv(trans), hw_rf_kill);
-               }
+               iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
 
                handled |= CSR_INT_BIT_RF_KILL;
        }
@@ -1065,7 +1050,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans)
        if (inta & CSR_INT_BIT_WAKEUP) {
                IWL_DEBUG_ISR(trans, "Wakeup interrupt\n");
                iwl_rx_queue_update_write_ptr(trans, &trans_pcie->rxq);
-               for (i = 0; i < hw_params(trans).max_txq_num; i++)
+               for (i = 0; i < cfg(trans)->base_params->num_of_queues; i++)
                        iwl_txq_update_write_ptr(trans,
                                                 &trans_pcie->txq[i]);
 
@@ -1130,8 +1115,8 @@ 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 */
-               trans->ucode_write_complete = 1;
-               wake_up(&trans->shrd->wait_command_queue);
+               trans_pcie->ucode_write_complete = true;
+               wake_up(&trans_pcie->ucode_write_waitq);
        }
 
        if (inta & ~handled) {
@@ -1146,13 +1131,11 @@ void iwl_irq_tasklet(struct iwl_trans *trans)
 
        /* Re-enable all interrupts */
        /* only Re-enable if disabled by irq */
-       if (test_bit(STATUS_INT_ENABLED, &trans->shrd->status))
+       if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status))
                iwl_enable_interrupts(trans);
        /* Re-enable RF_KILL if it occurred */
-       else if (handled & CSR_INT_BIT_RF_KILL) {
-               IWL_DEBUG_ISR(trans, "Enabling rfkill interrupt\n");
-               iwl_write32(trans, CSR_INT_MASK, CSR_INT_BIT_RF_KILL);
-       }
+       else if (handled & CSR_INT_BIT_RF_KILL)
+               iwl_enable_rfkill_int(trans);
 }
 
 /******************************************************************************
@@ -1232,7 +1215,7 @@ void iwl_reset_ict(struct iwl_trans *trans)
        if (!trans_pcie->ict_tbl)
                return;
 
-       spin_lock_irqsave(&trans->shrd->lock, flags);
+       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
        iwl_disable_interrupts(trans);
 
        memset(trans_pcie->ict_tbl, 0, ICT_SIZE);
@@ -1249,7 +1232,7 @@ void iwl_reset_ict(struct iwl_trans *trans)
        trans_pcie->ict_index = 0;
        iwl_write32(trans, CSR_INT, trans_pcie->inta_mask);
        iwl_enable_interrupts(trans);
-       spin_unlock_irqrestore(&trans->shrd->lock, flags);
+       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 }
 
 /* Device is going down disable ict interrupt usage */
@@ -1260,9 +1243,9 @@ void iwl_disable_ict(struct iwl_trans *trans)
 
        unsigned long flags;
 
-       spin_lock_irqsave(&trans->shrd->lock, flags);
+       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
        trans_pcie->use_ict = false;
-       spin_unlock_irqrestore(&trans->shrd->lock, flags);
+       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 }
 
 static irqreturn_t iwl_isr(int irq, void *data)
@@ -1277,11 +1260,11 @@ static irqreturn_t iwl_isr(int irq, void *data)
        if (!trans)
                return IRQ_NONE;
 
-       trace_iwlwifi_dev_irq(priv(trans));
+       trace_iwlwifi_dev_irq(trans->dev);
 
        trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 
-       spin_lock_irqsave(&trans->shrd->lock, flags);
+       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
 
        /* Disable (but don't clear!) interrupts here to avoid
         *    back-to-back ISRs and sporadic interrupts from our NIC.
@@ -1309,7 +1292,7 @@ static irqreturn_t iwl_isr(int irq, void *data)
        }
 
 #ifdef CONFIG_IWLWIFI_DEBUG
-       if (iwl_get_debug_level(trans->shrd) & (IWL_DL_ISR)) {
+       if (iwl_have_debug_level(IWL_DL_ISR)) {
                inta_fh = iwl_read32(trans, CSR_FH_INT_STATUS);
                IWL_DEBUG_ISR(trans, "ISR inta 0x%08x, enabled 0x%08x, "
                              "fh 0x%08x\n", inta, inta_mask, inta_fh);
@@ -1320,22 +1303,22 @@ static irqreturn_t iwl_isr(int irq, void *data)
        /* iwl_irq_tasklet() will service interrupts and re-enable them */
        if (likely(inta))
                tasklet_schedule(&trans_pcie->irq_tasklet);
-       else if (test_bit(STATUS_INT_ENABLED, &trans->shrd->status) &&
+       else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
                        !trans_pcie->inta)
                iwl_enable_interrupts(trans);
 
  unplugged:
-       spin_unlock_irqrestore(&trans->shrd->lock, flags);
+       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
        return IRQ_HANDLED;
 
  none:
        /* re-enable interrupts here since we don't have anything to service. */
        /* only Re-enable if disabled by irq  and no schedules tasklet. */
-       if (test_bit(STATUS_INT_ENABLED, &trans->shrd->status) &&
+       if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
                !trans_pcie->inta)
                iwl_enable_interrupts(trans);
 
-       spin_unlock_irqrestore(&trans->shrd->lock, flags);
+       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
        return IRQ_NONE;
 }
 
@@ -1367,9 +1350,9 @@ irqreturn_t iwl_isr_ict(int irq, void *data)
        if (!trans_pcie->use_ict)
                return iwl_isr(irq, data);
 
-       trace_iwlwifi_dev_irq(priv(trans));
+       trace_iwlwifi_dev_irq(trans->dev);
 
-       spin_lock_irqsave(&trans->shrd->lock, flags);
+       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
 
        /* Disable (but don't clear!) interrupts here to avoid
         * back-to-back ISRs and sporadic interrupts from our NIC.
@@ -1384,7 +1367,7 @@ irqreturn_t iwl_isr_ict(int irq, void *data)
         * This may be due to IRQ shared with another device,
         * or due to sporadic interrupts thrown from our NIC. */
        read = le32_to_cpu(trans_pcie->ict_tbl[trans_pcie->ict_index]);
-       trace_iwlwifi_dev_ict_read(priv(trans), trans_pcie->ict_index, read);
+       trace_iwlwifi_dev_ict_read(trans->dev, trans_pcie->ict_index, read);
        if (!read) {
                IWL_DEBUG_ISR(trans, "Ignore interrupt, inta == 0\n");
                goto none;
@@ -1403,7 +1386,7 @@ irqreturn_t iwl_isr_ict(int irq, void *data)
                        iwl_queue_inc_wrap(trans_pcie->ict_index, ICT_COUNT);
 
                read = le32_to_cpu(trans_pcie->ict_tbl[trans_pcie->ict_index]);
-               trace_iwlwifi_dev_ict_read(priv(trans), trans_pcie->ict_index,
+               trace_iwlwifi_dev_ict_read(trans->dev, trans_pcie->ict_index,
                                           read);
        } while (read);
 
@@ -1431,7 +1414,7 @@ irqreturn_t iwl_isr_ict(int irq, void *data)
        /* iwl_irq_tasklet() will service interrupts and re-enable them */
        if (likely(inta))
                tasklet_schedule(&trans_pcie->irq_tasklet);
-       else if (test_bit(STATUS_INT_ENABLED, &trans->shrd->status) &&
+       else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
                 !trans_pcie->inta) {
                /* Allow interrupt if was disabled by this handler and
                 * no tasklet was schedules, We should not enable interrupt,
@@ -1440,17 +1423,17 @@ irqreturn_t iwl_isr_ict(int irq, void *data)
                iwl_enable_interrupts(trans);
        }
 
-       spin_unlock_irqrestore(&trans->shrd->lock, flags);
+       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
        return IRQ_HANDLED;
 
  none:
        /* re-enable interrupts here since we don't have anything to service.
         * only Re-enable if disabled by irq.
         */
-       if (test_bit(STATUS_INT_ENABLED, &trans->shrd->status) &&
+       if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
            !trans_pcie->inta)
                iwl_enable_interrupts(trans);
 
-       spin_unlock_irqrestore(&trans->shrd->lock, flags);
+       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
        return IRQ_NONE;
 }
index a8dfecadea11990a2ec7804bb631b331806836ae..eb430b6e1cde621e41b25903b4ecdd2b923a4ccb 100644 (file)
 #include "iwl-prph.h"
 #include "iwl-io.h"
 #include "iwl-agn-hw.h"
+#include "iwl-op-mode.h"
 #include "iwl-trans-pcie-int.h"
 
 #define IWL_TX_CRC_SIZE 4
 #define IWL_TX_DELIMITER_SIZE 4
 
+/*
+ * mac80211 queues, ACs, hardware queues, FIFOs.
+ *
+ * Cf. http://wireless.kernel.org/en/developers/Documentation/mac80211/queues
+ *
+ * Mac80211 uses the following numbers, which we get as from it
+ * by way of skb_get_queue_mapping(skb):
+ *
+ *     VO      0
+ *     VI      1
+ *     BE      2
+ *     BK      3
+ *
+ *
+ * Regular (not A-MPDU) frames are put into hardware queues corresponding
+ * to the FIFOs, see comments in iwl-prph.h. Aggregated frames get their
+ * own queue per aggregation session (RA/TID combination), such queues are
+ * set up to map into FIFOs too, for which we need an AC->FIFO mapping. In
+ * order to map frames to the right queue, we also need an AC->hw queue
+ * mapping. This is implemented here.
+ *
+ * Due to the way hw queues are set up (by the hw specific code), the AC->hw
+ * queue mapping is the identity mapping.
+ */
+
+static const u8 tid_to_ac[] = {
+       IEEE80211_AC_BE,
+       IEEE80211_AC_BK,
+       IEEE80211_AC_BK,
+       IEEE80211_AC_BE,
+       IEEE80211_AC_VI,
+       IEEE80211_AC_VI,
+       IEEE80211_AC_VO,
+       IEEE80211_AC_VO
+};
+
+
 /**
  * iwl_trans_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
  */
@@ -98,7 +136,7 @@ void iwl_txq_update_write_ptr(struct iwl_trans *trans, struct iwl_tx_queue *txq)
        if (txq->need_update == 0)
                return;
 
-       if (hw_params(trans).shadow_reg_enable) {
+       if (cfg(trans)->base_params->shadow_reg_enable) {
                /* shadow register enabled */
                iwl_write32(trans, HBUS_TARG_WRPTR,
                            txq->q.write_ptr | (txq_id << 8));
@@ -216,6 +254,8 @@ void iwlagn_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq,
 {
        struct iwl_tfd *tfd_tmp = txq->tfds;
 
+       lockdep_assert_held(&txq->lock);
+
        iwlagn_unmap_tfd(trans, &txq->meta[index], &tfd_tmp[index], dma_dir);
 
        /* free SKB */
@@ -229,7 +269,7 @@ void iwlagn_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq,
                 * freed and that the queue is not empty - free the skb
                 */
                if (skb) {
-                       iwl_free_skb(priv(trans), skb);
+                       iwl_op_mode_free_skb(trans->op_mode, skb);
                        txq->skbs[index] = NULL;
                }
        }
@@ -357,7 +397,7 @@ static void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_trans *trans,
 
        WARN_ON(read_ptr >= TFD_QUEUE_SIZE_MAX);
 
-       if (txq_id != trans->shrd->cmd_queue)
+       if (txq_id != trans_pcie->cmd_queue)
                sta_id = tx_cmd->sta_id;
 
        bc_ent = cpu_to_le16(1 | (sta_id << 12));
@@ -439,6 +479,15 @@ void iwl_trans_tx_queue_set_status(struct iwl_trans *trans,
                        scd_retry ? "BA" : "AC/CMD", txq_id);
 }
 
+static inline int get_ac_from_tid(u16 tid)
+{
+       if (likely(tid < ARRAY_SIZE(tid_to_ac)))
+               return tid_to_ac[tid];
+
+       /* no support for TIDs 8-15 yet */
+       return -EINVAL;
+}
+
 static inline int get_fifo_from_tid(struct iwl_trans_pcie *trans_pcie,
                                    u8 ctx, u16 tid)
 {
@@ -492,7 +541,7 @@ void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans,
 
        ra_tid = BUILD_RAxTID(sta_id, tid);
 
-       spin_lock_irqsave(&trans->shrd->lock, flags);
+       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
 
        /* Stop this Tx queue before configuring it */
        iwlagn_tx_queue_stop_scheduler(trans, txq_id);
@@ -532,7 +581,7 @@ void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans,
        trans_pcie->txq[txq_id].sta_id = sta_id;
        trans_pcie->txq[txq_id].tid = tid;
 
-       spin_unlock_irqrestore(&trans->shrd->lock, flags);
+       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 }
 
 /*
@@ -546,7 +595,8 @@ static int iwlagn_txq_ctx_activate_free(struct iwl_trans *trans)
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        int txq_id;
 
-       for (txq_id = 0; txq_id < hw_params(trans).max_txq_num; txq_id++)
+       for (txq_id = 0; txq_id < cfg(trans)->base_params->num_of_queues;
+            txq_id++)
                if (!test_and_set_bit(txq_id,
                                        &trans_pcie->txq_ctx_active_msk))
                        return txq_id;
@@ -615,15 +665,13 @@ int iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans, int sta_id, int tid)
 static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_tx_queue *txq = &trans_pcie->txq[trans->shrd->cmd_queue];
+       struct iwl_tx_queue *txq = &trans_pcie->txq[trans_pcie->cmd_queue];
        struct iwl_queue *q = &txq->q;
        struct iwl_device_cmd *out_cmd;
        struct iwl_cmd_meta *out_meta;
        dma_addr_t phys_addr;
-       unsigned long flags;
        u32 idx;
        u16 copy_size, cmd_size;
-       bool is_ct_kill = false;
        bool had_nocopy = false;
        int i;
        u8 *cmd_dest;
@@ -638,12 +686,6 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
                return -EIO;
        }
 
-       if ((trans->shrd->ucode_owner == IWL_OWNERSHIP_TM) &&
-           !(cmd->flags & CMD_ON_DEMAND)) {
-               IWL_DEBUG_HC(trans, "tm own the uCode, no regular hcmd send\n");
-               return -EIO;
-       }
-
        copy_size = sizeof(out_cmd->hdr);
        cmd_size = sizeof(out_cmd->hdr);
 
@@ -673,23 +715,13 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
        if (WARN_ON(copy_size > TFD_MAX_PAYLOAD_SIZE))
                return -EINVAL;
 
-       if (iwl_is_rfkill(trans->shrd) || iwl_is_ctkill(trans->shrd)) {
-               IWL_WARN(trans, "Not sending command - %s KILL\n",
-                        iwl_is_rfkill(trans->shrd) ? "RF" : "CT");
-               return -EIO;
-       }
-
-       spin_lock_irqsave(&trans->hcmd_lock, flags);
+       spin_lock_bh(&txq->lock);
 
        if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) {
-               spin_unlock_irqrestore(&trans->hcmd_lock, flags);
+               spin_unlock_bh(&txq->lock);
 
                IWL_ERR(trans, "No space in command queue\n");
-               is_ct_kill = iwl_check_for_ct_kill(priv(trans));
-               if (!is_ct_kill) {
-                       IWL_ERR(trans, "Restarting adapter queue is full\n");
-                       iwlagn_fw_error(priv(trans), false);
-               }
+               iwl_op_mode_cmd_queue_full(trans->op_mode);
                return -ENOSPC;
        }
 
@@ -706,7 +738,7 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
        out_cmd->hdr.cmd = cmd->id;
        out_cmd->hdr.flags = 0;
        out_cmd->hdr.sequence =
-               cpu_to_le16(QUEUE_TO_SEQ(trans->shrd->cmd_queue) |
+               cpu_to_le16(QUEUE_TO_SEQ(trans_pcie->cmd_queue) |
                                         INDEX_TO_SEQ(q->write_ptr));
 
        /* and copy the data that needs to be copied */
@@ -726,7 +758,7 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
                        get_cmd_string(out_cmd->hdr.cmd),
                        out_cmd->hdr.cmd,
                        le16_to_cpu(out_cmd->hdr.sequence), cmd_size,
-                       q->write_ptr, idx, trans->shrd->cmd_queue);
+                       q->write_ptr, idx, trans_pcie->cmd_queue);
 
        phys_addr = dma_map_single(trans->dev, &out_cmd->hdr, copy_size,
                                DMA_BIDIRECTIONAL);
@@ -778,7 +810,7 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
        /* check that tracing gets all possible blocks */
        BUILD_BUG_ON(IWL_MAX_CMD_TFDS + 1 != 3);
 #ifdef CONFIG_IWLWIFI_DEVICE_TRACING
-       trace_iwlwifi_dev_hcmd(priv(trans), cmd->flags,
+       trace_iwlwifi_dev_hcmd(trans->dev, cmd->flags,
                               trace_bufs[0], trace_lens[0],
                               trace_bufs[1], trace_lens[1],
                               trace_bufs[2], trace_lens[2]);
@@ -789,7 +821,7 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
        iwl_txq_update_write_ptr(trans, txq);
 
  out:
-       spin_unlock_irqrestore(&trans->hcmd_lock, flags);
+       spin_unlock_bh(&txq->lock);
        return idx;
 }
 
@@ -808,6 +840,8 @@ static void iwl_hcmd_queue_reclaim(struct iwl_trans *trans, int txq_id,
        struct iwl_queue *q = &txq->q;
        int nfreed = 0;
 
+       lockdep_assert_held(&txq->lock);
+
        if ((idx >= q->n_bd) || (iwl_queue_used(q, idx) == 0)) {
                IWL_ERR(trans, "%s: Read index for DMA queue txq id (%d), "
                          "index %d is out of range [0-%d] %d %d.\n", __func__,
@@ -821,7 +855,7 @@ static void iwl_hcmd_queue_reclaim(struct iwl_trans *trans, int txq_id,
                if (nfreed++ > 0) {
                        IWL_ERR(trans, "HCMD skipped: index (%d) %d %d\n", idx,
                                        q->write_ptr, q->read_ptr);
-                       iwlagn_fw_error(priv(trans), false);
+                       iwl_op_mode_nic_error(trans->op_mode);
                }
 
        }
@@ -837,7 +871,7 @@ static void iwl_hcmd_queue_reclaim(struct iwl_trans *trans, int txq_id,
  * will be executed.  The attached skb (if present) will only be freed
  * if the callback returns 1
  */
-void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_mem_buffer *rxb,
+void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_cmd_buffer *rxb,
                         int handler_status)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
@@ -848,21 +882,22 @@ void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_mem_buffer *rxb,
        struct iwl_device_cmd *cmd;
        struct iwl_cmd_meta *meta;
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_tx_queue *txq = &trans_pcie->txq[trans->shrd->cmd_queue];
-       unsigned long flags;
+       struct iwl_tx_queue *txq = &trans_pcie->txq[trans_pcie->cmd_queue];
 
        /* If a Tx command is being handled and it isn't in the actual
         * command queue then there a command routing bug has been introduced
         * in the queue management code. */
-       if (WARN(txq_id != trans->shrd->cmd_queue,
+       if (WARN(txq_id != trans_pcie->cmd_queue,
                 "wrong command queue %d (should be %d), sequence 0x%X readp=%d writep=%d\n",
-                 txq_id, trans->shrd->cmd_queue, sequence,
-                 trans_pcie->txq[trans->shrd->cmd_queue].q.read_ptr,
-                 trans_pcie->txq[trans->shrd->cmd_queue].q.write_ptr)) {
+                 txq_id, trans_pcie->cmd_queue, sequence,
+                 trans_pcie->txq[trans_pcie->cmd_queue].q.read_ptr,
+                 trans_pcie->txq[trans_pcie->cmd_queue].q.write_ptr)) {
                iwl_print_hex_error(trans, pkt, 32);
                return;
        }
 
+       spin_lock(&txq->lock);
+
        cmd_index = get_cmd_index(&txq->q, index);
        cmd = txq->cmd[cmd_index];
        meta = &txq->meta[cmd_index];
@@ -874,13 +909,14 @@ void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_mem_buffer *rxb,
 
        /* Input error checking is done when commands are added to queue. */
        if (meta->flags & CMD_WANT_SKB) {
-               meta->source->reply_page = (unsigned long)rxb_addr(rxb);
+               struct page *p = rxb_steal_page(rxb);
+
+               meta->source->resp_pkt = pkt;
+               meta->source->_rx_page_addr = (unsigned long)page_address(p);
+               meta->source->_rx_page_order = hw_params(trans).rx_page_order;
                meta->source->handler_status = handler_status;
-               rxb->page = NULL;
        }
 
-       spin_lock_irqsave(&trans->hcmd_lock, flags);
-
        iwl_hcmd_queue_reclaim(trans, txq_id, index);
 
        if (!(meta->flags & CMD_ASYNC)) {
@@ -897,7 +933,7 @@ void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_mem_buffer *rxb,
 
        meta->flags = 0;
 
-       spin_unlock_irqrestore(&trans->hcmd_lock, flags);
+       spin_unlock(&txq->lock);
 }
 
 #define HOST_COMPLETE_TIMEOUT (2 * HZ)
@@ -911,12 +947,9 @@ static int iwl_send_cmd_async(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
                return -EINVAL;
 
 
-       if (test_bit(STATUS_EXIT_PENDING, &trans->shrd->status))
-               return -EBUSY;
-
        ret = iwl_enqueue_hcmd(trans, cmd);
        if (ret < 0) {
-               IWL_DEBUG_QUIET_RFKILL(trans,
+               IWL_ERR(trans,
                        "Error sending %s: enqueue_hcmd failed: %d\n",
                          get_cmd_string(cmd->id), ret);
                return ret;
@@ -930,26 +963,22 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
        int cmd_idx;
        int ret;
 
-       lockdep_assert_held(&trans->shrd->mutex);
-
        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);
+
+       if (WARN_ON(test_and_set_bit(STATUS_HCMD_ACTIVE,
+                                    &trans->shrd->status))) {
+               IWL_ERR(trans, "Command %s: a command is already active!\n",
+                       get_cmd_string(cmd->id));
+               return -EIO;
+       }
+
        IWL_DEBUG_INFO(trans, "Setting HCMD_ACTIVE for command %s\n",
                        get_cmd_string(cmd->id));
 
@@ -957,7 +986,7 @@ 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_DEBUG_QUIET_RFKILL(trans,
+               IWL_ERR(trans,
                        "Error sending %s: enqueue_hcmd failed: %d\n",
                          get_cmd_string(cmd->id), ret);
                return ret;
@@ -969,15 +998,15 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
        if (!ret) {
                if (test_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status)) {
                        struct iwl_tx_queue *txq =
-                               &trans_pcie->txq[trans->shrd->cmd_queue];
+                               &trans_pcie->txq[trans_pcie->cmd_queue];
                        struct iwl_queue *q = &txq->q;
 
-                       IWL_DEBUG_QUIET_RFKILL(trans,
+                       IWL_ERR(trans,
                                "Error sending %s: time out after %dms.\n",
                                get_cmd_string(cmd->id),
                                jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));
 
-                       IWL_DEBUG_QUIET_RFKILL(trans,
+                       IWL_ERR(trans,
                                "Current CMD queue read_ptr %d write_ptr %d\n",
                                q->read_ptr, q->write_ptr);
 
@@ -989,7 +1018,7 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
                }
        }
 
-       if ((cmd->flags & CMD_WANT_SKB) && !cmd->reply_page) {
+       if ((cmd->flags & CMD_WANT_SKB) && !cmd->resp_pkt) {
                IWL_ERR(trans, "Error: Response NULL in '%s'\n",
                          get_cmd_string(cmd->id));
                ret = -EIO;
@@ -1006,13 +1035,13 @@ cancel:
                 * in later, it will possibly set an invalid
                 * address (cmd->meta.source).
                 */
-               trans_pcie->txq[trans->shrd->cmd_queue].meta[cmd_idx].flags &=
+               trans_pcie->txq[trans_pcie->cmd_queue].meta[cmd_idx].flags &=
                                                        ~CMD_WANT_SKB;
        }
 
-       if (cmd->reply_page) {
-               iwl_free_pages(trans->shrd, cmd->reply_page);
-               cmd->reply_page = 0;
+       if (cmd->resp_pkt) {
+               iwl_free_resp(cmd);
+               cmd->resp_pkt = NULL;
        }
 
        return ret;
@@ -1037,9 +1066,11 @@ int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index,
        int freed = 0;
 
        /* This function is not meant to release cmd queue*/
-       if (WARN_ON(txq_id == trans->shrd->cmd_queue))
+       if (WARN_ON(txq_id == trans_pcie->cmd_queue))
                return 0;
 
+       lockdep_assert_held(&txq->lock);
+
        /*Since we free until index _not_ inclusive, the one before index is
         * the last we will free. This one must be used */
        last_to_free = iwl_queue_dec_wrap(index, q->n_bd);
index f5cb5d3cd92641826cb12c33248184e56c8c1b16..91628565409fe2c1f2b0e5650c638764156f82f0 100644 (file)
 #include "iwl-shared.h"
 #include "iwl-eeprom.h"
 #include "iwl-agn-hw.h"
-#include "iwl-core.h"
+
+#define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo))))
+
+#define SCD_QUEUECHAIN_SEL_ALL(trans, trans_pcie)      \
+       (((1<<cfg(trans)->base_params->num_of_queues) - 1) &\
+       (~(1<<(trans_pcie)->cmd_queue)))
 
 static int iwl_trans_rx_alloc(struct iwl_trans *trans)
 {
@@ -219,10 +224,10 @@ static int iwl_rx_init(struct iwl_trans *trans)
 
        iwl_trans_rx_hw_init(trans, rxq);
 
-       spin_lock_irqsave(&trans->shrd->lock, flags);
+       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
        rxq->need_update = 1;
        iwl_rx_queue_update_write_ptr(trans, rxq);
-       spin_unlock_irqrestore(&trans->shrd->lock, flags);
+       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 
        return 0;
 }
@@ -300,6 +305,7 @@ static int iwl_trans_txq_alloc(struct iwl_trans *trans,
 {
        size_t tfd_sz = sizeof(struct iwl_tfd) * TFD_QUEUE_SIZE_MAX;
        int i;
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 
        if (WARN_ON(txq->meta || txq->cmd || txq->skbs || txq->tfds))
                return -EINVAL;
@@ -312,7 +318,7 @@ static int iwl_trans_txq_alloc(struct iwl_trans *trans,
        if (!txq->meta || !txq->cmd)
                goto error;
 
-       if (txq_id == trans->shrd->cmd_queue)
+       if (txq_id == trans_pcie->cmd_queue)
                for (i = 0; i < slots_num; i++) {
                        txq->cmd[i] = kmalloc(sizeof(struct iwl_device_cmd),
                                                GFP_KERNEL);
@@ -323,7 +329,7 @@ static int iwl_trans_txq_alloc(struct iwl_trans *trans,
        /* Alloc driver data array and TFD circular buffer */
        /* Driver private data, only for Tx (not command) queues,
         * not shared with device. */
-       if (txq_id != trans->shrd->cmd_queue) {
+       if (txq_id != trans_pcie->cmd_queue) {
                txq->skbs = kcalloc(TFD_QUEUE_SIZE_MAX, sizeof(txq->skbs[0]),
                                    GFP_KERNEL);
                if (!txq->skbs) {
@@ -351,7 +357,7 @@ error:
        txq->skbs = NULL;
        /* since txq->cmd has been zeroed,
         * all non allocated cmd[i] will be NULL */
-       if (txq->cmd && txq_id == trans->shrd->cmd_queue)
+       if (txq->cmd && txq_id == trans_pcie->cmd_queue)
                for (i = 0; i < slots_num; i++)
                        kfree(txq->cmd[i]);
        kfree(txq->meta);
@@ -389,6 +395,8 @@ static int iwl_trans_txq_init(struct iwl_trans *trans, struct iwl_tx_queue *txq,
        if (ret)
                return ret;
 
+       spin_lock_init(&txq->lock);
+
        /*
         * Tell nic where to find circular buffer of Tx Frame Descriptors for
         * given Tx queue, and enable the DMA channel used for that queue.
@@ -408,8 +416,6 @@ static void iwl_tx_queue_unmap(struct iwl_trans *trans, int txq_id)
        struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
        struct iwl_queue *q = &txq->q;
        enum dma_data_direction dma_dir;
-       unsigned long flags;
-       spinlock_t *lock;
 
        if (!q->n_bd)
                return;
@@ -417,22 +423,19 @@ static void iwl_tx_queue_unmap(struct iwl_trans *trans, int txq_id)
        /* In the command queue, all the TBs are mapped as BIDI
         * so unmap them as such.
         */
-       if (txq_id == trans->shrd->cmd_queue) {
+       if (txq_id == trans_pcie->cmd_queue)
                dma_dir = DMA_BIDIRECTIONAL;
-               lock = &trans->hcmd_lock;
-       } else {
+       else
                dma_dir = DMA_TO_DEVICE;
-               lock = &trans->shrd->sta_lock;
-       }
 
-       spin_lock_irqsave(lock, flags);
+       spin_lock_bh(&txq->lock);
        while (q->write_ptr != q->read_ptr) {
                /* The read_ptr needs to bound by q->n_window */
                iwlagn_txq_free_tfd(trans, txq, get_cmd_index(q, q->read_ptr),
                                    dma_dir);
                q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd);
        }
-       spin_unlock_irqrestore(lock, flags);
+       spin_unlock_bh(&txq->lock);
 }
 
 /**
@@ -456,7 +459,7 @@ static void iwl_tx_queue_free(struct iwl_trans *trans, int txq_id)
 
        /* De-alloc array of command/tx buffers */
 
-       if (txq_id == trans->shrd->cmd_queue)
+       if (txq_id == trans_pcie->cmd_queue)
                for (i = 0; i < txq->q.n_window; i++)
                        kfree(txq->cmd[i]);
 
@@ -494,7 +497,7 @@ static void iwl_trans_pcie_tx_free(struct iwl_trans *trans)
        /* Tx queues */
        if (trans_pcie->txq) {
                for (txq_id = 0;
-                    txq_id < hw_params(trans).max_txq_num; txq_id++)
+                    txq_id < cfg(trans)->base_params->num_of_queues; txq_id++)
                        iwl_tx_queue_free(trans, txq_id);
        }
 
@@ -519,7 +522,7 @@ static int iwl_trans_tx_alloc(struct iwl_trans *trans)
        int txq_id, slots_num;
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 
-       u16 scd_bc_tbls_size = hw_params(trans).max_txq_num *
+       u16 scd_bc_tbls_size = cfg(trans)->base_params->num_of_queues *
                        sizeof(struct iwlagn_scd_bc_tbl);
 
        /*It is not allowed to alloc twice, so warn when this happens.
@@ -543,7 +546,7 @@ static int iwl_trans_tx_alloc(struct iwl_trans *trans)
                goto error;
        }
 
-       trans_pcie->txq = kcalloc(hw_params(trans).max_txq_num,
+       trans_pcie->txq = kcalloc(cfg(trans)->base_params->num_of_queues,
                                  sizeof(struct iwl_tx_queue), GFP_KERNEL);
        if (!trans_pcie->txq) {
                IWL_ERR(trans, "Not enough memory for txq\n");
@@ -552,8 +555,9 @@ static int iwl_trans_tx_alloc(struct iwl_trans *trans)
        }
 
        /* Alloc and init all Tx queues, including the command queue (#4/#9) */
-       for (txq_id = 0; txq_id < hw_params(trans).max_txq_num; txq_id++) {
-               slots_num = (txq_id == trans->shrd->cmd_queue) ?
+       for (txq_id = 0; txq_id < cfg(trans)->base_params->num_of_queues;
+            txq_id++) {
+               slots_num = (txq_id == trans_pcie->cmd_queue) ?
                                        TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
                ret = iwl_trans_txq_alloc(trans, &trans_pcie->txq[txq_id],
                                          slots_num, txq_id);
@@ -585,7 +589,7 @@ static int iwl_tx_init(struct iwl_trans *trans)
                alloc = true;
        }
 
-       spin_lock_irqsave(&trans->shrd->lock, flags);
+       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
 
        /* Turn off all Tx DMA fifos */
        iwl_write_prph(trans, SCD_TXFACT, 0);
@@ -594,11 +598,12 @@ static int iwl_tx_init(struct iwl_trans *trans)
        iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG,
                           trans_pcie->kw.dma >> 4);
 
-       spin_unlock_irqrestore(&trans->shrd->lock, flags);
+       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 
        /* Alloc and init all Tx queues, including the command queue (#4/#9) */
-       for (txq_id = 0; txq_id < hw_params(trans).max_txq_num; txq_id++) {
-               slots_num = (txq_id == trans->shrd->cmd_queue) ?
+       for (txq_id = 0; txq_id < cfg(trans)->base_params->num_of_queues;
+            txq_id++) {
+               slots_num = (txq_id == trans_pcie->cmd_queue) ?
                                        TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
                ret = iwl_trans_txq_init(trans, &trans_pcie->txq[txq_id],
                                         slots_num, txq_id);
@@ -686,6 +691,7 @@ static void iwl_apm_config(struct iwl_trans *trans)
  */
 static int iwl_apm_init(struct iwl_trans *trans)
 {
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        int ret = 0;
        IWL_DEBUG_INFO(trans, "Init card's basic functions\n");
 
@@ -755,7 +761,7 @@ static int iwl_apm_init(struct iwl_trans *trans)
        iwl_set_bits_prph(trans, APMG_PCIDEV_STT_REG,
                          APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
 
-       set_bit(STATUS_DEVICE_ENABLED, &trans->shrd->status);
+       set_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status);
 
 out:
        return ret;
@@ -781,9 +787,10 @@ static int iwl_apm_stop_master(struct iwl_trans *trans)
 
 static void iwl_apm_stop(struct iwl_trans *trans)
 {
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        IWL_DEBUG_INFO(trans, "Stop card, put in low power state\n");
 
-       clear_bit(STATUS_DEVICE_ENABLED, &trans->shrd->status);
+       clear_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status);
 
        /* Stop device's DMA activity */
        iwl_apm_stop_master(trans);
@@ -803,21 +810,22 @@ static void iwl_apm_stop(struct iwl_trans *trans)
 
 static int iwl_nic_init(struct iwl_trans *trans)
 {
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        unsigned long flags;
 
        /* nic_init */
-       spin_lock_irqsave(&trans->shrd->lock, flags);
+       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
        iwl_apm_init(trans);
 
        /* Set interrupt coalescing calibration timer to default (512 usecs) */
        iwl_write8(trans, CSR_INT_COALESCING,
                IWL_HOST_INT_CALIB_TIMEOUT_DEF);
 
-       spin_unlock_irqrestore(&trans->shrd->lock, flags);
+       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 
        iwl_set_pwr_vmain(trans);
 
-       iwl_nic_config(priv(trans));
+       iwl_op_mode_nic_config(trans->op_mode);
 
 #ifndef CONFIG_IWLWIFI_IDI
        /* Allocate the RX queue, or reset if it is already allocated */
@@ -828,14 +836,12 @@ static int iwl_nic_init(struct iwl_trans *trans)
        if (iwl_tx_init(trans))
                return -ENOMEM;
 
-       if (hw_params(trans).shadow_reg_enable) {
+       if (cfg(trans)->base_params->shadow_reg_enable) {
                /* enable shadow regs in HW */
                iwl_set_bit(trans, CSR_MAC_SHADOW_REG_CTRL,
                        0x800FFFFF);
        }
 
-       set_bit(STATUS_INIT, &trans->shrd->status);
-
        return 0;
 }
 
@@ -946,13 +952,14 @@ static const u8 iwlagn_pan_ac_to_queue[] = {
  * ucode
  */
 static int iwl_load_section(struct iwl_trans *trans, const char *name,
-                               struct fw_desc *image, u32 dst_addr)
+                           const struct fw_desc *image, u32 dst_addr)
 {
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        dma_addr_t phy_addr = image->p_addr;
        u32 byte_cnt = image->len;
        int ret;
 
-       trans->ucode_write_complete = 0;
+       trans_pcie->ucode_write_complete = false;
 
        iwl_write_direct32(trans,
                FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
@@ -983,8 +990,8 @@ static int iwl_load_section(struct iwl_trans *trans, const char *name,
                FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
 
        IWL_DEBUG_FW(trans, "%s uCode section being loaded...\n", name);
-       ret = wait_event_timeout(trans->shrd->wait_command_queue,
-                                trans->ucode_write_complete, 5 * HZ);
+       ret = wait_event_timeout(trans_pcie->ucode_write_waitq,
+                                trans_pcie->ucode_write_complete, 5 * HZ);
        if (!ret) {
                IWL_ERR(trans, "Could not load the %s uCode section\n",
                        name);
@@ -994,7 +1001,8 @@ static int iwl_load_section(struct iwl_trans *trans, const char *name,
        return 0;
 }
 
-static int iwl_load_given_ucode(struct iwl_trans *trans, struct fw_img *image)
+static int iwl_load_given_ucode(struct iwl_trans *trans,
+                               const struct fw_img *image)
 {
        int ret = 0;
 
@@ -1014,13 +1022,14 @@ static int iwl_load_given_ucode(struct iwl_trans *trans, struct fw_img *image)
        return 0;
 }
 
-static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, struct fw_img *fw)
+static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
+                                  const struct fw_img *fw)
 {
        int ret;
        struct iwl_trans_pcie *trans_pcie =
                IWL_TRANS_GET_PCIE_TRANS(trans);
+       bool hw_rfkill;
 
-       trans->shrd->ucode_owner = IWL_OWNERSHIP_DRIVER;
        trans_pcie->ac_to_queue[IWL_RXON_CTX_BSS] = iwlagn_bss_ac_to_queue;
        trans_pcie->ac_to_queue[IWL_RXON_CTX_PAN] = iwlagn_pan_ac_to_queue;
 
@@ -1030,22 +1039,19 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, struct fw_img *fw)
        trans_pcie->mcast_queue[IWL_RXON_CTX_BSS] = 0;
        trans_pcie->mcast_queue[IWL_RXON_CTX_PAN] = IWL_IPAN_MCAST_QUEUE;
 
-       if ((hw_params(trans).sku & EEPROM_SKU_CAP_AMT_ENABLE) &&
-            iwl_prepare_card_hw(trans)) {
+       /* This may fail if AMT took ownership of the device */
+       if (iwl_prepare_card_hw(trans)) {
                IWL_WARN(trans, "Exit HW not ready\n");
                return -EIO;
        }
 
        /* If platform's RF_KILL switch is NOT set to KILL */
-       if (iwl_read32(trans, CSR_GP_CNTRL) &
-                       CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
-               clear_bit(STATUS_RF_KILL_HW, &trans->shrd->status);
-       else
-               set_bit(STATUS_RF_KILL_HW, &trans->shrd->status);
+       hw_rfkill = !(iwl_read32(trans, CSR_GP_CNTRL) &
+                               CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW);
+       iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
 
-       if (iwl_is_rfkill(trans->shrd)) {
-               iwl_set_hw_rfkill_state(priv(trans), true);
-               iwl_enable_interrupts(trans);
+       if (hw_rfkill) {
+               iwl_enable_rfkill_int(trans);
                return -ERFKILL;
        }
 
@@ -1071,17 +1077,20 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, struct fw_img *fw)
        iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
 
        /* Load the given image to the HW */
-       iwl_load_given_ucode(trans, fw);
-
-       return 0;
+       return iwl_load_given_ucode(trans, fw);
 }
 
 /*
  * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask
- * must be called under priv->shrd->lock and mac access
+ * must be called under the irq lock and with MAC access
  */
 static void iwl_trans_txq_set_sched(struct iwl_trans *trans, u32 mask)
 {
+       struct iwl_trans_pcie __maybe_unused *trans_pcie =
+               IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       lockdep_assert_held(&trans_pcie->irq_lock);
+
        iwl_write_prph(trans, SCD_TXFACT, mask);
 }
 
@@ -1095,7 +1104,7 @@ static void iwl_tx_start(struct iwl_trans *trans)
        int i, chan;
        u32 reg_val;
 
-       spin_lock_irqsave(&trans->shrd->lock, flags);
+       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
 
        trans_pcie->scd_base_addr =
                iwl_read_prph(trans, SCD_SRAM_BASE_ADDR);
@@ -1109,7 +1118,8 @@ static void iwl_tx_start(struct iwl_trans *trans)
                a += 4)
                iwl_write_targ_mem(trans, a, 0);
        for (; a < trans_pcie->scd_base_addr +
-              SCD_TRANS_TBL_OFFSET_QUEUE(hw_params(trans).max_txq_num);
+              SCD_TRANS_TBL_OFFSET_QUEUE(
+                               cfg(trans)->base_params->num_of_queues);
               a += 4)
                iwl_write_targ_mem(trans, a, 0);
 
@@ -1128,11 +1138,11 @@ static void iwl_tx_start(struct iwl_trans *trans)
                           reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN);
 
        iwl_write_prph(trans, SCD_QUEUECHAIN_SEL,
-               SCD_QUEUECHAIN_SEL_ALL(trans));
+               SCD_QUEUECHAIN_SEL_ALL(trans, trans_pcie));
        iwl_write_prph(trans, SCD_AGGR_SEL, 0);
 
        /* initiate the queues */
-       for (i = 0; i < hw_params(trans).max_txq_num; i++) {
+       for (i = 0; i < cfg(trans)->base_params->num_of_queues; i++) {
                iwl_write_prph(trans, SCD_QUEUE_RDPTR(i), 0);
                iwl_write_direct32(trans, HBUS_TARG_WRPTR, 0 | (i << 8));
                iwl_write_targ_mem(trans, trans_pcie->scd_base_addr +
@@ -1149,7 +1159,7 @@ static void iwl_tx_start(struct iwl_trans *trans)
        }
 
        iwl_write_prph(trans, SCD_INTERRUPT_MASK,
-                       IWL_MASK(0, hw_params(trans).max_txq_num));
+                       IWL_MASK(0, cfg(trans)->base_params->num_of_queues));
 
        /* Activate all Tx DMA/FIFO channels */
        iwl_trans_txq_set_sched(trans, IWL_MASK(0, 7));
@@ -1160,7 +1170,7 @@ static void iwl_tx_start(struct iwl_trans *trans)
        else
                queue_to_fifo = iwlagn_default_queue_to_tx_fifo;
 
-       iwl_trans_set_wr_ptrs(trans, trans->shrd->cmd_queue, 0);
+       iwl_trans_set_wr_ptrs(trans, trans_pcie->cmd_queue, 0);
 
        /* make sure all queue are not stopped */
        memset(&trans_pcie->queue_stopped[0], 0,
@@ -1191,7 +1201,7 @@ static void iwl_tx_start(struct iwl_trans *trans)
                                              fifo, 0);
        }
 
-       spin_unlock_irqrestore(&trans->shrd->lock, flags);
+       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 
        /* Enable L1-Active */
        iwl_clear_bits_prph(trans, APMG_PCIDEV_STT_REG,
@@ -1209,12 +1219,12 @@ static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans)
  */
 static int iwl_trans_tx_stop(struct iwl_trans *trans)
 {
-       int ch, txq_id;
+       int ch, txq_id, ret;
        unsigned long flags;
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 
        /* Turn off all Tx DMA fifos */
-       spin_lock_irqsave(&trans->shrd->lock, flags);
+       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
 
        iwl_trans_txq_set_sched(trans, 0);
 
@@ -1222,15 +1232,16 @@ static int iwl_trans_tx_stop(struct iwl_trans *trans)
        for (ch = 0; ch < FH_TCSR_CHNL_NUM; ch++) {
                iwl_write_direct32(trans,
                                   FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0);
-               if (iwl_poll_direct_bit(trans, FH_TSSR_TX_STATUS_REG,
+               ret = iwl_poll_direct_bit(trans, FH_TSSR_TX_STATUS_REG,
                                    FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch),
-                                   1000))
+                                   1000);
+               if (ret < 0)
                        IWL_ERR(trans, "Failing on timeout while stopping"
                            " DMA channel %d [0x%08x]", ch,
                            iwl_read_direct32(trans,
                                              FH_TSSR_TX_STATUS_REG));
        }
-       spin_unlock_irqrestore(&trans->shrd->lock, flags);
+       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 
        if (!trans_pcie->txq) {
                IWL_WARN(trans, "Stopping tx queues that aren't allocated...");
@@ -1238,7 +1249,8 @@ static int iwl_trans_tx_stop(struct iwl_trans *trans)
        }
 
        /* Unmap DMA from host system and free skb's */
-       for (txq_id = 0; txq_id < hw_params(trans).max_txq_num; txq_id++)
+       for (txq_id = 0; txq_id < cfg(trans)->base_params->num_of_queues;
+            txq_id++)
                iwl_tx_queue_unmap(trans, txq_id);
 
        return 0;
@@ -1250,9 +1262,9 @@ static void iwl_trans_pcie_stop_device(struct iwl_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);
+       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
        iwl_disable_interrupts(trans);
-       spin_unlock_irqrestore(&trans->shrd->lock, flags);
+       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 
        /* device going down, Stop using ICT table */
        iwl_disable_ict(trans);
@@ -1264,7 +1276,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
         * restart. So don't process again if the device is
         * already dead.
         */
-       if (test_bit(STATUS_DEVICE_ENABLED, &trans->shrd->status)) {
+       if (test_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status)) {
                iwl_trans_tx_stop(trans);
 #ifndef CONFIG_IWLWIFI_IDI
                iwl_trans_rx_stop(trans);
@@ -1285,18 +1297,31 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *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);
+       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
        iwl_disable_interrupts(trans);
-       spin_unlock_irqrestore(&trans->shrd->lock, flags);
+       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 
        /* wait to make sure we flush pending tasklet*/
-       synchronize_irq(trans->irq);
+       synchronize_irq(trans_pcie->irq);
        tasklet_kill(&trans_pcie->irq_tasklet);
 
+       cancel_work_sync(&trans_pcie->rx_replenish);
+
        /* stop and reset the on-board processor */
        iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
 }
 
+static void iwl_trans_pcie_wowlan_suspend(struct iwl_trans *trans)
+{
+       /* let the ucode operate on its own */
+       iwl_write32(trans, CSR_UCODE_DRV_GP1_SET,
+                   CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
+
+       iwl_disable_interrupts(trans);
+       iwl_clear_bit(trans, CSR_GP_CNTRL,
+                     CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+}
+
 static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
                struct iwl_device_cmd *dev_cmd, enum iwl_rxon_context_id ctx,
                u8 sta_id, u8 tid)
@@ -1349,6 +1374,8 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
        txq = &trans_pcie->txq[txq_id];
        q = &txq->q;
 
+       spin_lock(&txq->lock);
+
        /* In AGG mode, the index in the ring must correspond to the WiFi
         * sequence number. This is a HW requirements to help the SCD to parse
         * the BA.
@@ -1395,7 +1422,7 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
                                    &dev_cmd->hdr, firstlen,
                                    DMA_BIDIRECTIONAL);
        if (unlikely(dma_mapping_error(trans->dev, txcmd_phys)))
-               return -1;
+               goto out_err;
        dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
        dma_unmap_len_set(out_meta, len, firstlen);
 
@@ -1417,7 +1444,7 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
                                         dma_unmap_addr(out_meta, mapping),
                                         dma_unmap_len(out_meta, len),
                                         DMA_BIDIRECTIONAL);
-                       return -1;
+                       goto out_err;
                }
        }
 
@@ -1448,7 +1475,7 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
        dma_sync_single_for_device(trans->dev, txcmd_phys, firstlen,
                        DMA_BIDIRECTIONAL);
 
-       trace_iwlwifi_dev_tx(priv(trans),
+       trace_iwlwifi_dev_tx(trans->dev,
                             &((struct iwl_tfd *)txq->tfds)[txq->q.write_ptr],
                             sizeof(struct iwl_tfd),
                             &dev_cmd->hdr, firstlen,
@@ -1469,10 +1496,14 @@ 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, "Queue is full");
+                       iwl_stop_queue(trans, txq);
                }
        }
+       spin_unlock(&txq->lock);
        return 0;
+ out_err:
+       spin_unlock(&txq->lock);
+       return -1;
 }
 
 static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
@@ -1480,6 +1511,7 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
        struct iwl_trans_pcie *trans_pcie =
                IWL_TRANS_GET_PCIE_TRANS(trans);
        int err;
+       bool hw_rfkill;
 
        trans_pcie->inta_mask = CSR_INI_SET_MASK;
 
@@ -1489,11 +1521,11 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
 
                iwl_alloc_isr_ict(trans);
 
-               err = request_irq(trans->irq, iwl_isr_ict, IRQF_SHARED,
+               err = request_irq(trans_pcie->irq, iwl_isr_ict, IRQF_SHARED,
                        DRV_NAME, trans);
                if (err) {
                        IWL_ERR(trans, "Error allocating IRQ %d\n",
-                               trans->irq);
+                               trans_pcie->irq);
                        goto error;
                }
 
@@ -1509,21 +1541,14 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
 
        iwl_apm_init(trans);
 
-       /* If platform's RF_KILL switch is NOT set to KILL */
-       if (iwl_read32(trans,
-                       CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
-               clear_bit(STATUS_RF_KILL_HW, &trans->shrd->status);
-       else
-               set_bit(STATUS_RF_KILL_HW, &trans->shrd->status);
-
-       iwl_set_hw_rfkill_state(priv(trans),
-                               test_bit(STATUS_RF_KILL_HW,
-                                        &trans->shrd->status));
+       hw_rfkill = !(iwl_read32(trans, CSR_GP_CNTRL) &
+                               CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW);
+       iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
 
        return err;
 
 err_free_irq:
-       free_irq(trans->irq, trans);
+       free_irq(trans_pcie->irq, trans);
 error:
        iwl_free_isr_ict(trans);
        tasklet_kill(&trans_pcie->irq_tasklet);
@@ -1537,13 +1562,11 @@ static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans)
        iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
 
        /* Even if we stop the HW, we still want the RF kill interrupt */
-       IWL_DEBUG_ISR(trans, "Enabling rfkill interrupt\n");
-       iwl_write32(trans, CSR_INT_MASK, CSR_INT_BIT_RF_KILL);
+       iwl_enable_rfkill_int(trans);
 }
 
 static int iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid,
-                     int txq_id, int ssn, u32 status,
-                     struct sk_buff_head *skbs)
+                     int txq_id, int ssn, struct sk_buff_head *skbs)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
@@ -1551,6 +1574,8 @@ static int iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid,
        int tfd_num = ssn & (txq->q.n_bd - 1);
        int freed = 0;
 
+       spin_lock(&txq->lock);
+
        txq->time_stamp = jiffies;
 
        if (unlikely(txq_id >= IWLAGN_FIRST_AMPDU_QUEUE &&
@@ -1565,6 +1590,7 @@ static int iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid,
                IWL_DEBUG_TX_QUEUES(trans, "Bad queue mapping txq_id %d, "
                        "agg_txq[sta_id[tid] %d", txq_id,
                        trans_pcie->agg_txq[sta_id][tid]);
+               spin_unlock(&txq->lock);
                return 1;
        }
 
@@ -1573,28 +1599,35 @@ static int iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid,
                                txq_id, iwl_get_queue_ac(txq), txq->q.read_ptr,
                                tfd_num, ssn);
                freed = iwl_tx_queue_reclaim(trans, txq_id, tfd_num, skbs);
-               if (iwl_queue_space(&txq->q) > txq->q.low_mark &&
-                  (!txq->sched_retry ||
-                  status != TX_STATUS_FAIL_PASSIVE_NO_RX))
-                       iwl_wake_queue(trans, txq, "Packets reclaimed");
+               if (iwl_queue_space(&txq->q) > txq->q.low_mark)
+                       iwl_wake_queue(trans, txq);
        }
+
+       spin_unlock(&txq->lock);
        return 0;
 }
 
 static void iwl_trans_pcie_write8(struct iwl_trans *trans, u32 ofs, u8 val)
 {
-       iowrite8(val, IWL_TRANS_GET_PCIE_TRANS(trans)->hw_base + ofs);
+       writeb(val, IWL_TRANS_GET_PCIE_TRANS(trans)->hw_base + ofs);
 }
 
 static void iwl_trans_pcie_write32(struct iwl_trans *trans, u32 ofs, u32 val)
 {
-       iowrite32(val, IWL_TRANS_GET_PCIE_TRANS(trans)->hw_base + ofs);
+       writel(val, IWL_TRANS_GET_PCIE_TRANS(trans)->hw_base + ofs);
 }
 
 static u32 iwl_trans_pcie_read32(struct iwl_trans *trans, u32 ofs)
 {
-       u32 val = ioread32(IWL_TRANS_GET_PCIE_TRANS(trans)->hw_base + ofs);
-       return val;
+       return readl(IWL_TRANS_GET_PCIE_TRANS(trans)->hw_base + ofs);
+}
+
+static void iwl_trans_pcie_configure(struct iwl_trans *trans,
+                             const struct iwl_trans_config *trans_cfg)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       trans_pcie->cmd_queue = trans_cfg->cmd_queue;
 }
 
 static void iwl_trans_pcie_free(struct iwl_trans *trans)
@@ -1602,18 +1635,17 @@ static void iwl_trans_pcie_free(struct iwl_trans *trans)
        struct iwl_trans_pcie *trans_pcie =
                IWL_TRANS_GET_PCIE_TRANS(trans);
 
-       iwl_calib_free_results(trans);
        iwl_trans_pcie_tx_free(trans);
 #ifndef CONFIG_IWLWIFI_IDI
        iwl_trans_pcie_rx_free(trans);
 #endif
        if (trans_pcie->irq_requested == true) {
-               free_irq(trans->irq, trans);
+               free_irq(trans_pcie->irq, trans);
                iwl_free_isr_ict(trans);
        }
 
        pci_disable_msi(trans_pcie->pci_dev);
-       pci_iounmap(trans_pcie->pci_dev, trans_pcie->hw_base);
+       iounmap(trans_pcie->hw_base);
        pci_release_regions(trans_pcie->pci_dev);
        pci_disable_device(trans_pcie->pci_dev);
 
@@ -1624,75 +1656,27 @@ static void iwl_trans_pcie_free(struct iwl_trans *trans)
 #ifdef CONFIG_PM_SLEEP
 static int iwl_trans_pcie_suspend(struct iwl_trans *trans)
 {
-       /*
-        * This function is called when system goes into suspend state
-        * mac80211 will call iwlagn_mac_stop() from the mac80211 suspend
-        * function first but since iwlagn_mac_stop() has no knowledge of
-        * who the caller is,
-        * it will not call apm_ops.stop() to stop the DMA operation.
-        * Calling apm_ops.stop here to make sure we stop the DMA.
-        *
-        * But of course ... if we have configured WoWLAN then we did other
-        * things already :-)
-        */
-       if (!trans->shrd->wowlan) {
-               iwl_apm_stop(trans);
-       } else {
-               iwl_disable_interrupts(trans);
-               iwl_clear_bit(trans, CSR_GP_CNTRL,
-                             CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-       }
-
        return 0;
 }
 
 static int iwl_trans_pcie_resume(struct iwl_trans *trans)
 {
-       bool hw_rfkill = false;
-
-       iwl_enable_interrupts(trans);
+       bool hw_rfkill;
 
-       if (!(iwl_read32(trans, CSR_GP_CNTRL) &
-                               CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
-               hw_rfkill = true;
+       hw_rfkill = !(iwl_read32(trans, CSR_GP_CNTRL) &
+                               CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW);
 
        if (hw_rfkill)
-               set_bit(STATUS_RF_KILL_HW, &trans->shrd->status);
+               iwl_enable_rfkill_int(trans);
        else
-               clear_bit(STATUS_RF_KILL_HW, &trans->shrd->status);
+               iwl_enable_interrupts(trans);
 
-       iwl_set_hw_rfkill_state(priv(trans), hw_rfkill);
+       iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
 
        return 0;
 }
 #endif /* CONFIG_PM_SLEEP */
 
-static void iwl_trans_pcie_wake_any_queue(struct iwl_trans *trans,
-                                         enum iwl_rxon_context_id ctx,
-                                         const char *msg)
-{
-       u8 ac, txq_id;
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       for (ac = 0; ac < AC_NUM; ac++) {
-               txq_id = trans_pcie->ac_to_queue[ctx][ac];
-               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], msg);
-       }
-}
-
-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], msg);
-}
-
 #define IWL_FLUSH_WAIT_MS      2000
 
 static int iwl_trans_pcie_wait_tx_queue_empty(struct iwl_trans *trans)
@@ -1705,8 +1689,8 @@ static int iwl_trans_pcie_wait_tx_queue_empty(struct iwl_trans *trans)
        int ret = 0;
 
        /* waiting for all the tx frames complete might take a while */
-       for (cnt = 0; cnt < hw_params(trans).max_txq_num; cnt++) {
-               if (cnt == trans->shrd->cmd_queue)
+       for (cnt = 0; cnt < cfg(trans)->base_params->num_of_queues; cnt++) {
+               if (cnt == trans_pcie->cmd_queue)
                        continue;
                txq = &trans_pcie->txq[cnt];
                q = &txq->q;
@@ -1951,7 +1935,9 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file,
        int pos = 0;
        int cnt;
        int ret;
-       const size_t bufsz = sizeof(char) * 64 * hw_params(trans).max_txq_num;
+       size_t bufsz;
+
+       bufsz = sizeof(char) * 64 * cfg(trans)->base_params->num_of_queues;
 
        if (!trans_pcie->txq) {
                IWL_ERR(trans, "txq not ready\n");
@@ -1961,7 +1947,7 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file,
        if (!buf)
                return -ENOMEM;
 
-       for (cnt = 0; cnt < hw_params(trans).max_txq_num; cnt++) {
+       for (cnt = 0; cnt < cfg(trans)->base_params->num_of_queues; cnt++) {
                txq = &trans_pcie->txq[cnt];
                q = &txq->q;
                pos += scnprintf(buf + pos, bufsz - pos,
@@ -2210,7 +2196,7 @@ const struct iwl_trans_ops trans_ops_pcie = {
        .start_fw = iwl_trans_pcie_start_fw,
        .stop_device = iwl_trans_pcie_stop_device,
 
-       .wake_any_queue = iwl_trans_pcie_wake_any_queue,
+       .wowlan_suspend = iwl_trans_pcie_wowlan_suspend,
 
        .send_cmd = iwl_trans_pcie_send_cmd,
 
@@ -2222,7 +2208,6 @@ const struct iwl_trans_ops trans_ops_pcie = {
        .tx_agg_setup = iwl_trans_pcie_tx_agg_setup,
 
        .free = iwl_trans_pcie_free,
-       .stop_queue = iwl_trans_pcie_stop_queue,
 
        .dbgfs_register = iwl_trans_pcie_dbgfs_register,
 
@@ -2236,6 +2221,7 @@ const struct iwl_trans_ops trans_ops_pcie = {
        .write8 = iwl_trans_pcie_write8,
        .write32 = iwl_trans_pcie_write32,
        .read32 = iwl_trans_pcie_read32,
+       .configure = iwl_trans_pcie_configure,
 };
 
 struct iwl_trans *iwl_trans_pcie_alloc(struct iwl_shared *shrd,
@@ -2258,7 +2244,8 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct iwl_shared *shrd,
        trans->ops = &trans_ops_pcie;
        trans->shrd = shrd;
        trans_pcie->trans = trans;
-       spin_lock_init(&trans->hcmd_lock);
+       spin_lock_init(&trans_pcie->irq_lock);
+       init_waitqueue_head(&trans_pcie->ucode_write_waitq);
 
        /* W/A - seems to solve weird behavior. We need to remove this if we
         * don't want to stay in L1 all the time. This wastes a lot of power */
@@ -2294,9 +2281,9 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct iwl_shared *shrd,
                goto out_pci_disable_device;
        }
 
-       trans_pcie->hw_base = pci_iomap(pdev, 0, 0);
+       trans_pcie->hw_base = pci_ioremap_bar(pdev, 0);
        if (!trans_pcie->hw_base) {
-               dev_printk(KERN_ERR, &pdev->dev, "pci_iomap failed");
+               dev_printk(KERN_ERR, &pdev->dev, "pci_ioremap_bar failed");
                err = -ENODEV;
                goto out_pci_release_regions;
        }
@@ -2320,7 +2307,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct iwl_shared *shrd,
                        "pci_enable_msi failed(0X%x)", err);
 
        trans->dev = &pdev->dev;
-       trans->irq = pdev->irq;
+       trans_pcie->irq = pdev->irq;
        trans_pcie->pci_dev = pdev;
        trans->hw_rev = iwl_read32(trans, CSR_HW_REV);
        trans->hw_id = (pdev->device << 16) + pdev->subsystem_device;
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.c b/drivers/net/wireless/iwlwifi/iwl-trans.c
deleted file mode 100644 (file)
index 506c062..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/******************************************************************************
- *
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
- *
- * 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.GPL.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- * BSD LICENSE
- *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *  * Neither the name Intel Corporation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *****************************************************************************/
-
-#include "iwl-trans.h"
-
-int iwl_trans_send_cmd_pdu(struct iwl_trans *trans, u8 id,
-                          u32 flags, u16 len, const void *data)
-{
-       struct iwl_host_cmd cmd = {
-               .id = id,
-               .len = { len, },
-               .data = { data, },
-               .flags = flags,
-       };
-
-       return iwl_trans_send_cmd(trans, &cmd);
-}
index ae68c51e532730a3eaa1472c5e5b1407eec25e3d..7d1990c7f65842d387ad64377ba6111db1dac014 100644 (file)
 #ifndef __iwl_trans_h__
 #define __iwl_trans_h__
 
-#include <linux/debugfs.h>
-#include <linux/skbuff.h>
+#include <linux/ieee80211.h>
+#include <linux/mm.h> /* for page_address */
 
 #include "iwl-shared.h"
-#include "iwl-commands.h"
+#include "iwl-debug.h"
 
- /*This file includes the declaration that are exported from the transport
- * layer */
+/**
+ * DOC: Transport layer - what is it ?
+ *
+ * The tranport layer is the layer that deals with the HW directly. It provides
+ * an abstraction of the underlying HW to the upper layer. The transport layer
+ * doesn't provide any policy, algorithm or anything of this kind, but only
+ * mechanisms to make the HW do something.It is not completely stateless but
+ * close to it.
+ * We will have an implementation for each different supported bus.
+ */
+
+/**
+ * DOC: Life cycle of the transport layer
+ *
+ * The transport layer has a very precise life cycle.
+ *
+ *     1) A helper function is called during the module initialization and
+ *        registers the bus driver's ops with the transport's alloc function.
+ *     2) Bus's probe calls to the transport layer's allocation functions.
+ *        Of course this function is bus specific.
+ *     3) This allocation functions will spawn the upper layer which will
+ *        register mac80211.
+ *
+ *     4) At some point (i.e. mac80211's start call), the op_mode will call
+ *        the following sequence:
+ *        start_hw
+ *        start_fw
+ *
+ *     5) Then when finished (or reset):
+ *        stop_fw (a.k.a. stop device for the moment)
+ *        stop_hw
+ *
+ *     6) Eventually, the free function will be called.
+ */
 
 struct iwl_priv;
 struct iwl_shared;
+struct iwl_op_mode;
+struct fw_img;
+struct sk_buff;
+struct dentry;
 
+/**
+ * DOC: Host command section
+ *
+ * A host command is a commaned issued by the upper layer to the fw. There are
+ * several versions of fw that have several APIs. The transport layer is
+ * completely agnostic to these differences.
+ * The transport does provide helper functionnality (i.e. SYNC / ASYNC mode),
+ */
 #define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
 #define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ)
 #define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4)
+#define SEQ_TO_QUEUE(s)        (((s) >> 8) & 0x1f)
+#define QUEUE_TO_SEQ(q)        (((q) & 0x1f) << 8)
+#define SEQ_TO_INDEX(s)        ((s) & 0xff)
+#define INDEX_TO_SEQ(i)        ((i) & 0xff)
+#define SEQ_RX_FRAME   cpu_to_le16(0x8000)
+
+/**
+ * struct iwl_cmd_header
+ *
+ * This header format appears in the beginning of each command sent from the
+ * driver, and each response/notification received from uCode.
+ */
+struct iwl_cmd_header {
+       u8 cmd;         /* Command ID:  REPLY_RXON, etc. */
+       u8 flags;       /* 0:5 reserved, 6 abort, 7 internal */
+       /*
+        * The driver sets up the sequence number to values of its choosing.
+        * uCode does not use this value, but passes it back to the driver
+        * when sending the response to each driver-originated command, so
+        * the driver can match the response to the command.  Since the values
+        * don't get used by uCode, the driver may set up an arbitrary format.
+        *
+        * There is one exception:  uCode sets bit 15 when it originates
+        * the response/notification, i.e. when the response/notification
+        * is not a direct response to a command sent by the driver.  For
+        * example, uCode issues REPLY_RX when it sends a received frame
+        * to the driver; it is not a direct response to any driver command.
+        *
+        * The Linux driver uses the following format:
+        *
+        *  0:7         tfd index - position within TX queue
+        *  8:12        TX queue id
+        *  13:14       reserved
+        *  15          unsolicited RX or uCode-originated notification
+        */
+       __le16 sequence;
+} __packed;
+
+
+#define FH_RSCSR_FRAME_SIZE_MSK                0x00003FFF      /* bits 0-13 */
+
+struct iwl_rx_packet {
+       /*
+        * The first 4 bytes of the RX frame header contain both the RX frame
+        * size and some flags.
+        * Bit fields:
+        * 31:    flag flush RB request
+        * 30:    flag ignore TC (terminal counter) request
+        * 29:    flag fast IRQ request
+        * 28-14: Reserved
+        * 13-00: RX frame size
+        */
+       __le32 len_n_flags;
+       struct iwl_cmd_header hdr;
+       u8 data[];
+} __packed;
 
-enum {
+/**
+ * enum CMD_MODE - how to send the host commands ?
+ *
+ * @CMD_SYNC: The caller will be stalled until the fw responds to the command
+ * @CMD_ASYNC: Return right away and don't want for the response
+ * @CMD_WANT_SKB: valid only with CMD_SYNC. The caller needs the buffer of the
+ *     response.
+ * @CMD_ON_DEMAND: This command is sent by the test mode pipe.
+ */
+enum CMD_MODE {
        CMD_SYNC = 0,
        CMD_ASYNC = BIT(0),
        CMD_WANT_SKB = BIT(1),
@@ -104,25 +213,38 @@ struct iwl_device_cmd {
 
 #define IWL_MAX_CMD_TFDS       2
 
+/**
+ * struct iwl_hcmd_dataflag - flag for each one of the chunks of the command
+ *
+ * IWL_HCMD_DFL_NOCOPY: By default, the command is copied to the host command's
+ *     ring. The transport layer doesn't map the command's buffer to DMA, but
+ *     rather copies it to an previously allocated DMA buffer. This flag tells
+ *     the transport layer not to copy the command, but to map the existing
+ *     buffer. This can save memcpy and is worth with very big comamnds.
+ */
 enum iwl_hcmd_dataflag {
        IWL_HCMD_DFL_NOCOPY     = BIT(0),
 };
 
 /**
  * struct iwl_host_cmd - Host command to the uCode
+ *
  * @data: array of chunks that composes the data of the host command
- * @reply_page: pointer to the page that holds the response to the host command
+ * @resp_pkt: response packet, if %CMD_WANT_SKB was set
+ * @_rx_page_order: (internally used to free response packet)
+ * @_rx_page_addr: (internally used to free response packet)
  * @handler_status: return value of the handler of the command
  *     (put in setup_rx_handlers) - valid for SYNC mode only
- * @callback:
- * @flags: can be CMD_* note CMD_WANT_SKB is incompatible withe CMD_ASYNC
+ * @flags: can be CMD_*
  * @len: array of the lenths of the chunks in data
- * @dataflags:
+ * @dataflags: IWL_HCMD_DFL_*
  * @id: id of the host command
  */
 struct iwl_host_cmd {
        const void *data[IWL_MAX_CMD_TFDS];
-       unsigned long reply_page;
+       struct iwl_rx_packet *resp_pkt;
+       unsigned long _rx_page_addr;
+       u32 _rx_page_order;
        int handler_status;
 
        u32 flags;
@@ -131,40 +253,80 @@ struct iwl_host_cmd {
        u8 id;
 };
 
-/* 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 */
+static inline void iwl_free_resp(struct iwl_host_cmd *cmd)
+{
+       free_pages(cmd->_rx_page_addr, cmd->_rx_page_order);
+}
+
+struct iwl_rx_cmd_buffer {
+       struct page *_page;
 };
 
-struct fw_img {
-       struct fw_desc code;    /* firmware code image */
-       struct fw_desc data;    /* firmware data image */
+static inline void *rxb_addr(struct iwl_rx_cmd_buffer *r)
+{
+       return page_address(r->_page);
+}
+
+static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r)
+{
+       struct page *p = r->_page;
+       r->_page = NULL;
+       return p;
+}
+
+/**
+ * struct iwl_trans_config - transport configuration
+ *
+ * @op_mode: pointer to the upper layer.
+ *     Must be set before any other call.
+ * @cmd_queue: the index of the command queue.
+ *     Must be set before start_fw.
+ */
+struct iwl_trans_config {
+       struct iwl_op_mode *op_mode;
+       u8 cmd_queue;
 };
 
 /**
  * struct iwl_trans_ops - transport specific operations
+ *
+ * All the handlers MUST be implemented
+ *
  * @start_hw: starts the HW- from that point on, the HW can send interrupts
+ *     May sleep
  * @stop_hw: stops the HW- from that point on, the HW will be in low power but
  *     will still issue interrupt if the HW RF kill is triggered.
+ *     May sleep
  * @start_fw: allocates and inits all the resources for the transport
- *     layer. Also kick a fw image. This handler may sleep.
+ *     layer. Also kick a fw image.
+ *     May sleep
  * @fw_alive: called when the fw sends alive notification
- * @wake_any_queue: wake all the queues of a specfic context IWL_RXON_CTX_*
+ *     May sleep
  * @stop_device:stops the whole device (embedded CPU put to reset)
+ *     May sleep
+ * @wowlan_suspend: put the device into the correct mode for WoWLAN during
+ *     suspend. This is optional, if not implemented WoWLAN will not be
+ *     supported. This callback may sleep.
  * @send_cmd:send a host command
+ *     May sleep only if CMD_SYNC is set
  * @tx: send an skb
+ *     Must be atomic
  * @reclaim: free packet until ssn. Returns a list of freed packets.
+ *     Must be atomic
  * @tx_agg_alloc: allocate resources for a TX BA session
+ *     Must be atomic
  * @tx_agg_setup: setup a tx queue for AMPDU - will be called once the HW is
- *                 ready and a successful ADDBA response has been received.
+ *     ready and a successful ADDBA response has been received.
+ *     May sleep
  * @tx_agg_disable: de-configure a Tx queue to send AMPDUs
+ *     Must be atomic
  * @free: release all the ressource for the transport layer itself such as
- *        irq, tasklet etc...
- * @stop_queue: stop a specific queue
+ *     irq, tasklet etc... From this point on, the device may not issue
+ *     any interrupt (incl. RFKILL).
+ *     May sleep
  * @check_stuck_queue: check if a specific queue is stuck
  * @wait_tx_queue_empty: wait until all tx queues are empty
+ *     May sleep
  * @dbgfs_register: add the dbgfs files under this directory. Files will be
  *     automatically deleted.
  * @suspend: stop the device unless WoWLAN is configured
@@ -172,18 +334,19 @@ struct fw_img {
  * @write8: write a u8 to a register at offset ofs from the BAR
  * @write32: write a u32 to a register at offset ofs from the BAR
  * @read32: read a u32 register at offset ofs from the BAR
+ * @configure: configure parameters required by the transport layer from
+ *     the op_mode. May be called several times before start_fw, can't be
+ *     called after that.
  */
 struct iwl_trans_ops {
 
        int (*start_hw)(struct iwl_trans *iwl_trans);
        void (*stop_hw)(struct iwl_trans *iwl_trans);
-       int (*start_fw)(struct iwl_trans *trans, struct fw_img *fw);
+       int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw);
        void (*fw_alive)(struct iwl_trans *trans);
        void (*stop_device)(struct iwl_trans *trans);
 
-       void (*wake_any_queue)(struct iwl_trans *trans,
-                              enum iwl_rxon_context_id ctx,
-                              const char *msg);
+       void (*wowlan_suspend)(struct iwl_trans *trans);
 
        int (*send_cmd)(struct iwl_trans *trans, struct iwl_host_cmd *cmd);
 
@@ -191,8 +354,7 @@ struct iwl_trans_ops {
                struct iwl_device_cmd *dev_cmd, enum iwl_rxon_context_id ctx,
                u8 sta_id, u8 tid);
        int (*reclaim)(struct iwl_trans *trans, int sta_id, int tid,
-                       int txq_id, int ssn, u32 status,
-                       struct sk_buff_head *skbs);
+                       int txq_id, int ssn, struct sk_buff_head *skbs);
 
        int (*tx_agg_disable)(struct iwl_trans *trans,
                              int sta_id, int tid);
@@ -204,8 +366,6 @@ struct iwl_trans_ops {
 
        void (*free)(struct iwl_trans *trans);
 
-       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);
        int (*wait_tx_queue_empty)(struct iwl_trans *trans);
@@ -216,80 +376,94 @@ struct iwl_trans_ops {
        void (*write8)(struct iwl_trans *trans, u32 ofs, u8 val);
        void (*write32)(struct iwl_trans *trans, u32 ofs, u32 val);
        u32 (*read32)(struct iwl_trans *trans, u32 ofs);
+       void (*configure)(struct iwl_trans *trans,
+                         const struct iwl_trans_config *trans_cfg);
 };
 
-/* Opaque calibration results */
-struct iwl_calib_result {
-       struct list_head list;
-       size_t cmd_len;
-       struct iwl_calib_hdr hdr;
-       /* data follows */
+/**
+ * enum iwl_trans_state - state of the transport layer
+ *
+ * @IWL_TRANS_NO_FW: no fw has sent an alive response
+ * @IWL_TRANS_FW_ALIVE: a fw has sent an alive response
+ */
+enum iwl_trans_state {
+       IWL_TRANS_NO_FW = 0,
+       IWL_TRANS_FW_ALIVE      = 1,
 };
 
 /**
  * struct iwl_trans - transport common data
+ *
  * @ops - pointer to iwl_trans_ops
+ * @op_mode - pointer to the op_mode
  * @shrd - pointer to iwl_shared which holds shared data from the upper layer
- * @hcmd_lock: protects HCMD
  * @reg_lock - protect hw register access
  * @dev - pointer to struct device * that represents the device
- * @irq - the irq number for the device
  * @hw_id: a u32 with the ID of the device / subdevice.
 *    Set during transport alloaction.
*     Set during transport allocation.
  * @hw_id_str: a string with info about HW ID. Set during transport allocation.
- * @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)
  * @nvm_device_type: indicates OTP or eeprom
  * @pm_support: set to true in start_hw if link pm is supported
- * @calib_results: list head for init calibration results
  */
 struct iwl_trans {
        const struct iwl_trans_ops *ops;
+       struct iwl_op_mode *op_mode;
        struct iwl_shared *shrd;
-       spinlock_t hcmd_lock;
+       enum iwl_trans_state state;
        spinlock_t reg_lock;
 
        struct device *dev;
-       unsigned int irq;
        u32 hw_rev;
        u32 hw_id;
        char hw_id_str[52];
 
-       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;
        bool pm_support;
 
-       /* init calibration results */
-       struct list_head calib_results;
-
        /* pointer to trans specific struct */
        /*Ensure that this pointer will always be aligned to sizeof pointer */
-       char trans_specific[0] __attribute__((__aligned__(sizeof(void *))));
+       char trans_specific[0] __aligned(sizeof(void *));
 };
 
+static inline void iwl_trans_configure(struct iwl_trans *trans,
+                                      const struct iwl_trans_config *trans_cfg)
+{
+       /*
+        * only set the op_mode for the moment. Later on, this function will do
+        * more
+        */
+       trans->op_mode = trans_cfg->op_mode;
+
+       trans->ops->configure(trans, trans_cfg);
+}
+
 static inline int iwl_trans_start_hw(struct iwl_trans *trans)
 {
+       might_sleep();
+
        return trans->ops->start_hw(trans);
 }
 
 static inline void iwl_trans_stop_hw(struct iwl_trans *trans)
 {
+       might_sleep();
+
        trans->ops->stop_hw(trans);
+
+       trans->state = IWL_TRANS_NO_FW;
 }
 
 static inline void iwl_trans_fw_alive(struct iwl_trans *trans)
 {
+       might_sleep();
+
        trans->ops->fw_alive(trans);
+
+       trans->state = IWL_TRANS_FW_ALIVE;
 }
 
-static inline int iwl_trans_start_fw(struct iwl_trans *trans, struct fw_img *fw)
+static inline int iwl_trans_start_fw(struct iwl_trans *trans,
+                                    const struct fw_img *fw)
 {
        might_sleep();
 
@@ -298,50 +472,63 @@ static inline int iwl_trans_start_fw(struct iwl_trans *trans, struct fw_img *fw)
 
 static inline void iwl_trans_stop_device(struct iwl_trans *trans)
 {
+       might_sleep();
+
        trans->ops->stop_device(trans);
+
+       trans->state = IWL_TRANS_NO_FW;
 }
 
-static inline void iwl_trans_wake_any_queue(struct iwl_trans *trans,
-                                           enum iwl_rxon_context_id ctx,
-                                           const char *msg)
+static inline void iwl_trans_wowlan_suspend(struct iwl_trans *trans)
 {
-       trans->ops->wake_any_queue(trans, ctx, msg);
+       might_sleep();
+       trans->ops->wowlan_suspend(trans);
 }
 
-
 static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
                                struct iwl_host_cmd *cmd)
 {
+       if (trans->state != IWL_TRANS_FW_ALIVE)
+               IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
+
        return trans->ops->send_cmd(trans, cmd);
 }
 
-int iwl_trans_send_cmd_pdu(struct iwl_trans *trans, u8 id,
-                          u32 flags, u16 len, const void *data);
-
 static inline int iwl_trans_tx(struct iwl_trans *trans, struct sk_buff *skb,
                struct iwl_device_cmd *dev_cmd, enum iwl_rxon_context_id ctx,
                u8 sta_id, u8 tid)
 {
+       if (trans->state != IWL_TRANS_FW_ALIVE)
+               IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
+
        return trans->ops->tx(trans, skb, dev_cmd, ctx, sta_id, tid);
 }
 
 static inline int iwl_trans_reclaim(struct iwl_trans *trans, int sta_id,
-                                int tid, int txq_id, int ssn, u32 status,
+                                int tid, int txq_id, int ssn,
                                 struct sk_buff_head *skbs)
 {
-       return trans->ops->reclaim(trans, sta_id, tid, txq_id, ssn,
-                                  status, skbs);
+       if (trans->state != IWL_TRANS_FW_ALIVE)
+               IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
+
+       return trans->ops->reclaim(trans, sta_id, tid, txq_id, ssn, skbs);
 }
 
 static inline int iwl_trans_tx_agg_disable(struct iwl_trans *trans,
                                            int sta_id, int tid)
 {
+       if (trans->state != IWL_TRANS_FW_ALIVE)
+               IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
+
        return trans->ops->tx_agg_disable(trans, sta_id, tid);
 }
 
 static inline int iwl_trans_tx_agg_alloc(struct iwl_trans *trans,
                                         int sta_id, int tid)
 {
+       if (trans->state != IWL_TRANS_FW_ALIVE)
+               IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
+
        return trans->ops->tx_agg_alloc(trans, sta_id, tid);
 }
 
@@ -351,6 +538,11 @@ static inline void iwl_trans_tx_agg_setup(struct iwl_trans *trans,
                                           int sta_id, int tid,
                                           int frame_limit, u16 ssn)
 {
+       might_sleep();
+
+       if (trans->state != IWL_TRANS_FW_ALIVE)
+               IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
+
        trans->ops->tx_agg_setup(trans, ctx, sta_id, tid, frame_limit, ssn);
 }
 
@@ -359,19 +551,19 @@ 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,
-                                       const char *msg)
-{
-       trans->ops->stop_queue(trans, q, msg);
-}
-
 static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans)
 {
+       if (trans->state != IWL_TRANS_FW_ALIVE)
+               IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
+
        return trans->ops->wait_tx_queue_empty(trans);
 }
 
 static inline int iwl_trans_check_stuck_queue(struct iwl_trans *trans, int q)
 {
+       if (trans->state != IWL_TRANS_FW_ALIVE)
+               IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
+
        return trans->ops->check_stuck_queue(trans, q);
 }
 static inline int iwl_trans_dbgfs_register(struct iwl_trans *trans,
@@ -407,16 +599,6 @@ static inline u32 iwl_trans_read32(struct iwl_trans *trans, u32 ofs)
        return trans->ops->read32(trans, ofs);
 }
 
-/*****************************************************
-* Utils functions
-******************************************************/
-void iwl_dealloc_ucode(struct iwl_trans *trans);
-
-int iwl_send_calib_results(struct iwl_trans *trans);
-int iwl_calib_set(struct iwl_trans *trans,
-                 const struct iwl_calib_hdr *cmd, int len);
-void iwl_calib_free_results(struct iwl_trans *trans);
-
 /*****************************************************
 * Transport layers implementations + their allocation function
 ******************************************************/
@@ -426,6 +608,8 @@ extern const struct iwl_trans_ops trans_ops_pcie;
 struct iwl_trans *iwl_trans_pcie_alloc(struct iwl_shared *shrd,
                                       struct pci_dev *pdev,
                                       const struct pci_device_id *ent);
+int __must_check iwl_pci_register_driver(void);
+void iwl_pci_unregister_driver(void);
 
 extern const struct iwl_trans_ops trans_ops_idi;
 struct iwl_trans *iwl_trans_idi_alloc(struct iwl_shared *shrd,
index 11b659ab261d5bbb4cecc4e9fe3bf9950cfe7d41..d97cf44b75baa2037e22abaa48be19b71218397c 100644 (file)
  *****************************************************************************/
 
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/dma-mapping.h>
-#include <linux/firmware.h>
 
-#include "iwl-ucode.h"
-#include "iwl-wifi.h"
 #include "iwl-dev.h"
 #include "iwl-core.h"
 #include "iwl-io.h"
@@ -44,6 +38,7 @@
 #include "iwl-agn-calib.h"
 #include "iwl-trans.h"
 #include "iwl-fh.h"
+#include "iwl-op-mode.h"
 
 static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = {
        {COEX_CU_UNASSOC_IDLE_RP, COEX_CU_UNASSOC_IDLE_WP,
@@ -82,56 +77,16 @@ static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = {
  *
  ******************************************************************************/
 
-static void iwl_free_fw_desc(struct iwl_trans *trans, struct fw_desc *desc)
-{
-       if (desc->v_addr)
-               dma_free_coherent(trans->dev, desc->len,
-                                 desc->v_addr, desc->p_addr);
-       desc->v_addr = NULL;
-       desc->len = 0;
-}
-
-static void iwl_free_fw_img(struct iwl_trans *trans, struct fw_img *img)
-{
-       iwl_free_fw_desc(trans, &img->code);
-       iwl_free_fw_desc(trans, &img->data);
-}
-
-void iwl_dealloc_ucode(struct iwl_trans *trans)
-{
-       iwl_free_fw_img(trans, &trans->ucode_rt);
-       iwl_free_fw_img(trans, &trans->ucode_init);
-       iwl_free_fw_img(trans, &trans->ucode_wowlan);
-}
-
-static int iwl_alloc_fw_desc(struct iwl_trans *trans, struct fw_desc *desc,
-                     const void *data, size_t len)
-{
-       if (!len) {
-               desc->v_addr = NULL;
-               return -EINVAL;
-       }
-
-       desc->v_addr = dma_alloc_coherent(trans->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 inline struct fw_img *iwl_get_ucode_image(struct iwl_trans *trans,
-                                       enum iwl_ucode_type ucode_type)
+static inline const struct fw_img *
+iwl_get_ucode_image(struct iwl_priv *priv, enum iwl_ucode_type ucode_type)
 {
        switch (ucode_type) {
        case IWL_UCODE_INIT:
-               return &trans->ucode_init;
+               return &priv->fw->ucode_init;
        case IWL_UCODE_WOWLAN:
-               return &trans->ucode_wowlan;
+               return &priv->fw->ucode_wowlan;
        case IWL_UCODE_REGULAR:
-               return &trans->ucode_rt;
+               return &priv->fw->ucode_rt;
        case IWL_UCODE_NONE:
                break;
        }
@@ -141,23 +96,23 @@ static inline struct fw_img *iwl_get_ucode_image(struct iwl_trans *trans,
 /*
  *  Calibration
  */
-static int iwl_set_Xtal_calib(struct iwl_trans *trans)
+static int iwl_set_Xtal_calib(struct iwl_priv *priv)
 {
        struct iwl_calib_xtal_freq_cmd cmd;
        __le16 *xtal_calib =
-               (__le16 *)iwl_eeprom_query_addr(trans->shrd, EEPROM_XTAL);
+               (__le16 *)iwl_eeprom_query_addr(priv->shrd, EEPROM_XTAL);
 
        iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD);
        cmd.cap_pin1 = le16_to_cpu(xtal_calib[0]);
        cmd.cap_pin2 = le16_to_cpu(xtal_calib[1]);
-       return iwl_calib_set(trans, (void *)&cmd, sizeof(cmd));
+       return iwl_calib_set(priv, (void *)&cmd, sizeof(cmd));
 }
 
-static int iwl_set_temperature_offset_calib(struct iwl_trans *trans)
+static int iwl_set_temperature_offset_calib(struct iwl_priv *priv)
 {
        struct iwl_calib_temperature_offset_cmd cmd;
        __le16 *offset_calib =
-               (__le16 *)iwl_eeprom_query_addr(trans->shrd,
+               (__le16 *)iwl_eeprom_query_addr(priv->shrd,
                                                EEPROM_RAW_TEMPERATURE);
 
        memset(&cmd, 0, sizeof(cmd));
@@ -166,48 +121,48 @@ static int iwl_set_temperature_offset_calib(struct iwl_trans *trans)
        if (!(cmd.radio_sensor_offset))
                cmd.radio_sensor_offset = DEFAULT_RADIO_SENSOR_OFFSET;
 
-       IWL_DEBUG_CALIB(trans, "Radio sensor offset: %d\n",
+       IWL_DEBUG_CALIB(priv, "Radio sensor offset: %d\n",
                        le16_to_cpu(cmd.radio_sensor_offset));
-       return iwl_calib_set(trans, (void *)&cmd, sizeof(cmd));
+       return iwl_calib_set(priv, (void *)&cmd, sizeof(cmd));
 }
 
-static int iwl_set_temperature_offset_calib_v2(struct iwl_trans *trans)
+static int iwl_set_temperature_offset_calib_v2(struct iwl_priv *priv)
 {
        struct iwl_calib_temperature_offset_v2_cmd cmd;
-       __le16 *offset_calib_high = (__le16 *)iwl_eeprom_query_addr(trans->shrd,
+       __le16 *offset_calib_high = (__le16 *)iwl_eeprom_query_addr(priv->shrd,
                                     EEPROM_KELVIN_TEMPERATURE);
        __le16 *offset_calib_low =
-               (__le16 *)iwl_eeprom_query_addr(trans->shrd,
+               (__le16 *)iwl_eeprom_query_addr(priv->shrd,
                                                EEPROM_RAW_TEMPERATURE);
        struct iwl_eeprom_calib_hdr *hdr;
 
        memset(&cmd, 0, sizeof(cmd));
        iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_TEMP_OFFSET_CMD);
-       hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(trans->shrd,
+       hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(priv->shrd,
                                                        EEPROM_CALIB_ALL);
        memcpy(&cmd.radio_sensor_offset_high, offset_calib_high,
                sizeof(*offset_calib_high));
        memcpy(&cmd.radio_sensor_offset_low, offset_calib_low,
                sizeof(*offset_calib_low));
        if (!(cmd.radio_sensor_offset_low)) {
-               IWL_DEBUG_CALIB(trans, "no info in EEPROM, use default\n");
+               IWL_DEBUG_CALIB(priv, "no info in EEPROM, use default\n");
                cmd.radio_sensor_offset_low = DEFAULT_RADIO_SENSOR_OFFSET;
                cmd.radio_sensor_offset_high = DEFAULT_RADIO_SENSOR_OFFSET;
        }
        memcpy(&cmd.burntVoltageRef, &hdr->voltage,
                sizeof(hdr->voltage));
 
-       IWL_DEBUG_CALIB(trans, "Radio sensor offset high: %d\n",
+       IWL_DEBUG_CALIB(priv, "Radio sensor offset high: %d\n",
                        le16_to_cpu(cmd.radio_sensor_offset_high));
-       IWL_DEBUG_CALIB(trans, "Radio sensor offset low: %d\n",
+       IWL_DEBUG_CALIB(priv, "Radio sensor offset low: %d\n",
                        le16_to_cpu(cmd.radio_sensor_offset_low));
-       IWL_DEBUG_CALIB(trans, "Voltage Ref: %d\n",
+       IWL_DEBUG_CALIB(priv, "Voltage Ref: %d\n",
                        le16_to_cpu(cmd.burntVoltageRef));
 
-       return iwl_calib_set(trans, (void *)&cmd, sizeof(cmd));
+       return iwl_calib_set(priv, (void *)&cmd, sizeof(cmd));
 }
 
-static int iwl_send_calib_cfg(struct iwl_trans *trans)
+static int iwl_send_calib_cfg(struct iwl_priv *priv)
 {
        struct iwl_calib_cfg_cmd calib_cfg_cmd;
        struct iwl_host_cmd cmd = {
@@ -223,47 +178,47 @@ static int iwl_send_calib_cfg(struct iwl_trans *trans)
        calib_cfg_cmd.ucd_calib_cfg.flags =
                IWL_CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_MSK;
 
-       return iwl_trans_send_cmd(trans, &cmd);
+       return iwl_dvm_send_cmd(priv, &cmd);
 }
 
 int iwlagn_rx_calib_result(struct iwl_priv *priv,
-                           struct iwl_rx_mem_buffer *rxb,
+                           struct iwl_rx_cmd_buffer *rxb,
                            struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_calib_hdr *hdr = (struct iwl_calib_hdr *)pkt->u.raw;
+       struct iwl_calib_hdr *hdr = (struct iwl_calib_hdr *)pkt->data;
        int len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
 
        /* reduce the size of the length field itself */
        len -= 4;
 
-       if (iwl_calib_set(trans(priv), hdr, len))
+       if (iwl_calib_set(priv, hdr, len))
                IWL_ERR(priv, "Failed to record calibration data %d\n",
                        hdr->op_code);
 
        return 0;
 }
 
-int iwl_init_alive_start(struct iwl_trans *trans)
+int iwl_init_alive_start(struct iwl_priv *priv)
 {
        int ret;
 
-       if (cfg(trans)->bt_params &&
-           cfg(trans)->bt_params->advanced_bt_coexist) {
+       if (cfg(priv)->bt_params &&
+           cfg(priv)->bt_params->advanced_bt_coexist) {
                /*
                 * Tell uCode we are ready to perform calibration
                 * need to perform this before any calibration
                 * no need to close the envlope since we are going
                 * to load the runtime uCode later.
                 */
-               ret = iwl_send_bt_env(trans, IWL_BT_COEX_ENV_OPEN,
+               ret = iwl_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN,
                        BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
                if (ret)
                        return ret;
 
        }
 
-       ret = iwl_send_calib_cfg(trans);
+       ret = iwl_send_calib_cfg(priv);
        if (ret)
                return ret;
 
@@ -271,21 +226,21 @@ int iwl_init_alive_start(struct iwl_trans *trans)
         * temperature offset calibration is only needed for runtime ucode,
         * so prepare the value now.
         */
-       if (cfg(trans)->need_temp_offset_calib) {
-               if (cfg(trans)->temp_offset_v2)
-                       return iwl_set_temperature_offset_calib_v2(trans);
+       if (cfg(priv)->need_temp_offset_calib) {
+               if (cfg(priv)->temp_offset_v2)
+                       return iwl_set_temperature_offset_calib_v2(priv);
                else
-                       return iwl_set_temperature_offset_calib(trans);
+                       return iwl_set_temperature_offset_calib(priv);
        }
 
        return 0;
 }
 
-static int iwl_send_wimax_coex(struct iwl_trans *trans)
+static int iwl_send_wimax_coex(struct iwl_priv *priv)
 {
        struct iwl_wimax_coex_cmd coex_cmd;
 
-       if (cfg(trans)->base_params->support_wimax_coexist) {
+       if (cfg(priv)->base_params->support_wimax_coexist) {
                /* UnMask wake up src at associated sleep */
                coex_cmd.flags = COEX_FLAGS_ASSOC_WA_UNMASK_MSK;
 
@@ -304,7 +259,7 @@ static int iwl_send_wimax_coex(struct iwl_trans *trans)
                /* coexistence is disabled */
                memset(&coex_cmd, 0, sizeof(coex_cmd));
        }
-       return iwl_trans_send_cmd_pdu(trans,
+       return iwl_dvm_send_cmd_pdu(priv,
                                COEX_PRIORITY_TABLE_CMD, CMD_SYNC,
                                sizeof(coex_cmd), &coex_cmd);
 }
@@ -331,64 +286,54 @@ static const u8 iwl_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = {
        0, 0, 0, 0, 0, 0, 0
 };
 
-void iwl_send_prio_tbl(struct iwl_trans *trans)
+void iwl_send_prio_tbl(struct iwl_priv *priv)
 {
        struct iwl_bt_coex_prio_table_cmd prio_tbl_cmd;
 
        memcpy(prio_tbl_cmd.prio_tbl, iwl_bt_prio_tbl,
                sizeof(iwl_bt_prio_tbl));
-       if (iwl_trans_send_cmd_pdu(trans,
+       if (iwl_dvm_send_cmd_pdu(priv,
                                REPLY_BT_COEX_PRIO_TABLE, CMD_SYNC,
                                sizeof(prio_tbl_cmd), &prio_tbl_cmd))
-               IWL_ERR(trans, "failed to send BT prio tbl command\n");
+               IWL_ERR(priv, "failed to send BT prio tbl command\n");
 }
 
-int iwl_send_bt_env(struct iwl_trans *trans, u8 action, u8 type)
+int iwl_send_bt_env(struct iwl_priv *priv, u8 action, u8 type)
 {
        struct iwl_bt_coex_prot_env_cmd env_cmd;
        int ret;
 
        env_cmd.action = action;
        env_cmd.type = type;
-       ret = iwl_trans_send_cmd_pdu(trans,
+       ret = iwl_dvm_send_cmd_pdu(priv,
                               REPLY_BT_COEX_PROT_ENV, CMD_SYNC,
                               sizeof(env_cmd), &env_cmd);
        if (ret)
-               IWL_ERR(trans, "failed to send BT env command\n");
+               IWL_ERR(priv, "failed to send BT env command\n");
        return ret;
 }
 
 
-static int iwl_alive_notify(struct iwl_trans *trans)
+static int iwl_alive_notify(struct iwl_priv *priv)
 {
-       struct iwl_priv *priv = priv(trans);
-       struct iwl_rxon_context *ctx;
        int ret;
 
-       if (!priv->tx_cmd_pool)
-               priv->tx_cmd_pool =
-                       kmem_cache_create("iwl_dev_cmd",
-                                         sizeof(struct iwl_device_cmd),
-                                         sizeof(void *), 0, NULL);
-
-       if (!priv->tx_cmd_pool)
-               return -ENOMEM;
+       iwl_trans_fw_alive(trans(priv));
 
-       iwl_trans_fw_alive(trans);
-       for_each_context(priv, ctx)
-               ctx->last_tx_rejected = false;
+       priv->passive_no_rx = false;
+       priv->transport_queue_stop = 0;
 
-       ret = iwl_send_wimax_coex(trans);
+       ret = iwl_send_wimax_coex(priv);
        if (ret)
                return ret;
 
        if (!cfg(priv)->no_xtal_calib) {
-               ret = iwl_set_Xtal_calib(trans);
+               ret = iwl_set_Xtal_calib(priv);
                if (ret)
                        return ret;
        }
 
-       return iwl_send_calib_results(trans);
+       return iwl_send_calib_results(priv);
 }
 
 
@@ -397,23 +342,23 @@ static int iwl_alive_notify(struct iwl_trans *trans)
  *   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_trans *trans,
-                                     struct fw_desc *fw_desc)
+static int iwl_verify_inst_sparse(struct iwl_priv *priv,
+                                 const struct fw_desc *fw_desc)
 {
        __le32 *image = (__le32 *)fw_desc->v_addr;
        u32 len = fw_desc->len;
        u32 val;
        u32 i;
 
-       IWL_DEBUG_FW(trans, "ucode inst image size is %u\n", len);
+       IWL_DEBUG_FW(priv, "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(trans, HBUS_TARG_MEM_RADDR,
+               iwl_write_direct32(trans(priv), HBUS_TARG_MEM_RADDR,
                        i + IWLAGN_RTC_INST_LOWER_BOUND);
-               val = iwl_read32(trans, HBUS_TARG_MEM_RDAT);
+               val = iwl_read32(trans(priv), HBUS_TARG_MEM_RDAT);
                if (val != le32_to_cpu(*image))
                        return -EIO;
        }
@@ -421,8 +366,8 @@ static int iwl_verify_inst_sparse(struct iwl_trans *trans,
        return 0;
 }
 
-static void iwl_print_mismatch_inst(struct iwl_trans *trans,
-                                   struct fw_desc *fw_desc)
+static void iwl_print_mismatch_inst(struct iwl_priv *priv,
+                                   const struct fw_desc *fw_desc)
 {
        __le32 *image = (__le32 *)fw_desc->v_addr;
        u32 len = fw_desc->len;
@@ -430,18 +375,18 @@ static void iwl_print_mismatch_inst(struct iwl_trans *trans,
        u32 offs;
        int errors = 0;
 
-       IWL_DEBUG_FW(trans, "ucode inst image size is %u\n", len);
+       IWL_DEBUG_FW(priv, "ucode inst image size is %u\n", len);
 
-       iwl_write_direct32(trans, HBUS_TARG_MEM_RADDR,
+       iwl_write_direct32(trans(priv), 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(trans, HBUS_TARG_MEM_RDAT);
+               val = iwl_read32(trans(priv), HBUS_TARG_MEM_RDAT);
                if (val != le32_to_cpu(*image)) {
-                       IWL_ERR(trans, "uCode INST section at "
+                       IWL_ERR(priv, "uCode INST section at "
                                "offset 0x%x, is 0x%x, s/b 0x%x\n",
                                offs, val, le32_to_cpu(*image));
                        errors++;
@@ -453,24 +398,24 @@ static void iwl_print_mismatch_inst(struct iwl_trans *trans,
  * iwl_verify_ucode - determine which instruction image is in SRAM,
  *    and verify its contents
  */
-static int iwl_verify_ucode(struct iwl_trans *trans,
+static int iwl_verify_ucode(struct iwl_priv *priv,
                            enum iwl_ucode_type ucode_type)
 {
-       struct fw_img *img = iwl_get_ucode_image(trans, ucode_type);
+       const struct fw_img *img = iwl_get_ucode_image(priv, ucode_type);
 
        if (!img) {
-               IWL_ERR(trans, "Invalid ucode requested (%d)\n", ucode_type);
+               IWL_ERR(priv, "Invalid ucode requested (%d)\n", ucode_type);
                return -EINVAL;
        }
 
-       if (!iwl_verify_inst_sparse(trans, &img->code)) {
-               IWL_DEBUG_FW(trans, "uCode is good in inst SRAM\n");
+       if (!iwl_verify_inst_sparse(priv, &img->code)) {
+               IWL_DEBUG_FW(priv, "uCode is good in inst SRAM\n");
                return 0;
        }
 
-       IWL_ERR(trans, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n");
+       IWL_ERR(priv, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n");
 
-       iwl_print_mismatch_inst(trans, &img->code);
+       iwl_print_mismatch_inst(priv, &img->code);
        return -EIO;
 }
 
@@ -479,119 +424,57 @@ struct iwl_alive_data {
        u8 subtype;
 };
 
-static void iwl_alive_fn(struct iwl_trans *trans,
+static void iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,
                            struct iwl_rx_packet *pkt,
                            void *data)
 {
+       struct iwl_priv *priv =
+               container_of(notif_wait, struct iwl_priv, notif_wait);
        struct iwl_alive_data *alive_data = data;
        struct iwl_alive_resp *palive;
 
-       palive = &pkt->u.alive_frame;
+       palive = (void *)pkt->data;
 
-       IWL_DEBUG_FW(trans, "Alive ucode status 0x%08X revision "
+       IWL_DEBUG_FW(priv, "Alive ucode status 0x%08X revision "
                       "0x%01X 0x%01X\n",
                       palive->is_valid, palive->ver_type,
                       palive->ver_subtype);
 
-       trans->shrd->device_pointers.error_event_table =
+       priv->shrd->device_pointers.error_event_table =
                le32_to_cpu(palive->error_event_table_ptr);
-       trans->shrd->device_pointers.log_event_table =
+       priv->shrd->device_pointers.log_event_table =
                le32_to_cpu(palive->log_event_table_ptr);
 
        alive_data->subtype = palive->ver_subtype;
        alive_data->valid = palive->is_valid == UCODE_VALID_OK;
 }
 
-/* notification wait support */
-void iwl_init_notification_wait(struct iwl_shared *shrd,
-                                  struct iwl_notification_wait *wait_entry,
-                                  u8 cmd,
-                                  void (*fn)(struct iwl_trans *trans,
-                                             struct iwl_rx_packet *pkt,
-                                             void *data),
-                                  void *fn_data)
-{
-       wait_entry->fn = fn;
-       wait_entry->fn_data = fn_data;
-       wait_entry->cmd = cmd;
-       wait_entry->triggered = false;
-       wait_entry->aborted = false;
-
-       spin_lock_bh(&shrd->notif_wait_lock);
-       list_add(&wait_entry->list, &shrd->notif_waits);
-       spin_unlock_bh(&shrd->notif_wait_lock);
-}
-
-int iwl_wait_notification(struct iwl_shared *shrd,
-                            struct iwl_notification_wait *wait_entry,
-                            unsigned long timeout)
-{
-       int ret;
-
-       ret = wait_event_timeout(shrd->notif_waitq,
-                                wait_entry->triggered || wait_entry->aborted,
-                                timeout);
-
-       spin_lock_bh(&shrd->notif_wait_lock);
-       list_del(&wait_entry->list);
-       spin_unlock_bh(&shrd->notif_wait_lock);
-
-       if (wait_entry->aborted)
-               return -EIO;
-
-       /* return value is always >= 0 */
-       if (ret <= 0)
-               return -ETIMEDOUT;
-       return 0;
-}
-
-void iwl_remove_notification(struct iwl_shared *shrd,
-                               struct iwl_notification_wait *wait_entry)
-{
-       spin_lock_bh(&shrd->notif_wait_lock);
-       list_del(&wait_entry->list);
-       spin_unlock_bh(&shrd->notif_wait_lock);
-}
-
-void iwl_abort_notification_waits(struct iwl_shared *shrd)
-{
-       unsigned long flags;
-       struct iwl_notification_wait *wait_entry;
-
-       spin_lock_irqsave(&shrd->notif_wait_lock, flags);
-       list_for_each_entry(wait_entry, &shrd->notif_waits, list)
-               wait_entry->aborted = true;
-       spin_unlock_irqrestore(&shrd->notif_wait_lock, flags);
-
-       wake_up_all(&shrd->notif_waitq);
-}
-
 #define UCODE_ALIVE_TIMEOUT    HZ
 #define UCODE_CALIB_TIMEOUT    (2*HZ)
 
-int iwl_load_ucode_wait_alive(struct iwl_trans *trans,
+int iwl_load_ucode_wait_alive(struct iwl_priv *priv,
                                 enum iwl_ucode_type ucode_type)
 {
        struct iwl_notification_wait alive_wait;
        struct iwl_alive_data alive_data;
-       struct fw_img *fw;
+       const struct fw_img *fw;
        int ret;
        enum iwl_ucode_type old_type;
 
-       iwl_init_notification_wait(trans->shrd, &alive_wait, REPLY_ALIVE,
-                                     iwl_alive_fn, &alive_data);
-
-       old_type = trans->shrd->ucode_type;
-       trans->shrd->ucode_type = ucode_type;
-       fw = iwl_get_ucode_image(trans, ucode_type);
+       old_type = priv->shrd->ucode_type;
+       priv->shrd->ucode_type = ucode_type;
+       fw = iwl_get_ucode_image(priv, ucode_type);
 
        if (!fw)
                return -EINVAL;
 
-       ret = iwl_trans_start_fw(trans, fw);
+       iwl_init_notification_wait(&priv->notif_wait, &alive_wait, REPLY_ALIVE,
+                                     iwl_alive_fn, &alive_data);
+
+       ret = iwl_trans_start_fw(trans(priv), fw);
        if (ret) {
-               trans->shrd->ucode_type = old_type;
-               iwl_remove_notification(trans->shrd, &alive_wait);
+               priv->shrd->ucode_type = old_type;
+               iwl_remove_notification(&priv->notif_wait, &alive_wait);
                return ret;
        }
 
@@ -599,16 +482,16 @@ int iwl_load_ucode_wait_alive(struct iwl_trans *trans,
         * Some things may run in the background now, but we
         * just wait for the ALIVE notification here.
         */
-       ret = iwl_wait_notification(trans->shrd, &alive_wait,
+       ret = iwl_wait_notification(&priv->notif_wait, &alive_wait,
                                        UCODE_ALIVE_TIMEOUT);
        if (ret) {
-               trans->shrd->ucode_type = old_type;
+               priv->shrd->ucode_type = old_type;
                return ret;
        }
 
        if (!alive_data.valid) {
-               IWL_ERR(trans, "Loaded ucode is not valid!\n");
-               trans->shrd->ucode_type = old_type;
+               IWL_ERR(priv, "Loaded ucode is not valid!\n");
+               priv->shrd->ucode_type = old_type;
                return -EIO;
        }
 
@@ -618,9 +501,9 @@ int iwl_load_ucode_wait_alive(struct iwl_trans *trans,
         * skip it for WoWLAN.
         */
        if (ucode_type != IWL_UCODE_WOWLAN) {
-               ret = iwl_verify_ucode(trans, ucode_type);
+               ret = iwl_verify_ucode(priv, ucode_type);
                if (ret) {
-                       trans->shrd->ucode_type = old_type;
+                       priv->shrd->ucode_type = old_type;
                        return ret;
                }
 
@@ -628,41 +511,41 @@ int iwl_load_ucode_wait_alive(struct iwl_trans *trans,
                msleep(5);
        }
 
-       ret = iwl_alive_notify(trans);
+       ret = iwl_alive_notify(priv);
        if (ret) {
-               IWL_WARN(trans,
+               IWL_WARN(priv,
                        "Could not complete ALIVE transition: %d\n", ret);
-               trans->shrd->ucode_type = old_type;
+               priv->shrd->ucode_type = old_type;
                return ret;
        }
 
        return 0;
 }
 
-int iwl_run_init_ucode(struct iwl_trans *trans)
+int iwl_run_init_ucode(struct iwl_priv *priv)
 {
        struct iwl_notification_wait calib_wait;
        int ret;
 
-       lockdep_assert_held(&trans->shrd->mutex);
+       lockdep_assert_held(&priv->mutex);
 
        /* No init ucode required? Curious, but maybe ok */
-       if (!trans->ucode_init.code.len)
+       if (!priv->fw->ucode_init.code.len)
                return 0;
 
-       if (trans->shrd->ucode_type != IWL_UCODE_NONE)
+       if (priv->shrd->ucode_type != IWL_UCODE_NONE)
                return 0;
 
-       iwl_init_notification_wait(trans->shrd, &calib_wait,
+       iwl_init_notification_wait(&priv->notif_wait, &calib_wait,
                                      CALIBRATION_COMPLETE_NOTIFICATION,
                                      NULL, NULL);
 
        /* Will also start the device */
-       ret = iwl_load_ucode_wait_alive(trans, IWL_UCODE_INIT);
+       ret = iwl_load_ucode_wait_alive(priv, IWL_UCODE_INIT);
        if (ret)
                goto error;
 
-       ret = iwl_init_alive_start(trans);
+       ret = iwl_init_alive_start(priv);
        if (ret)
                goto error;
 
@@ -670,621 +553,15 @@ int iwl_run_init_ucode(struct iwl_trans *trans)
         * Some things may run in the background now, but we
         * just wait for the calibration complete notification.
         */
-       ret = iwl_wait_notification(trans->shrd, &calib_wait,
+       ret = iwl_wait_notification(&priv->notif_wait, &calib_wait,
                                        UCODE_CALIB_TIMEOUT);
 
        goto out;
 
  error:
-       iwl_remove_notification(trans->shrd, &calib_wait);
+       iwl_remove_notification(&priv->notif_wait, &calib_wait);
  out:
        /* Whatever happened, stop the device */
-       iwl_trans_stop_device(trans);
+       iwl_trans_stop_device(trans(priv));
        return ret;
 }
-
-static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context);
-
-#define UCODE_EXPERIMENTAL_INDEX       100
-#define UCODE_EXPERIMENTAL_TAG         "exp"
-
-int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first)
-{
-       const char *name_pre = cfg(priv)->fw_name_pre;
-       char tag[8];
-
-       if (first) {
-#ifdef CONFIG_IWLWIFI_DEBUG_EXPERIMENTAL_UCODE
-               priv->fw_index = UCODE_EXPERIMENTAL_INDEX;
-               strcpy(tag, UCODE_EXPERIMENTAL_TAG);
-       } else if (priv->fw_index == UCODE_EXPERIMENTAL_INDEX) {
-#endif
-               priv->fw_index = cfg(priv)->ucode_api_max;
-               sprintf(tag, "%d", priv->fw_index);
-       } else {
-               priv->fw_index--;
-               sprintf(tag, "%d", priv->fw_index);
-       }
-
-       if (priv->fw_index < cfg(priv)->ucode_api_min) {
-               IWL_ERR(priv, "no suitable firmware found!\n");
-               return -ENOENT;
-       }
-
-       sprintf(priv->firmware_name, "%s%s%s", name_pre, tag, ".ucode");
-
-       IWL_DEBUG_INFO(priv, "attempting to load firmware %s'%s'\n",
-                      (priv->fw_index == UCODE_EXPERIMENTAL_INDEX)
-                               ? "EXPERIMENTAL " : "",
-                      priv->firmware_name);
-
-       return request_firmware_nowait(THIS_MODULE, 1, priv->firmware_name,
-                                      trans(priv)->dev,
-                                      GFP_KERNEL, priv, iwl_ucode_callback);
-}
-
-struct iwlagn_firmware_pieces {
-       const void *inst, *data, *init, *init_data, *wowlan_inst, *wowlan_data;
-       size_t inst_size, data_size, init_size, init_data_size,
-              wowlan_inst_size, wowlan_data_size;
-
-       u32 build;
-
-       u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr;
-       u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr;
-};
-
-static int iwlagn_load_legacy_firmware(struct iwl_priv *priv,
-                                      const struct firmware *ucode_raw,
-                                      struct iwlagn_firmware_pieces *pieces)
-{
-       struct iwl_ucode_header *ucode = (void *)ucode_raw->data;
-       u32 api_ver, hdr_size;
-       const u8 *src;
-
-       priv->ucode_ver = le32_to_cpu(ucode->ver);
-       api_ver = IWL_UCODE_API(priv->ucode_ver);
-
-       switch (api_ver) {
-       default:
-               hdr_size = 28;
-               if (ucode_raw->size < hdr_size) {
-                       IWL_ERR(priv, "File size too small!\n");
-                       return -EINVAL;
-               }
-               pieces->build = le32_to_cpu(ucode->u.v2.build);
-               pieces->inst_size = le32_to_cpu(ucode->u.v2.inst_size);
-               pieces->data_size = le32_to_cpu(ucode->u.v2.data_size);
-               pieces->init_size = le32_to_cpu(ucode->u.v2.init_size);
-               pieces->init_data_size = le32_to_cpu(ucode->u.v2.init_data_size);
-               src = ucode->u.v2.data;
-               break;
-       case 0:
-       case 1:
-       case 2:
-               hdr_size = 24;
-               if (ucode_raw->size < hdr_size) {
-                       IWL_ERR(priv, "File size too small!\n");
-                       return -EINVAL;
-               }
-               pieces->build = 0;
-               pieces->inst_size = le32_to_cpu(ucode->u.v1.inst_size);
-               pieces->data_size = le32_to_cpu(ucode->u.v1.data_size);
-               pieces->init_size = le32_to_cpu(ucode->u.v1.init_size);
-               pieces->init_data_size = le32_to_cpu(ucode->u.v1.init_data_size);
-               src = ucode->u.v1.data;
-               break;
-       }
-
-       /* Verify size of file vs. image size info in file's header */
-       if (ucode_raw->size != hdr_size + pieces->inst_size +
-                               pieces->data_size + pieces->init_size +
-                               pieces->init_data_size) {
-
-               IWL_ERR(priv,
-                       "uCode file size %d does not match expected size\n",
-                       (int)ucode_raw->size);
-               return -EINVAL;
-       }
-
-       pieces->inst = src;
-       src += pieces->inst_size;
-       pieces->data = src;
-       src += pieces->data_size;
-       pieces->init = src;
-       src += pieces->init_size;
-       pieces->init_data = src;
-       src += pieces->init_data_size;
-
-       return 0;
-}
-
-static int iwlagn_load_firmware(struct iwl_priv *priv,
-                               const struct firmware *ucode_raw,
-                               struct iwlagn_firmware_pieces *pieces,
-                               struct iwlagn_ucode_capabilities *capa)
-{
-       struct iwl_tlv_ucode_header *ucode = (void *)ucode_raw->data;
-       struct iwl_ucode_tlv *tlv;
-       size_t len = ucode_raw->size;
-       const u8 *data;
-       int wanted_alternative = iwlagn_mod_params.wanted_ucode_alternative;
-       int tmp;
-       u64 alternatives;
-       u32 tlv_len;
-       enum iwl_ucode_tlv_type tlv_type;
-       const u8 *tlv_data;
-
-       if (len < sizeof(*ucode)) {
-               IWL_ERR(priv, "uCode has invalid length: %zd\n", len);
-               return -EINVAL;
-       }
-
-       if (ucode->magic != cpu_to_le32(IWL_TLV_UCODE_MAGIC)) {
-               IWL_ERR(priv, "invalid uCode magic: 0X%x\n",
-                       le32_to_cpu(ucode->magic));
-               return -EINVAL;
-       }
-
-       /*
-        * Check which alternatives are present, and "downgrade"
-        * when the chosen alternative is not present, warning
-        * the user when that happens. Some files may not have
-        * any alternatives, so don't warn in that case.
-        */
-       alternatives = le64_to_cpu(ucode->alternatives);
-       tmp = wanted_alternative;
-       if (wanted_alternative > 63)
-               wanted_alternative = 63;
-       while (wanted_alternative && !(alternatives & BIT(wanted_alternative)))
-               wanted_alternative--;
-       if (wanted_alternative && wanted_alternative != tmp)
-               IWL_WARN(priv,
-                        "uCode alternative %d not available, choosing %d\n",
-                        tmp, wanted_alternative);
-
-       priv->ucode_ver = le32_to_cpu(ucode->ver);
-       pieces->build = le32_to_cpu(ucode->build);
-       data = ucode->data;
-
-       len -= sizeof(*ucode);
-
-       while (len >= sizeof(*tlv)) {
-               u16 tlv_alt;
-
-               len -= sizeof(*tlv);
-               tlv = (void *)data;
-
-               tlv_len = le32_to_cpu(tlv->length);
-               tlv_type = le16_to_cpu(tlv->type);
-               tlv_alt = le16_to_cpu(tlv->alternative);
-               tlv_data = tlv->data;
-
-               if (len < tlv_len) {
-                       IWL_ERR(priv, "invalid TLV len: %zd/%u\n",
-                               len, tlv_len);
-                       return -EINVAL;
-               }
-               len -= ALIGN(tlv_len, 4);
-               data += sizeof(*tlv) + ALIGN(tlv_len, 4);
-
-               /*
-                * Alternative 0 is always valid.
-                *
-                * Skip alternative TLVs that are not selected.
-                */
-               if (tlv_alt != 0 && tlv_alt != wanted_alternative)
-                       continue;
-
-               switch (tlv_type) {
-               case IWL_UCODE_TLV_INST:
-                       pieces->inst = tlv_data;
-                       pieces->inst_size = tlv_len;
-                       break;
-               case IWL_UCODE_TLV_DATA:
-                       pieces->data = tlv_data;
-                       pieces->data_size = tlv_len;
-                       break;
-               case IWL_UCODE_TLV_INIT:
-                       pieces->init = tlv_data;
-                       pieces->init_size = tlv_len;
-                       break;
-               case IWL_UCODE_TLV_INIT_DATA:
-                       pieces->init_data = tlv_data;
-                       pieces->init_data_size = tlv_len;
-                       break;
-               case IWL_UCODE_TLV_BOOT:
-                       IWL_ERR(priv, "Found unexpected BOOT ucode\n");
-                       break;
-               case IWL_UCODE_TLV_PROBE_MAX_LEN:
-                       if (tlv_len != sizeof(u32))
-                               goto invalid_tlv_len;
-                       capa->max_probe_length =
-                                       le32_to_cpup((__le32 *)tlv_data);
-                       break;
-               case IWL_UCODE_TLV_PAN:
-                       if (tlv_len)
-                               goto invalid_tlv_len;
-                       capa->flags |= IWL_UCODE_TLV_FLAGS_PAN;
-                       break;
-               case IWL_UCODE_TLV_FLAGS:
-                       /* must be at least one u32 */
-                       if (tlv_len < sizeof(u32))
-                               goto invalid_tlv_len;
-                       /* and a proper number of u32s */
-                       if (tlv_len % sizeof(u32))
-                               goto invalid_tlv_len;
-                       /*
-                        * This driver only reads the first u32 as
-                        * right now no more features are defined,
-                        * if that changes then either the driver
-                        * will not work with the new firmware, or
-                        * it'll not take advantage of new features.
-                        */
-                       capa->flags = le32_to_cpup((__le32 *)tlv_data);
-                       break;
-               case IWL_UCODE_TLV_INIT_EVTLOG_PTR:
-                       if (tlv_len != sizeof(u32))
-                               goto invalid_tlv_len;
-                       pieces->init_evtlog_ptr =
-                                       le32_to_cpup((__le32 *)tlv_data);
-                       break;
-               case IWL_UCODE_TLV_INIT_EVTLOG_SIZE:
-                       if (tlv_len != sizeof(u32))
-                               goto invalid_tlv_len;
-                       pieces->init_evtlog_size =
-                                       le32_to_cpup((__le32 *)tlv_data);
-                       break;
-               case IWL_UCODE_TLV_INIT_ERRLOG_PTR:
-                       if (tlv_len != sizeof(u32))
-                               goto invalid_tlv_len;
-                       pieces->init_errlog_ptr =
-                                       le32_to_cpup((__le32 *)tlv_data);
-                       break;
-               case IWL_UCODE_TLV_RUNT_EVTLOG_PTR:
-                       if (tlv_len != sizeof(u32))
-                               goto invalid_tlv_len;
-                       pieces->inst_evtlog_ptr =
-                                       le32_to_cpup((__le32 *)tlv_data);
-                       break;
-               case IWL_UCODE_TLV_RUNT_EVTLOG_SIZE:
-                       if (tlv_len != sizeof(u32))
-                               goto invalid_tlv_len;
-                       pieces->inst_evtlog_size =
-                                       le32_to_cpup((__le32 *)tlv_data);
-                       break;
-               case IWL_UCODE_TLV_RUNT_ERRLOG_PTR:
-                       if (tlv_len != sizeof(u32))
-                               goto invalid_tlv_len;
-                       pieces->inst_errlog_ptr =
-                                       le32_to_cpup((__le32 *)tlv_data);
-                       break;
-               case IWL_UCODE_TLV_ENHANCE_SENS_TBL:
-                       if (tlv_len)
-                               goto invalid_tlv_len;
-                       priv->enhance_sensitivity_table = true;
-                       break;
-               case IWL_UCODE_TLV_WOWLAN_INST:
-                       pieces->wowlan_inst = tlv_data;
-                       pieces->wowlan_inst_size = tlv_len;
-                       break;
-               case IWL_UCODE_TLV_WOWLAN_DATA:
-                       pieces->wowlan_data = tlv_data;
-                       pieces->wowlan_data_size = tlv_len;
-                       break;
-               case IWL_UCODE_TLV_PHY_CALIBRATION_SIZE:
-                       if (tlv_len != sizeof(u32))
-                               goto invalid_tlv_len;
-                       capa->standard_phy_calibration_size =
-                                       le32_to_cpup((__le32 *)tlv_data);
-                       break;
-               default:
-                       IWL_DEBUG_INFO(priv, "unknown TLV: %d\n", tlv_type);
-                       break;
-               }
-       }
-
-       if (len) {
-               IWL_ERR(priv, "invalid TLV after parsing: %zd\n", len);
-               iwl_print_hex_dump(priv, IWL_DL_FW, (u8 *)data, len);
-               return -EINVAL;
-       }
-
-       return 0;
-
- invalid_tlv_len:
-       IWL_ERR(priv, "TLV %d has invalid size: %u\n", tlv_type, tlv_len);
-       iwl_print_hex_dump(priv, IWL_DL_FW, tlv_data, tlv_len);
-
-       return -EINVAL;
-}
-
-/**
- * iwl_ucode_callback - callback when firmware was loaded
- *
- * If loaded successfully, copies the firmware into buffers
- * for the card to fetch (via DMA).
- */
-static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
-{
-       struct iwl_priv *priv = context;
-       struct iwl_ucode_header *ucode;
-       int err;
-       struct iwlagn_firmware_pieces pieces;
-       const unsigned int api_max = cfg(priv)->ucode_api_max;
-       unsigned int api_ok = cfg(priv)->ucode_api_ok;
-       const unsigned int api_min = cfg(priv)->ucode_api_min;
-       u32 api_ver;
-       char buildstr[25];
-       u32 build;
-       struct iwlagn_ucode_capabilities ucode_capa = {
-               .max_probe_length = 200,
-               .standard_phy_calibration_size =
-                       IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE,
-       };
-
-       if (!api_ok)
-               api_ok = api_max;
-
-       memset(&pieces, 0, sizeof(pieces));
-
-       if (!ucode_raw) {
-               if (priv->fw_index <= api_ok)
-                       IWL_ERR(priv,
-                               "request for firmware file '%s' failed.\n",
-                               priv->firmware_name);
-               goto try_again;
-       }
-
-       IWL_DEBUG_INFO(priv, "Loaded firmware file '%s' (%zd bytes).\n",
-                      priv->firmware_name, ucode_raw->size);
-
-       /* Make sure that we got at least the API version number */
-       if (ucode_raw->size < 4) {
-               IWL_ERR(priv, "File size way too small!\n");
-               goto try_again;
-       }
-
-       /* Data from ucode file:  header followed by uCode images */
-       ucode = (struct iwl_ucode_header *)ucode_raw->data;
-
-       if (ucode->ver)
-               err = iwlagn_load_legacy_firmware(priv, ucode_raw, &pieces);
-       else
-               err = iwlagn_load_firmware(priv, ucode_raw, &pieces,
-                                          &ucode_capa);
-
-       if (err)
-               goto try_again;
-
-       api_ver = IWL_UCODE_API(priv->ucode_ver);
-       build = pieces.build;
-
-       /*
-        * api_ver should match the api version forming part of the
-        * firmware filename ... but we don't check for that and only rely
-        * on the API version read from firmware header from here on forward
-        */
-       /* no api version check required for experimental uCode */
-       if (priv->fw_index != UCODE_EXPERIMENTAL_INDEX) {
-               if (api_ver < api_min || api_ver > api_max) {
-                       IWL_ERR(priv,
-                               "Driver unable to support your firmware API. "
-                               "Driver supports v%u, firmware is v%u.\n",
-                               api_max, api_ver);
-                       goto try_again;
-               }
-
-               if (api_ver < api_ok) {
-                       if (api_ok != api_max)
-                               IWL_ERR(priv, "Firmware has old API version, "
-                                       "expected v%u through v%u, got v%u.\n",
-                                       api_ok, api_max, api_ver);
-                       else
-                               IWL_ERR(priv, "Firmware has old API version, "
-                                       "expected v%u, got v%u.\n",
-                                       api_max, api_ver);
-                       IWL_ERR(priv, "New firmware can be obtained from "
-                                     "http://www.intellinuxwireless.org/.\n");
-               }
-       }
-
-       if (build)
-               sprintf(buildstr, " build %u%s", build,
-                      (priv->fw_index == UCODE_EXPERIMENTAL_INDEX)
-                               ? " (EXP)" : "");
-       else
-               buildstr[0] = '\0';
-
-       IWL_INFO(priv, "loaded firmware version %u.%u.%u.%u%s\n",
-                IWL_UCODE_MAJOR(priv->ucode_ver),
-                IWL_UCODE_MINOR(priv->ucode_ver),
-                IWL_UCODE_API(priv->ucode_ver),
-                IWL_UCODE_SERIAL(priv->ucode_ver),
-                buildstr);
-
-       snprintf(priv->hw->wiphy->fw_version,
-                sizeof(priv->hw->wiphy->fw_version),
-                "%u.%u.%u.%u%s",
-                IWL_UCODE_MAJOR(priv->ucode_ver),
-                IWL_UCODE_MINOR(priv->ucode_ver),
-                IWL_UCODE_API(priv->ucode_ver),
-                IWL_UCODE_SERIAL(priv->ucode_ver),
-                buildstr);
-
-       /*
-        * For any of the failures below (before allocating pci memory)
-        * we will try to load a version with a smaller API -- maybe the
-        * user just got a corrupted version of the latest API.
-        */
-
-       IWL_DEBUG_INFO(priv, "f/w package hdr ucode version raw = 0x%x\n",
-                      priv->ucode_ver);
-       IWL_DEBUG_INFO(priv, "f/w package hdr runtime inst size = %Zd\n",
-                      pieces.inst_size);
-       IWL_DEBUG_INFO(priv, "f/w package hdr runtime data size = %Zd\n",
-                      pieces.data_size);
-       IWL_DEBUG_INFO(priv, "f/w package hdr init inst size = %Zd\n",
-                      pieces.init_size);
-       IWL_DEBUG_INFO(priv, "f/w package hdr init data size = %Zd\n",
-                      pieces.init_data_size);
-
-       /* Verify that uCode images will fit in card's SRAM */
-       if (pieces.inst_size > hw_params(priv).max_inst_size) {
-               IWL_ERR(priv, "uCode instr len %Zd too large to fit in\n",
-                       pieces.inst_size);
-               goto try_again;
-       }
-
-       if (pieces.data_size > hw_params(priv).max_data_size) {
-               IWL_ERR(priv, "uCode data len %Zd too large to fit in\n",
-                       pieces.data_size);
-               goto try_again;
-       }
-
-       if (pieces.init_size > hw_params(priv).max_inst_size) {
-               IWL_ERR(priv, "uCode init instr len %Zd too large to fit in\n",
-                       pieces.init_size);
-               goto try_again;
-       }
-
-       if (pieces.init_data_size > hw_params(priv).max_data_size) {
-               IWL_ERR(priv, "uCode init data len %Zd too large to fit in\n",
-                       pieces.init_data_size);
-               goto try_again;
-       }
-
-       /* Allocate ucode buffers for card's bus-master loading ... */
-
-       /* 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(trans(priv), &trans(priv)->ucode_rt.code,
-                             pieces.inst, pieces.inst_size))
-               goto err_pci_alloc;
-       if (iwl_alloc_fw_desc(trans(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(trans(priv),
-                                     &trans(priv)->ucode_init.code,
-                                     pieces.init, pieces.init_size))
-                       goto err_pci_alloc;
-               if (iwl_alloc_fw_desc(trans(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(trans(priv),
-                                     &trans(priv)->ucode_wowlan.code,
-                                     pieces.wowlan_inst,
-                                     pieces.wowlan_inst_size))
-                       goto err_pci_alloc;
-               if (iwl_alloc_fw_desc(trans(priv),
-                                     &trans(priv)->ucode_wowlan.data,
-                                     pieces.wowlan_data,
-                                     pieces.wowlan_data_size))
-                       goto err_pci_alloc;
-       }
-
-       /* Now that we can no longer fail, copy information */
-
-       /*
-        * The (size - 16) / 12 formula is based on the information recorded
-        * for each event, which is of mode 1 (including timestamp) for all
-        * new microcodes that include this information.
-        */
-       priv->init_evtlog_ptr = pieces.init_evtlog_ptr;
-       if (pieces.init_evtlog_size)
-               priv->init_evtlog_size = (pieces.init_evtlog_size - 16)/12;
-       else
-               priv->init_evtlog_size =
-                       cfg(priv)->base_params->max_event_log_size;
-       priv->init_errlog_ptr = pieces.init_errlog_ptr;
-       priv->inst_evtlog_ptr = pieces.inst_evtlog_ptr;
-       if (pieces.inst_evtlog_size)
-               priv->inst_evtlog_size = (pieces.inst_evtlog_size - 16)/12;
-       else
-               priv->inst_evtlog_size =
-                       cfg(priv)->base_params->max_event_log_size;
-       priv->inst_errlog_ptr = pieces.inst_errlog_ptr;
-#ifndef CONFIG_IWLWIFI_P2P
-       ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_PAN;
-#endif
-
-       priv->new_scan_threshold_behaviour =
-               !!(ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWSCAN);
-
-       if (!(cfg(priv)->sku & EEPROM_SKU_CAP_IPAN_ENABLE))
-               ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_PAN;
-
-       /*
-        * if not PAN, then don't support P2P -- might be a uCode
-        * packaging bug or due to the eeprom check above
-        */
-       if (!(ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN))
-               ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_P2P;
-
-       if (ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN) {
-               priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN;
-               priv->shrd->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM;
-       } else {
-               priv->sta_key_max_num = STA_KEY_MAX_NUM;
-               priv->shrd->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM;
-       }
-       /*
-        * figure out the offset of chain noise reset and gain commands
-        * base on the size of standard phy calibration commands table size
-        */
-       if (ucode_capa.standard_phy_calibration_size >
-           IWL_MAX_PHY_CALIBRATE_TBL_SIZE)
-               ucode_capa.standard_phy_calibration_size =
-                       IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE;
-
-       priv->phy_calib_chain_noise_reset_cmd =
-               ucode_capa.standard_phy_calibration_size;
-       priv->phy_calib_chain_noise_gain_cmd =
-               ucode_capa.standard_phy_calibration_size + 1;
-
-       /* initialize all valid contexts */
-       iwl_init_context(priv, ucode_capa.flags);
-
-       /**************************************************
-        * This is still part of probe() in a sense...
-        *
-        * 9. Setup and register with mac80211 and debugfs
-        **************************************************/
-       err = iwlagn_mac_setup_register(priv, &ucode_capa);
-       if (err)
-               goto out_unbind;
-
-       err = iwl_dbgfs_register(priv, DRV_NAME);
-       if (err)
-               IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err);
-
-       /* We have our copies now, allow OS release its copies */
-       release_firmware(ucode_raw);
-       complete(&priv->firmware_loading_complete);
-       return;
-
- try_again:
-       /* try next, if any */
-       if (iwl_request_firmware(priv, false))
-               goto out_unbind;
-       release_firmware(ucode_raw);
-       return;
-
- err_pci_alloc:
-       IWL_ERR(priv, "failed to allocate pci memory\n");
-       iwl_dealloc_ucode(trans(priv));
- out_unbind:
-       complete(&priv->firmware_loading_complete);
-       device_release_driver(trans(priv)->dev);
-       release_firmware(ucode_raw);
-}
-
diff --git a/drivers/net/wireless/iwlwifi/iwl-ucode.h b/drivers/net/wireless/iwlwifi/iwl-ucode.h
deleted file mode 100644 (file)
index eccf925..0000000
+++ /dev/null
@@ -1,178 +0,0 @@
-/******************************************************************************
- *
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
- *
- * 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.GPL.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- * BSD LICENSE
- *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *  * Neither the name Intel Corporation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *****************************************************************************/
-
-#ifndef __iwl_ucode_h__
-#define __iwl_ucode_h__
-
-/* v1/v2 uCode file layout */
-struct iwl_ucode_header {
-       __le32 ver;     /* major/minor/API/serial */
-       union {
-               struct {
-                       __le32 inst_size;       /* bytes of runtime code */
-                       __le32 data_size;       /* bytes of runtime data */
-                       __le32 init_size;       /* bytes of init code */
-                       __le32 init_data_size;  /* bytes of init data */
-                       __le32 boot_size;       /* bytes of bootstrap code */
-                       u8 data[0];             /* in same order as sizes */
-               } v1;
-               struct {
-                       __le32 build;           /* build number */
-                       __le32 inst_size;       /* bytes of runtime code */
-                       __le32 data_size;       /* bytes of runtime data */
-                       __le32 init_size;       /* bytes of init code */
-                       __le32 init_data_size;  /* bytes of init data */
-                       __le32 boot_size;       /* bytes of bootstrap code */
-                       u8 data[0];             /* in same order as sizes */
-               } v2;
-       } u;
-};
-
-/*
- * new TLV uCode file layout
- *
- * The new TLV file format contains TLVs, that each specify
- * some piece of data. To facilitate "groups", for example
- * different instruction image with different capabilities,
- * bundled with the same init image, an alternative mechanism
- * is provided:
- * When the alternative field is 0, that means that the item
- * is always valid. When it is non-zero, then it is only
- * valid in conjunction with items of the same alternative,
- * in which case the driver (user) selects one alternative
- * to use.
- */
-
-enum iwl_ucode_tlv_type {
-       IWL_UCODE_TLV_INVALID           = 0, /* unused */
-       IWL_UCODE_TLV_INST              = 1,
-       IWL_UCODE_TLV_DATA              = 2,
-       IWL_UCODE_TLV_INIT              = 3,
-       IWL_UCODE_TLV_INIT_DATA         = 4,
-       IWL_UCODE_TLV_BOOT              = 5,
-       IWL_UCODE_TLV_PROBE_MAX_LEN     = 6, /* a u32 value */
-       IWL_UCODE_TLV_PAN               = 7,
-       IWL_UCODE_TLV_RUNT_EVTLOG_PTR   = 8,
-       IWL_UCODE_TLV_RUNT_EVTLOG_SIZE  = 9,
-       IWL_UCODE_TLV_RUNT_ERRLOG_PTR   = 10,
-       IWL_UCODE_TLV_INIT_EVTLOG_PTR   = 11,
-       IWL_UCODE_TLV_INIT_EVTLOG_SIZE  = 12,
-       IWL_UCODE_TLV_INIT_ERRLOG_PTR   = 13,
-       IWL_UCODE_TLV_ENHANCE_SENS_TBL  = 14,
-       IWL_UCODE_TLV_PHY_CALIBRATION_SIZE = 15,
-       IWL_UCODE_TLV_WOWLAN_INST       = 16,
-       IWL_UCODE_TLV_WOWLAN_DATA       = 17,
-       IWL_UCODE_TLV_FLAGS             = 18,
-};
-
-/**
- * enum iwl_ucode_tlv_flag - ucode API flags
- * @IWL_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously
- *     was a separate TLV but moved here to save space.
- * @IWL_UCODE_TLV_FLAGS_NEWSCAN: new uCode scan behaviour on hidden SSID,
- *     treats good CRC threshold as a boolean
- * @IWL_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w).
- * @IWL_UCODE_TLV_FLAGS_P2P: This uCode image supports P2P.
- */
-enum iwl_ucode_tlv_flag {
-       IWL_UCODE_TLV_FLAGS_PAN         = BIT(0),
-       IWL_UCODE_TLV_FLAGS_NEWSCAN     = BIT(1),
-       IWL_UCODE_TLV_FLAGS_MFP         = BIT(2),
-       IWL_UCODE_TLV_FLAGS_P2P         = BIT(3),
-};
-
-struct iwl_ucode_tlv {
-       __le16 type;            /* see above */
-       __le16 alternative;     /* see comment */
-       __le32 length;          /* not including type/length fields */
-       u8 data[0];
-};
-
-#define IWL_TLV_UCODE_MAGIC    0x0a4c5749
-
-struct iwl_tlv_ucode_header {
-       /*
-        * The TLV style ucode header is distinguished from
-        * the v1/v2 style header by first four bytes being
-        * zero, as such is an invalid combination of
-        * major/minor/API/serial versions.
-        */
-       __le32 zero;
-       __le32 magic;
-       u8 human_readable[64];
-       __le32 ver;             /* major/minor/API/serial */
-       __le32 build;
-       __le64 alternatives;    /* bitmask of valid alternatives */
-       /*
-        * The data contained herein has a TLV layout,
-        * see above for the TLV header and types.
-        * Note that each TLV is padded to a length
-        * that is a multiple of 4 for alignment.
-        */
-       u8 data[0];
-};
-
-struct iwl_priv;
-
-int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first);
-
-#endif  /* __iwl_ucode_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-wifi.h b/drivers/net/wireless/iwlwifi/iwl-wifi.h
deleted file mode 100644 (file)
index 7e6eb20..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/******************************************************************************
- *
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
- *
- * 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.GPL.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- * BSD LICENSE
- *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *  * Neither the name Intel Corporation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *****************************************************************************/
-
-#ifndef __iwl_wifi_h__
-#define __iwl_wifi_h__
-
-#include "iwl-shared.h"
-
-int iwl_send_bt_env(struct iwl_trans *trans, u8 action, u8 type);
-void iwl_send_prio_tbl(struct iwl_trans *trans);
-int iwl_init_alive_start(struct iwl_trans *trans);
-int iwl_run_init_ucode(struct iwl_trans *trans);
-int iwl_load_ucode_wait_alive(struct iwl_trans *trans,
-                                enum iwl_ucode_type ucode_type);
-#endif  /* __iwl_wifi_h__ */
index 4b9e730d2c8a13cc184f1ee5b5cba868f59398a7..b4f6cb3298a46c08826fda462f963ef4b52a4459 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/etherdevice.h>
 #include <linux/debugfs.h>
 #include <linux/module.h>
+#include <linux/ktime.h>
 #include <net/genetlink.h>
 #include "mac80211_hwsim.h"
 
@@ -321,11 +322,15 @@ struct mac80211_hwsim_data {
        struct dentry *debugfs_group;
 
        int power_level;
+
+       /* difference between this hw's clock and the real clock, in usecs */
+       u64 tsf_offset;
 };
 
 
 struct hwsim_radiotap_hdr {
        struct ieee80211_radiotap_header hdr;
+       __le64 rt_tsft;
        u8 rt_flags;
        u8 rt_rate;
        __le16 rt_channel;
@@ -367,6 +372,28 @@ static netdev_tx_t hwsim_mon_xmit(struct sk_buff *skb,
        return NETDEV_TX_OK;
 }
 
+static __le64 __mac80211_hwsim_get_tsf(struct mac80211_hwsim_data *data)
+{
+       struct timeval tv = ktime_to_timeval(ktime_get_real());
+       u64 now = tv.tv_sec * USEC_PER_SEC + tv.tv_usec;
+       return cpu_to_le64(now + data->tsf_offset);
+}
+
+static u64 mac80211_hwsim_get_tsf(struct ieee80211_hw *hw,
+               struct ieee80211_vif *vif)
+{
+       struct mac80211_hwsim_data *data = hw->priv;
+       return le64_to_cpu(__mac80211_hwsim_get_tsf(data));
+}
+
+static void mac80211_hwsim_set_tsf(struct ieee80211_hw *hw,
+               struct ieee80211_vif *vif, u64 tsf)
+{
+       struct mac80211_hwsim_data *data = hw->priv;
+       struct timeval tv = ktime_to_timeval(ktime_get_real());
+       u64 now = tv.tv_sec * USEC_PER_SEC + tv.tv_usec;
+       data->tsf_offset = tsf - now;
+}
 
 static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
                                      struct sk_buff *tx_skb)
@@ -391,7 +418,9 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
        hdr->hdr.it_len = cpu_to_le16(sizeof(*hdr));
        hdr->hdr.it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
                                          (1 << IEEE80211_RADIOTAP_RATE) |
+                                         (1 << IEEE80211_RADIOTAP_TSFT) |
                                          (1 << IEEE80211_RADIOTAP_CHANNEL));
+       hdr->rt_tsft = __mac80211_hwsim_get_tsf(data);
        hdr->rt_flags = 0;
        hdr->rt_rate = txrate->bitrate / 5;
        hdr->rt_channel = cpu_to_le16(data->channel->center_freq);
@@ -592,7 +621,7 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
        return;
 
 nla_put_failure:
-       printk(KERN_DEBUG "mac80211_hwsim: error occured in %s\n", __func__);
+       printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__);
 }
 
 static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
@@ -610,7 +639,8 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
        }
 
        memset(&rx_status, 0, sizeof(rx_status));
-       /* TODO: set mactime */
+       rx_status.mactime = le64_to_cpu(__mac80211_hwsim_get_tsf(data));
+       rx_status.flag |= RX_FLAG_MACTIME_MPDU;
        rx_status.freq = data->channel->center_freq;
        rx_status.band = data->channel->band;
        rx_status.rate_idx = info->control.rates[0].idx;
@@ -667,6 +697,12 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
        bool ack;
        struct ieee80211_tx_info *txi;
        u32 _pid;
+       struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) skb->data;
+       struct mac80211_hwsim_data *data = hw->priv;
+
+       if (ieee80211_is_beacon(mgmt->frame_control) ||
+           ieee80211_is_probe_resp(mgmt->frame_control))
+               mgmt->u.beacon.timestamp = __mac80211_hwsim_get_tsf(data);
 
        mac80211_hwsim_monitor_rx(hw, skb);
 
@@ -763,9 +799,11 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
                                     struct ieee80211_vif *vif)
 {
        struct ieee80211_hw *hw = arg;
+       struct mac80211_hwsim_data *data = hw->priv;
        struct sk_buff *skb;
        struct ieee80211_tx_info *info;
        u32 _pid;
+       struct ieee80211_mgmt *mgmt;
 
        hwsim_check_magic(vif);
 
@@ -779,6 +817,9 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
                return;
        info = IEEE80211_SKB_CB(skb);
 
+       mgmt = (struct ieee80211_mgmt *) skb->data;
+       mgmt->u.beacon.timestamp = __mac80211_hwsim_get_tsf(data);
+
        mac80211_hwsim_monitor_rx(hw, skb);
 
        /* wmediumd mode check */
@@ -1199,6 +1240,8 @@ static struct ieee80211_ops mac80211_hwsim_ops =
        .sw_scan_start = mac80211_hwsim_sw_scan,
        .sw_scan_complete = mac80211_hwsim_sw_scan_complete,
        .flush = mac80211_hwsim_flush,
+       .get_tsf = mac80211_hwsim_get_tsf,
+       .set_tsf = mac80211_hwsim_set_tsf,
 };
 
 
@@ -1564,7 +1607,7 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
 
        return 0;
 err:
-       printk(KERN_DEBUG "mac80211_hwsim: error occured in %s\n", __func__);
+       printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__);
        goto out;
 out:
        dev_kfree_skb(skb);
@@ -1580,11 +1623,11 @@ static int hwsim_register_received_nl(struct sk_buff *skb_2,
        wmediumd_pid = info->snd_pid;
 
        printk(KERN_DEBUG "mac80211_hwsim: received a REGISTER, "
-       "switching to wmediumd mode with pid %d\n", info->snd_pid);
+              "switching to wmediumd mode with pid %d\n", info->snd_pid);
 
        return 0;
 out:
-       printk(KERN_DEBUG "mac80211_hwsim: error occured in %s\n", __func__);
+       printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__);
        return -EINVAL;
 }
 
@@ -1647,7 +1690,7 @@ static int hwsim_init_netlink(void)
        return 0;
 
 failure:
-       printk(KERN_DEBUG "mac80211_hwsim: error occured in %s\n", __func__);
+       printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__);
        return -EINVAL;
 }
 
index 8d8ee639fe5607ccab8502678bc0f68598cbd85d..84508b0652653f435ac29def452c87e4e64834ed 100644 (file)
@@ -146,7 +146,7 @@ mwifiex_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
        struct mwifiex_private *priv = mwifiex_netdev_get_priv(netdev);
 
        /* Return if WEP key not configured */
-       if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED)
+       if (!priv->sec_info.wep_enabled)
                return 0;
 
        if (mwifiex_set_encode(priv, NULL, 0, key_index, 0)) {
@@ -613,7 +613,6 @@ static struct ieee80211_rate mwifiex_rates[] = {
        {.bitrate = 20, .hw_value = 4, },
        {.bitrate = 55, .hw_value = 11, },
        {.bitrate = 110, .hw_value = 22, },
-       {.bitrate = 220, .hw_value = 44, },
        {.bitrate = 60, .hw_value = 12, },
        {.bitrate = 90, .hw_value = 18, },
        {.bitrate = 120, .hw_value = 24, },
@@ -622,7 +621,6 @@ static struct ieee80211_rate mwifiex_rates[] = {
        {.bitrate = 360, .hw_value = 72, },
        {.bitrate = 480, .hw_value = 96, },
        {.bitrate = 540, .hw_value = 108, },
-       {.bitrate = 720, .hw_value = 144, },
 };
 
 /* Channel definitions to be advertised to cfg80211 */
@@ -648,7 +646,7 @@ static struct ieee80211_supported_band mwifiex_band_2ghz = {
        .channels = mwifiex_channels_2ghz,
        .n_channels = ARRAY_SIZE(mwifiex_channels_2ghz),
        .bitrates = mwifiex_rates,
-       .n_bitrates = 14,
+       .n_bitrates = ARRAY_SIZE(mwifiex_rates),
 };
 
 static struct ieee80211_channel mwifiex_channels_5ghz[] = {
@@ -688,8 +686,8 @@ static struct ieee80211_channel mwifiex_channels_5ghz[] = {
 static struct ieee80211_supported_band mwifiex_band_5ghz = {
        .channels = mwifiex_channels_5ghz,
        .n_channels = ARRAY_SIZE(mwifiex_channels_5ghz),
-       .bitrates = mwifiex_rates - 4,
-       .n_bitrates = ARRAY_SIZE(mwifiex_rates) + 4,
+       .bitrates = mwifiex_rates + 4,
+       .n_bitrates = ARRAY_SIZE(mwifiex_rates) - 4,
 };
 
 
@@ -841,12 +839,12 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid,
                       u8 *bssid, int mode, struct ieee80211_channel *channel,
                       struct cfg80211_connect_params *sme, bool privacy)
 {
-       struct mwifiex_802_11_ssid req_ssid;
+       struct cfg80211_ssid req_ssid;
        int ret, auth_type = 0;
        struct cfg80211_bss *bss = NULL;
        u8 is_scanning_required = 0;
 
-       memset(&req_ssid, 0, sizeof(struct mwifiex_802_11_ssid));
+       memset(&req_ssid, 0, sizeof(struct cfg80211_ssid));
 
        req_ssid.ssid_len = ssid_len;
        if (ssid_len > IEEE80211_MAX_SSID_LEN) {
@@ -872,6 +870,8 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid,
        priv->sec_info.wpa_enabled = false;
        priv->sec_info.wpa2_enabled = false;
        priv->wep_key_curr_index = 0;
+       priv->sec_info.encryption_mode = 0;
+       priv->sec_info.is_authtype_auto = 0;
        ret = mwifiex_set_encode(priv, NULL, 0, 0, 1);
 
        if (mode == NL80211_IFTYPE_ADHOC) {
@@ -893,11 +893,12 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid,
        }
 
        /* Now handle infra mode. "sme" is valid for infra mode only */
-       if (sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC
-                       || sme->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM)
+       if (sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC) {
                auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM;
-       else if (sme->auth_type == NL80211_AUTHTYPE_SHARED_KEY)
-               auth_type = NL80211_AUTHTYPE_SHARED_KEY;
+               priv->sec_info.is_authtype_auto = 1;
+       } else {
+               auth_type = sme->auth_type;
+       }
 
        if (sme->crypto.n_ciphers_pairwise) {
                priv->sec_info.encryption_mode =
@@ -923,12 +924,6 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid,
                }
        }
 done:
-       /* Do specific SSID scanning */
-       if (mwifiex_request_scan(priv, &req_ssid)) {
-               dev_err(priv->adapter->dev, "scan error\n");
-               return -EFAULT;
-       }
-
        /*
         * Scan entries are valid for some time (15 sec). So we can save one
         * active scan time if we just try cfg80211_get_bss first. If it fails
@@ -1111,12 +1106,10 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev,
                dev_err(priv->adapter->dev, "failed to alloc scan_req\n");
                return -ENOMEM;
        }
-       for (i = 0; i < request->n_ssids; i++) {
-               memcpy(priv->user_scan_cfg->ssid_list[i].ssid,
-                       request->ssids[i].ssid, request->ssids[i].ssid_len);
-               priv->user_scan_cfg->ssid_list[i].max_len =
-                       request->ssids[i].ssid_len;
-       }
+
+       priv->user_scan_cfg->num_ssids = request->n_ssids;
+       priv->user_scan_cfg->ssid_list = request->ssids;
+
        for (i = 0; i < request->n_channels; i++) {
                chan = request->channels[i];
                priv->user_scan_cfg->chan_list[i].chan_number = chan->hw_value;
index 6623db69e1571693df899ccd6e26d03c8b92620b..c82eb7ff2fa26bb381626ec8059a3b550a450fe0 100644 (file)
@@ -771,7 +771,7 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
 
        /* Check init command response */
        if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) {
-               if (ret == -1) {
+               if (ret) {
                        dev_err(adapter->dev, "%s: cmd %#x failed during "
                                "initialization\n", __func__, cmdresp_no);
                        mwifiex_init_fw_complete(adapter);
@@ -781,10 +781,8 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
        }
 
        if (adapter->curr_cmd) {
-               if (adapter->curr_cmd->wait_q_enabled && (!ret))
-                       adapter->cmd_wait_q.status = 0;
-               else if (adapter->curr_cmd->wait_q_enabled && (ret == -1))
-                       adapter->cmd_wait_q.status = -1;
+               if (adapter->curr_cmd->wait_q_enabled)
+                       adapter->cmd_wait_q.status = ret;
 
                /* Clean up and put current command back to cmd_free_q */
                mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
index 3735c775495c24d4d0b6ef01e0be55426f71a3b9..be5fd1652e53a3d5930f14c42f4ec77439858373 100644 (file)
@@ -91,11 +91,6 @@ struct mwifiex_fw_image {
        u32 fw_len;
 };
 
-struct mwifiex_802_11_ssid {
-       u32 ssid_len;
-       u8 ssid[IEEE80211_MAX_SSID_LEN];
-};
-
 struct mwifiex_wait_queue {
        wait_queue_head_t wait;
        int status;
index 51c5417c569c42570e0a3300c59529c2c6af767c..fc4ffee6c6b9ce4021a52b94b5a336f4d4207898 100644 (file)
@@ -86,11 +86,6 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
        MWIFIEX_802_11_PRIV_FILTER_8021X_WEP
 };
 
-enum MWIFIEX_802_11_WEP_STATUS {
-       MWIFIEX_802_11_WEP_ENABLED,
-       MWIFIEX_802_11_WEP_DISABLED,
-};
-
 #define CAL_SNR(RSSI, NF)              ((s16)((s16)(RSSI)-(s16)(NF)))
 
 #define PROPRIETARY_TLV_BASE_ID                 0x0100
@@ -857,11 +852,6 @@ struct mwifiex_user_scan_chan {
        u32 scan_time;
 } __packed;
 
-struct mwifiex_user_scan_ssid {
-       u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
-       u8 max_len;
-} __packed;
-
 struct mwifiex_user_scan_cfg {
        /*
         *  BSS mode to be sent in the firmware command
@@ -872,8 +862,9 @@ struct mwifiex_user_scan_cfg {
        u8 reserved;
        /* BSSID filter sent in the firmware command to limit the results */
        u8 specific_bssid[ETH_ALEN];
-       /* SSID filter list used in the to limit the scan results */
-       struct mwifiex_user_scan_ssid ssid_list[MWIFIEX_MAX_SSID_LIST_LENGTH];
+       /* SSID filter list used in the firmware to limit the scan results */
+       struct cfg80211_ssid *ssid_list;
+       u8 num_ssids;
        /* Variable number (fixed maximum) of channels to scan up */
        struct mwifiex_user_scan_chan chan_list[MWIFIEX_USER_SCAN_CHAN_MAX];
 } __packed;
index ca59cc0d013ef7785647a1c6fe075ecf9d5b7556..e81bf6ef1666d3a9c55b8521eef6f34531771099 100644 (file)
@@ -82,7 +82,7 @@ static int mwifiex_init_priv(struct mwifiex_private *priv)
        priv->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR;
        priv->data_avg_factor = DEFAULT_DATA_AVG_FACTOR;
 
-       priv->sec_info.wep_status = MWIFIEX_802_11_WEP_DISABLED;
+       priv->sec_info.wep_enabled = 0;
        priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM;
        priv->sec_info.encryption_mode = 0;
        for (i = 0; i < ARRAY_SIZE(priv->wep_key); i++)
index d5d81f1fe41c9c5b310e21cf0778284a43478f86..7ca4e8234f3ee6512dc9599a6a3d2a3d1bcaa012 100644 (file)
@@ -50,7 +50,7 @@ struct mwifiex_chan_freq {
 };
 
 struct mwifiex_ssid_bssid {
-       struct mwifiex_802_11_ssid ssid;
+       struct cfg80211_ssid ssid;
        u8 bssid[ETH_ALEN];
 };
 
@@ -122,7 +122,7 @@ struct mwifiex_ver_ext {
 
 struct mwifiex_bss_info {
        u32 bss_mode;
-       struct mwifiex_802_11_ssid ssid;
+       struct cfg80211_ssid ssid;
        u32 bss_chan;
        u32 region_code;
        u32 media_connected;
index 0b0eb5efba9dd4206d08b8f79c817319ab4c8037..bce9991612c8cea2a01ec73ac8433165c07c47ed 100644 (file)
@@ -417,7 +417,7 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv,
        auth_tlv = (struct mwifiex_ie_types_auth_type *) pos;
        auth_tlv->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
        auth_tlv->header.len = cpu_to_le16(sizeof(auth_tlv->auth_type));
-       if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED)
+       if (priv->sec_info.wep_enabled)
                auth_tlv->auth_type = cpu_to_le16(
                                (u16) priv->sec_info.authentication_mode);
        else
@@ -585,7 +585,7 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
                       le16_to_cpu(assoc_rsp->cap_info_bitmap),
                       le16_to_cpu(assoc_rsp->a_id));
 
-               ret = -1;
+               ret = le16_to_cpu(assoc_rsp->status_code);
                goto done;
        }
 
@@ -714,7 +714,7 @@ done:
 int
 mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
                                struct host_cmd_ds_command *cmd,
-                               struct mwifiex_802_11_ssid *req_ssid)
+                               struct cfg80211_ssid *req_ssid)
 {
        int rsn_ie_len = 0;
        struct mwifiex_adapter *adapter = priv->adapter;
@@ -1069,8 +1069,7 @@ mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv,
        priv->curr_bss_params.bss_descriptor.channel = bss_desc->channel;
        priv->curr_bss_params.band = (u8) bss_desc->bss_band;
 
-       if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED
-           || priv->sec_info.wpa_enabled)
+       if (priv->sec_info.wep_enabled || priv->sec_info.wpa_enabled)
                tmp_cap |= WLAN_CAPABILITY_PRIVACY;
 
        if (IS_SUPPORT_MULTI_BANDS(priv->adapter)) {
@@ -1246,7 +1245,7 @@ int mwifiex_associate(struct mwifiex_private *priv,
  */
 int
 mwifiex_adhoc_start(struct mwifiex_private *priv,
-                   struct mwifiex_802_11_ssid *adhoc_ssid)
+                   struct cfg80211_ssid *adhoc_ssid)
 {
        dev_dbg(priv->adapter->dev, "info: Adhoc Channel = %d\n",
                priv->adhoc_channel);
index 52810b1497eadbf1718ebc2b24c466c5f8c841db..6dc116647411255741f2157b9063cb070b27bee3 100644 (file)
@@ -217,8 +217,9 @@ struct mwifiex_802_11_security {
        u8 wpa2_enabled;
        u8 wapi_enabled;
        u8 wapi_key_on;
-       enum MWIFIEX_802_11_WEP_STATUS wep_status;
+       u8 wep_enabled;
        u32 authentication_mode;
+       u8 is_authtype_auto;
        u32 encryption_mode;
 };
 
@@ -243,7 +244,7 @@ struct ieee_types_generic {
 
 struct mwifiex_bssdescriptor {
        u8 mac_address[ETH_ALEN];
-       struct mwifiex_802_11_ssid ssid;
+       struct cfg80211_ssid ssid;
        u32 privacy;
        s32 rssi;
        u32 channel;
@@ -387,7 +388,7 @@ struct mwifiex_private {
        s16 bcn_rssi_avg;
        s16 bcn_nf_avg;
        struct mwifiex_bssdescriptor *attempted_bss_desc;
-       struct mwifiex_802_11_ssid prev_ssid;
+       struct cfg80211_ssid prev_ssid;
        u8 prev_bssid[ETH_ALEN];
        struct mwifiex_current_bss_params curr_bss_params;
        u16 beacon_period;
@@ -746,8 +747,7 @@ void mwifiex_queue_scan_cmd(struct mwifiex_private *priv,
                            struct cmd_ctrl_node *cmd_node);
 int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
                            struct host_cmd_ds_command *resp);
-s32 mwifiex_ssid_cmp(struct mwifiex_802_11_ssid *ssid1,
-                      struct mwifiex_802_11_ssid *ssid2);
+s32 mwifiex_ssid_cmp(struct cfg80211_ssid *ssid1, struct cfg80211_ssid *ssid2);
 int mwifiex_associate(struct mwifiex_private *priv,
                      struct mwifiex_bssdescriptor *bss_desc);
 int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv,
@@ -759,12 +759,12 @@ void mwifiex_reset_connect_state(struct mwifiex_private *priv);
 u8 mwifiex_band_to_radio_type(u8 band);
 int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac);
 int mwifiex_adhoc_start(struct mwifiex_private *priv,
-                       struct mwifiex_802_11_ssid *adhoc_ssid);
+                       struct cfg80211_ssid *adhoc_ssid);
 int mwifiex_adhoc_join(struct mwifiex_private *priv,
                       struct mwifiex_bssdescriptor *bss_desc);
 int mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
                                    struct host_cmd_ds_command *cmd,
-                                   struct mwifiex_802_11_ssid *req_ssid);
+                                   struct cfg80211_ssid *req_ssid);
 int mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv,
                                   struct host_cmd_ds_command *cmd,
                                   struct mwifiex_bssdescriptor *bss_desc);
@@ -897,7 +897,7 @@ int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist,
                            struct net_device *dev);
 int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter);
 int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
-                     struct mwifiex_802_11_ssid *req_ssid);
+                     struct cfg80211_ssid *req_ssid);
 int mwifiex_cancel_hs(struct mwifiex_private *priv, int cmd_type);
 int mwifiex_enable_hs(struct mwifiex_adapter *adapter);
 int mwifiex_disable_auto_ds(struct mwifiex_private *priv);
@@ -906,13 +906,12 @@ int mwifiex_get_signal_info(struct mwifiex_private *priv,
 int mwifiex_drv_get_data_rate(struct mwifiex_private *priv,
                              struct mwifiex_rate_cfg *rate);
 int mwifiex_request_scan(struct mwifiex_private *priv,
-                        struct mwifiex_802_11_ssid *req_ssid);
+                        struct cfg80211_ssid *req_ssid);
 int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv,
                                struct mwifiex_user_scan_cfg *scan_req);
-int mwifiex_change_adhoc_chan(struct mwifiex_private *priv, int channel);
 int mwifiex_set_radio(struct mwifiex_private *priv, u8 option);
 
-int mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel);
+int mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, u16 channel);
 
 int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key,
                       int key_len, u8 key_index, int disable);
index 98f1ca9cd6d862cb4169d465c8a20db7d4b202b6..fd0302fe5bd84a9ecc75a77efee5150600a0c9c2 100644 (file)
@@ -163,8 +163,7 @@ mwifiex_is_wpa_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher)
  * This function compares two SSIDs and checks if they match.
  */
 s32
-mwifiex_ssid_cmp(struct mwifiex_802_11_ssid *ssid1,
-                struct mwifiex_802_11_ssid *ssid2)
+mwifiex_ssid_cmp(struct cfg80211_ssid *ssid1, struct cfg80211_ssid *ssid2)
 {
        if (!ssid1 || !ssid2 || (ssid1->ssid_len != ssid2->ssid_len))
                return -1;
@@ -196,9 +195,8 @@ static bool
 mwifiex_is_network_compatible_for_no_sec(struct mwifiex_private *priv,
                                       struct mwifiex_bssdescriptor *bss_desc)
 {
-       if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED
-           && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled
-           && ((!bss_desc->bcn_wpa_ie) ||
+       if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled &&
+           !priv->sec_info.wpa2_enabled && ((!bss_desc->bcn_wpa_ie) ||
                ((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id !=
            WLAN_EID_WPA))
            && ((!bss_desc->bcn_rsn_ie) ||
@@ -219,9 +217,8 @@ static bool
 mwifiex_is_network_compatible_for_static_wep(struct mwifiex_private *priv,
                                       struct mwifiex_bssdescriptor *bss_desc)
 {
-       if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED
-           && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled
-           && bss_desc->privacy) {
+       if (priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled &&
+           !priv->sec_info.wpa2_enabled && bss_desc->privacy) {
                return true;
        }
        return false;
@@ -235,10 +232,9 @@ static bool
 mwifiex_is_network_compatible_for_wpa(struct mwifiex_private *priv,
                                      struct mwifiex_bssdescriptor *bss_desc)
 {
-       if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED
-           && priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled
-           && ((bss_desc->bcn_wpa_ie) && ((*(bss_desc->bcn_wpa_ie)).vend_hdr.
-                                               element_id == WLAN_EID_WPA))
+       if (!priv->sec_info.wep_enabled && priv->sec_info.wpa_enabled &&
+           !priv->sec_info.wpa2_enabled && ((bss_desc->bcn_wpa_ie) &&
+           ((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id == WLAN_EID_WPA))
           /*
            * Privacy bit may NOT be set in some APs like
            * LinkSys WRT54G && bss_desc->privacy
@@ -253,8 +249,7 @@ mwifiex_is_network_compatible_for_wpa(struct mwifiex_private *priv,
                        (bss_desc->bcn_rsn_ie) ?
                        (*(bss_desc->bcn_rsn_ie)).
                        ieee_hdr.element_id : 0,
-                       (priv->sec_info.wep_status ==
-                       MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d",
+                       (priv->sec_info.wep_enabled) ? "e" : "d",
                        (priv->sec_info.wpa_enabled) ? "e" : "d",
                        (priv->sec_info.wpa2_enabled) ? "e" : "d",
                        priv->sec_info.encryption_mode,
@@ -272,10 +267,9 @@ static bool
 mwifiex_is_network_compatible_for_wpa2(struct mwifiex_private *priv,
                                       struct mwifiex_bssdescriptor *bss_desc)
 {
-       if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED
-          && !priv->sec_info.wpa_enabled && priv->sec_info.wpa2_enabled
-          && ((bss_desc->bcn_rsn_ie) && ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.
-                                               element_id == WLAN_EID_RSN))
+       if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled &&
+           priv->sec_info.wpa2_enabled && ((bss_desc->bcn_rsn_ie) &&
+           ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id == WLAN_EID_RSN))
           /*
            * Privacy bit may NOT be set in some APs like
            * LinkSys WRT54G && bss_desc->privacy
@@ -290,8 +284,7 @@ mwifiex_is_network_compatible_for_wpa2(struct mwifiex_private *priv,
                        (bss_desc->bcn_rsn_ie) ?
                        (*(bss_desc->bcn_rsn_ie)).
                        ieee_hdr.element_id : 0,
-                       (priv->sec_info.wep_status ==
-                       MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d",
+                       (priv->sec_info.wep_enabled) ? "e" : "d",
                        (priv->sec_info.wpa_enabled) ? "e" : "d",
                        (priv->sec_info.wpa2_enabled) ? "e" : "d",
                        priv->sec_info.encryption_mode,
@@ -309,10 +302,9 @@ static bool
 mwifiex_is_network_compatible_for_adhoc_aes(struct mwifiex_private *priv,
                                       struct mwifiex_bssdescriptor *bss_desc)
 {
-       if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED
-           && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled
-           && ((!bss_desc->bcn_wpa_ie) || ((*(bss_desc->bcn_wpa_ie)).vend_hdr.
-                  element_id != WLAN_EID_WPA))
+       if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled &&
+           !priv->sec_info.wpa2_enabled && ((!bss_desc->bcn_wpa_ie) ||
+           ((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id != WLAN_EID_WPA))
            && ((!bss_desc->bcn_rsn_ie) || ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.
                   element_id != WLAN_EID_RSN))
            && !priv->sec_info.encryption_mode
@@ -330,10 +322,9 @@ static bool
 mwifiex_is_network_compatible_for_dynamic_wep(struct mwifiex_private *priv,
                                       struct mwifiex_bssdescriptor *bss_desc)
 {
-       if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED
-           && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled
-           && ((!bss_desc->bcn_wpa_ie) || ((*(bss_desc->bcn_wpa_ie)).vend_hdr.
-                  element_id != WLAN_EID_WPA))
+       if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled &&
+           !priv->sec_info.wpa2_enabled && ((!bss_desc->bcn_wpa_ie) ||
+           ((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id != WLAN_EID_WPA))
            && ((!bss_desc->bcn_rsn_ie) || ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.
                   element_id != WLAN_EID_RSN))
            && priv->sec_info.encryption_mode
@@ -468,8 +459,7 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv,
                       (bss_desc->bcn_rsn_ie) ?
                       (*(bss_desc->bcn_rsn_ie)).ieee_hdr.
                       element_id : 0,
-                      (priv->sec_info.wep_status ==
-                               MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d",
+                      (priv->sec_info.wep_enabled) ? "e" : "d",
                       (priv->sec_info.wpa_enabled) ? "e" : "d",
                       (priv->sec_info.wpa2_enabled) ? "e" : "d",
                       priv->sec_info.encryption_mode, bss_desc->privacy);
@@ -747,7 +737,7 @@ mwifiex_scan_setup_scan_config(struct mwifiex_private *priv,
        u16 scan_dur;
        u8 channel;
        u8 radio_type;
-       u32 ssid_idx;
+       int i;
        u8 ssid_filter;
        u8 rates[MWIFIEX_SUPPORTED_RATES];
        u32 rates_size;
@@ -802,14 +792,8 @@ mwifiex_scan_setup_scan_config(struct mwifiex_private *priv,
                       user_scan_in->specific_bssid,
                       sizeof(scan_cfg_out->specific_bssid));
 
-               for (ssid_idx = 0;
-                    ((ssid_idx < ARRAY_SIZE(user_scan_in->ssid_list))
-                     && (*user_scan_in->ssid_list[ssid_idx].ssid
-                         || user_scan_in->ssid_list[ssid_idx].max_len));
-                    ssid_idx++) {
-
-                       ssid_len = strlen(user_scan_in->ssid_list[ssid_idx].
-                                         ssid) + 1;
+               for (i = 0; i < user_scan_in->num_ssids; i++) {
+                       ssid_len = user_scan_in->ssid_list[i].ssid_len;
 
                        wildcard_ssid_tlv =
                                (struct mwifiex_ie_types_wildcard_ssid_params *)
@@ -820,19 +804,26 @@ mwifiex_scan_setup_scan_config(struct mwifiex_private *priv,
                                (u16) (ssid_len + sizeof(wildcard_ssid_tlv->
                                                         max_ssid_length)));
 
-                       /* max_ssid_length = 0 tells firmware to perform
-                          specific scan for the SSID filled */
-                       wildcard_ssid_tlv->max_ssid_length = 0;
+                       /*
+                        * max_ssid_length = 0 tells firmware to perform
+                        * specific scan for the SSID filled, whereas
+                        * max_ssid_length = IEEE80211_MAX_SSID_LEN is for
+                        * wildcard scan.
+                        */
+                       if (ssid_len)
+                               wildcard_ssid_tlv->max_ssid_length = 0;
+                       else
+                               wildcard_ssid_tlv->max_ssid_length =
+                                                       IEEE80211_MAX_SSID_LEN;
 
                        memcpy(wildcard_ssid_tlv->ssid,
-                              user_scan_in->ssid_list[ssid_idx].ssid,
-                              ssid_len);
+                              user_scan_in->ssid_list[i].ssid, ssid_len);
 
                        tlv_pos += (sizeof(wildcard_ssid_tlv->header)
                                + le16_to_cpu(wildcard_ssid_tlv->header.len));
 
-                       dev_dbg(adapter->dev, "info: scan: ssid_list[%d]: %s, %d\n",
-                               ssid_idx, wildcard_ssid_tlv->ssid,
+                       dev_dbg(adapter->dev, "info: scan: ssid[%d]: %s, %d\n",
+                               i, wildcard_ssid_tlv->ssid,
                                wildcard_ssid_tlv->max_ssid_length);
 
                        /* Empty wildcard ssid with a maxlen will match many or
@@ -841,7 +832,6 @@ mwifiex_scan_setup_scan_config(struct mwifiex_private *priv,
                           filtered. */
                        if (!ssid_len && wildcard_ssid_tlv->max_ssid_length)
                                ssid_filter = false;
-
                }
 
                /*
@@ -850,7 +840,7 @@ mwifiex_scan_setup_scan_config(struct mwifiex_private *priv,
                 *  truncate scan results.  That is not an issue with an SSID
                 *  or BSSID filter applied to the scan results in the firmware.
                 */
-               if ((ssid_idx && ssid_filter)
+               if ((i && ssid_filter)
                    || memcmp(scan_cfg_out->specific_bssid, &zero_mac,
                              sizeof(zero_mac)))
                        *filtered_scan = true;
@@ -1860,7 +1850,7 @@ mwifiex_queue_scan_cmd(struct mwifiex_private *priv,
  * firmware, filtered on a specific SSID.
  */
 static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv,
-                                     struct mwifiex_802_11_ssid *req_ssid)
+                                     struct cfg80211_ssid *req_ssid)
 {
        struct mwifiex_adapter *adapter = priv->adapter;
        int ret = 0;
@@ -1886,8 +1876,8 @@ static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv,
                return -ENOMEM;
        }
 
-       memcpy(scan_cfg->ssid_list[0].ssid, req_ssid->ssid,
-              req_ssid->ssid_len);
+       scan_cfg->ssid_list = req_ssid;
+       scan_cfg->num_ssids = 1;
 
        ret = mwifiex_scan_networks(priv, scan_cfg);
 
@@ -1905,7 +1895,7 @@ static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv,
  * scan, depending upon whether an SSID is provided or not.
  */
 int mwifiex_request_scan(struct mwifiex_private *priv,
-                        struct mwifiex_802_11_ssid *req_ssid)
+                        struct cfg80211_ssid *req_ssid)
 {
        int ret;
 
index d7aa21da84d0124fd78a181da4bd7d711094c6eb..b9b59db60454b900087086dc34789adf95cbf0d6 100644 (file)
@@ -101,7 +101,7 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv)
 
        memcpy(&priv->prev_ssid,
               &priv->curr_bss_params.bss_descriptor.ssid,
-              sizeof(struct mwifiex_802_11_ssid));
+              sizeof(struct cfg80211_ssid));
 
        memcpy(priv->prev_bssid,
               priv->curr_bss_params.bss_descriptor.mac_address, ETH_ALEN);
index b0fbf5d4fea0bd6fbc9b8b340339f1db145059ee..0ae1209646c14859e76cc311f3cfdff585b501d8 100644 (file)
@@ -192,7 +192,7 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
  * first.
  */
 int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
-                     struct mwifiex_802_11_ssid *req_ssid)
+                     struct cfg80211_ssid *req_ssid)
 {
        int ret;
        struct mwifiex_adapter *adapter = priv->adapter;
@@ -249,6 +249,17 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
                 * application retrieval */
                priv->assoc_rsp_size = 0;
                ret = mwifiex_associate(priv, bss_desc);
+
+               /* If auth type is auto and association fails using open mode,
+                * try to connect using shared mode */
+               if (ret == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG &&
+                   priv->sec_info.is_authtype_auto &&
+                   priv->sec_info.wep_enabled) {
+                       priv->sec_info.authentication_mode =
+                                               NL80211_AUTHTYPE_SHARED_KEY;
+                       ret = mwifiex_associate(priv, bss_desc);
+               }
+
                if (bss)
                        cfg80211_put_bss(bss);
        } else {
@@ -453,8 +464,7 @@ int mwifiex_get_bss_info(struct mwifiex_private *priv,
 
        info->bss_mode = priv->bss_mode;
 
-       memcpy(&info->ssid, &bss_desc->ssid,
-              sizeof(struct mwifiex_802_11_ssid));
+       memcpy(&info->ssid, &bss_desc->ssid, sizeof(struct cfg80211_ssid));
 
        memcpy(&info->bssid, &bss_desc->mac_address, ETH_ALEN);
 
@@ -471,7 +481,7 @@ int mwifiex_get_bss_info(struct mwifiex_private *priv,
 
        info->bcn_nf_last = priv->bcn_nf_last;
 
-       if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED)
+       if (priv->sec_info.wep_enabled)
                info->wep_status = true;
        else
                info->wep_status = false;
@@ -599,7 +609,7 @@ static int mwifiex_bss_ioctl_ibss_channel(struct mwifiex_private *priv,
  *          - Start/Join the IBSS
  */
 int
-mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel)
+mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, u16 channel)
 {
        int ret;
        struct mwifiex_bss_info bss_info;
@@ -636,7 +646,7 @@ mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel)
        ret = mwifiex_deauthenticate(priv, ssid_bssid.bssid);
 
        ret = mwifiex_bss_ioctl_ibss_channel(priv, HostCmd_ACT_GEN_SET,
-                                            (u16 *) &channel);
+                                            &channel);
 
        /* Do specific SSID scanning */
        if (mwifiex_request_scan(priv, &bss_info.ssid)) {
@@ -1020,7 +1030,7 @@ static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv,
        wep_key = &priv->wep_key[priv->wep_key_curr_index];
        index = encrypt_key->key_index;
        if (encrypt_key->key_disable) {
-               priv->sec_info.wep_status = MWIFIEX_802_11_WEP_DISABLED;
+               priv->sec_info.wep_enabled = 0;
        } else if (!encrypt_key->key_len) {
                /* Copy the required key as the current key */
                wep_key = &priv->wep_key[index];
@@ -1030,7 +1040,7 @@ static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv,
                        return -1;
                }
                priv->wep_key_curr_index = (u16) index;
-               priv->sec_info.wep_status = MWIFIEX_802_11_WEP_ENABLED;
+               priv->sec_info.wep_enabled = 1;
        } else {
                wep_key = &priv->wep_key[index];
                memset(wep_key, 0, sizeof(struct mwifiex_wep_key));
@@ -1040,7 +1050,7 @@ static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv,
                       encrypt_key->key_len);
                wep_key->key_index = index;
                wep_key->key_length = encrypt_key->key_len;
-               priv->sec_info.wep_status = MWIFIEX_802_11_WEP_ENABLED;
+               priv->sec_info.wep_enabled = 1;
        }
        if (wep_key->key_length) {
                /* Send request to firmware */
@@ -1050,7 +1060,7 @@ static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv,
                if (ret)
                        return ret;
        }
-       if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED)
+       if (priv->sec_info.wep_enabled)
                priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE;
        else
                priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE;
index 40f4eb7da7b296e3d01227f625a24f4be401fdd6..ee8af1f047c8834f3f5cf5be4952616b6f44e5f9 100644 (file)
@@ -227,6 +227,7 @@ static int p54_add_interface(struct ieee80211_hw *dev,
                             struct ieee80211_vif *vif)
 {
        struct p54_common *priv = dev->priv;
+       int err;
 
        vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
 
@@ -251,9 +252,9 @@ static int p54_add_interface(struct ieee80211_hw *dev,
        }
 
        memcpy(priv->mac_addr, vif->addr, ETH_ALEN);
-       p54_setup_mac(priv);
+       err = p54_setup_mac(priv);
        mutex_unlock(&priv->conf_mutex);
-       return 0;
+       return err;
 }
 
 static void p54_remove_interface(struct ieee80211_hw *dev,
index b1f51a215792028783223984dec8f0b0ac1a8f17..45df728183fdec6b4bd12017a154103d7069821f 100644 (file)
@@ -624,36 +624,39 @@ static void __devexit p54p_remove(struct pci_dev *pdev)
 }
 
 #ifdef CONFIG_PM
-static int p54p_suspend(struct pci_dev *pdev, pm_message_t state)
+static int p54p_suspend(struct device *device)
 {
-       struct ieee80211_hw *dev = pci_get_drvdata(pdev);
-       struct p54p_priv *priv = dev->priv;
-
-       if (priv->common.mode != NL80211_IFTYPE_UNSPECIFIED) {
-               ieee80211_stop_queues(dev);
-               p54p_stop(dev);
-       }
+       struct pci_dev *pdev = to_pci_dev(device);
 
        pci_save_state(pdev);
-       pci_set_power_state(pdev, pci_choose_state(pdev, state));
+       pci_set_power_state(pdev, PCI_D3hot);
+       pci_disable_device(pdev);
        return 0;
 }
 
-static int p54p_resume(struct pci_dev *pdev)
+static int p54p_resume(struct device *device)
 {
-       struct ieee80211_hw *dev = pci_get_drvdata(pdev);
-       struct p54p_priv *priv = dev->priv;
+       struct pci_dev *pdev = to_pci_dev(device);
+       int err;
 
-       pci_set_power_state(pdev, PCI_D0);
-       pci_restore_state(pdev);
+       err = pci_reenable_device(pdev);
+       if (err)
+               return err;
+       return pci_set_power_state(pdev, PCI_D0);
+}
 
-       if (priv->common.mode != NL80211_IFTYPE_UNSPECIFIED) {
-               p54p_open(dev);
-               ieee80211_wake_queues(dev);
-       }
+static const struct dev_pm_ops p54pci_pm_ops = {
+       .suspend = p54p_suspend,
+       .resume = p54p_resume,
+       .freeze = p54p_suspend,
+       .thaw = p54p_resume,
+       .poweroff = p54p_suspend,
+       .restore = p54p_resume,
+};
 
-       return 0;
-}
+#define P54P_PM_OPS (&p54pci_pm_ops)
+#else
+#define P54P_PM_OPS (NULL)
 #endif /* CONFIG_PM */
 
 static struct pci_driver p54p_driver = {
@@ -661,10 +664,7 @@ static struct pci_driver p54p_driver = {
        .id_table       = p54p_table,
        .probe          = p54p_probe,
        .remove         = __devexit_p(p54p_remove),
-#ifdef CONFIG_PM
-       .suspend        = p54p_suspend,
-       .resume         = p54p_resume,
-#endif /* CONFIG_PM */
+       .driver.pm      = P54P_PM_OPS,
 };
 
 static int __init p54p_init(void)
index 7faed62c63786a629c64cfbd423dc228227e8768..f7929906d4371bd59ccdc0ad14ca6a9d5dff7a39 100644 (file)
@@ -618,19 +618,19 @@ static int __devinit p54spi_probe(struct spi_device *spi)
        ret = spi_setup(spi);
        if (ret < 0) {
                dev_err(&priv->spi->dev, "spi_setup failed");
-               goto err_free_common;
+               goto err_free;
        }
 
        ret = gpio_request(p54spi_gpio_power, "p54spi power");
        if (ret < 0) {
                dev_err(&priv->spi->dev, "power GPIO request failed: %d", ret);
-               goto err_free_common;
+               goto err_free;
        }
 
        ret = gpio_request(p54spi_gpio_irq, "p54spi irq");
        if (ret < 0) {
                dev_err(&priv->spi->dev, "irq GPIO request failed: %d", ret);
-               goto err_free_common;
+               goto err_free_gpio_power;
        }
 
        gpio_direction_output(p54spi_gpio_power, 0);
@@ -641,7 +641,7 @@ static int __devinit p54spi_probe(struct spi_device *spi)
                          priv->spi);
        if (ret < 0) {
                dev_err(&priv->spi->dev, "request_irq() failed");
-               goto err_free_common;
+               goto err_free_gpio_irq;
        }
 
        irq_set_irq_type(gpio_to_irq(p54spi_gpio_irq), IRQ_TYPE_EDGE_RISING);
@@ -673,6 +673,12 @@ static int __devinit p54spi_probe(struct spi_device *spi)
        return 0;
 
 err_free_common:
+       free_irq(gpio_to_irq(p54spi_gpio_irq), spi);
+err_free_gpio_irq:
+       gpio_free(p54spi_gpio_irq);
+err_free_gpio_power:
+       gpio_free(p54spi_gpio_power);
+err_free:
        p54_free_common(priv->hw);
        return ret;
 }
index 42b97bc3847717fa017d923fd840c6c12261bd8a..a08a6f0e4dd118064606754e3fbd3be369d7bee5 100644 (file)
@@ -690,7 +690,7 @@ static void p54_tx_80211_header(struct p54_common *priv, struct sk_buff *skb,
        if (!(info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ))
                *flags |= P54_HDR_FLAG_DATA_OUT_SEQNR;
 
-       if (info->flags & IEEE80211_TX_CTL_POLL_RESPONSE)
+       if (info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER)
                *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL;
 
        if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
index a330c69583d62a07dc935ebef2c617b4ee135496..d66e2980bc27bab54ddd06867a8fccd50f6cfb0c 100644 (file)
@@ -518,7 +518,7 @@ struct rndis_wlan_private {
        __le32 current_command_oid;
 
        /* encryption stuff */
-       int  encr_tx_key_index;
+       u8 encr_tx_key_index;
        struct rndis_wlan_encr_key encr_keys[RNDIS_WLAN_NUM_KEYS];
        int  wpa_version;
 
@@ -634,7 +634,7 @@ static u32 get_bcm4320_power_dbm(struct rndis_wlan_private *priv)
        }
 }
 
-static bool is_wpa_key(struct rndis_wlan_private *priv, int idx)
+static bool is_wpa_key(struct rndis_wlan_private *priv, u8 idx)
 {
        int cipher = priv->encr_keys[idx].cipher;
 
@@ -1350,7 +1350,7 @@ static int set_channel(struct usbnet *usbdev, int channel)
 }
 
 static struct ieee80211_channel *get_current_channel(struct usbnet *usbdev,
-                                                    u16 *beacon_interval)
+                                                    u32 *beacon_period)
 {
        struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
        struct ieee80211_channel *channel;
@@ -1370,14 +1370,14 @@ static struct ieee80211_channel *get_current_channel(struct usbnet *usbdev,
        if (!channel)
                return NULL;
 
-       if (beacon_interval)
-               *beacon_interval = le16_to_cpu(config.beacon_period);
+       if (beacon_period)
+               *beacon_period = le32_to_cpu(config.beacon_period);
        return channel;
 }
 
 /* index must be 0 - N, as per NDIS  */
 static int add_wep_key(struct usbnet *usbdev, const u8 *key, int key_len,
-                                                               int index)
+                                                               u8 index)
 {
        struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
        struct ndis_80211_wep_key ndis_key;
@@ -1387,13 +1387,15 @@ static int add_wep_key(struct usbnet *usbdev, const u8 *key, int key_len,
        netdev_dbg(usbdev->net, "%s(idx: %d, len: %d)\n",
                   __func__, index, key_len);
 
-       if ((key_len != 5 && key_len != 13) || index < 0 || index > 3)
+       if (index >= RNDIS_WLAN_NUM_KEYS)
                return -EINVAL;
 
        if (key_len == 5)
                cipher = WLAN_CIPHER_SUITE_WEP40;
-       else
+       else if (key_len == 13)
                cipher = WLAN_CIPHER_SUITE_WEP104;
+       else
+               return -EINVAL;
 
        memset(&ndis_key, 0, sizeof(ndis_key));
 
@@ -1428,7 +1430,7 @@ static int add_wep_key(struct usbnet *usbdev, const u8 *key, int key_len,
 }
 
 static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len,
-                       int index, const u8 *addr, const u8 *rx_seq,
+                       u8 index, const u8 *addr, const u8 *rx_seq,
                        int seq_len, u32 cipher, __le32 flags)
 {
        struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
@@ -1436,7 +1438,7 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len,
        bool is_addr_ok;
        int ret;
 
-       if (index < 0 || index >= 4) {
+       if (index >= RNDIS_WLAN_NUM_KEYS) {
                netdev_dbg(usbdev->net, "%s(): index out of range (%i)\n",
                           __func__, index);
                return -EINVAL;
@@ -1524,7 +1526,7 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len,
        return 0;
 }
 
-static int restore_key(struct usbnet *usbdev, int key_idx)
+static int restore_key(struct usbnet *usbdev, u8 key_idx)
 {
        struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
        struct rndis_wlan_encr_key key;
@@ -1550,13 +1552,13 @@ static void restore_keys(struct usbnet *usbdev)
                restore_key(usbdev, i);
 }
 
-static void clear_key(struct rndis_wlan_private *priv, int idx)
+static void clear_key(struct rndis_wlan_private *priv, u8 idx)
 {
        memset(&priv->encr_keys[idx], 0, sizeof(priv->encr_keys[idx]));
 }
 
 /* remove_key is for both wep and wpa */
-static int remove_key(struct usbnet *usbdev, int index, const u8 *bssid)
+static int remove_key(struct usbnet *usbdev, u8 index, const u8 *bssid)
 {
        struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
        struct ndis_80211_remove_key remove_key;
@@ -1790,9 +1792,9 @@ static struct ndis_80211_pmkid *remove_pmkid(struct usbnet *usbdev,
                                                struct cfg80211_pmksa *pmksa,
                                                int max_pmkids)
 {
-       int i, len, count, newlen, err;
+       int i, newlen, err;
+       unsigned int count;
 
-       len = le32_to_cpu(pmkids->length);
        count = le32_to_cpu(pmkids->bssid_info_count);
 
        if (count > max_pmkids)
@@ -1831,9 +1833,9 @@ static struct ndis_80211_pmkid *update_pmkid(struct usbnet *usbdev,
                                                struct cfg80211_pmksa *pmksa,
                                                int max_pmkids)
 {
-       int i, err, len, count, newlen;
+       int i, err, newlen;
+       unsigned int count;
 
-       len = le32_to_cpu(pmkids->length);
        count = le32_to_cpu(pmkids->bssid_info_count);
 
        if (count > max_pmkids)
@@ -2683,7 +2685,7 @@ static void rndis_wlan_craft_connected_bss(struct usbnet *usbdev, u8 *bssid,
        s32 signal;
        u64 timestamp;
        u16 capability;
-       u16 beacon_interval = 0;
+       u32 beacon_period = 0;
        __le32 rssi;
        u8 ie_buf[34];
        int len, ret, ie_len;
@@ -2708,7 +2710,7 @@ static void rndis_wlan_craft_connected_bss(struct usbnet *usbdev, u8 *bssid,
        }
 
        /* Get channel and beacon interval */
-       channel = get_current_channel(usbdev, &beacon_interval);
+       channel = get_current_channel(usbdev, &beacon_period);
        if (!channel) {
                netdev_warn(usbdev->net, "%s(): could not get channel.\n",
                                        __func__);
@@ -2738,11 +2740,11 @@ static void rndis_wlan_craft_connected_bss(struct usbnet *usbdev, u8 *bssid,
        netdev_dbg(usbdev->net, "%s(): channel:%d(freq), bssid:[%pM], tsf:%d, "
                "capa:%x, beacon int:%d, resp_ie(len:%d, essid:'%.32s'), "
                "signal:%d\n", __func__, (channel ? channel->center_freq : -1),
-               bssid, (u32)timestamp, capability, beacon_interval, ie_len,
+               bssid, (u32)timestamp, capability, beacon_period, ie_len,
                ssid.essid, signal);
 
        bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid,
-               timestamp, capability, beacon_interval, ie_buf, ie_len,
+               timestamp, capability, beacon_period, ie_buf, ie_len,
                signal, GFP_KERNEL);
        cfg80211_put_bss(bss);
 }
@@ -2755,9 +2757,10 @@ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev)
        struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
        struct ndis_80211_assoc_info *info = NULL;
        u8 bssid[ETH_ALEN];
-       int resp_ie_len, req_ie_len;
+       unsigned int resp_ie_len, req_ie_len;
+       unsigned int offset;
        u8 *req_ie, *resp_ie;
-       int ret, offset;
+       int ret;
        bool roamed = false;
        bool match_bss;
 
@@ -2785,7 +2788,9 @@ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev)
                ret = get_association_info(usbdev, info, CONTROL_BUFFER_SIZE);
                if (!ret) {
                        req_ie_len = le32_to_cpu(info->req_ie_length);
-                       if (req_ie_len > 0) {
+                       if (req_ie_len > CONTROL_BUFFER_SIZE)
+                               req_ie_len = CONTROL_BUFFER_SIZE;
+                       if (req_ie_len != 0) {
                                offset = le32_to_cpu(info->offset_req_ies);
 
                                if (offset > CONTROL_BUFFER_SIZE)
@@ -2799,7 +2804,9 @@ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev)
                        }
 
                        resp_ie_len = le32_to_cpu(info->resp_ie_length);
-                       if (resp_ie_len > 0) {
+                       if (resp_ie_len > CONTROL_BUFFER_SIZE)
+                               resp_ie_len = CONTROL_BUFFER_SIZE;
+                       if (resp_ie_len != 0) {
                                offset = le32_to_cpu(info->offset_resp_ies);
 
                                if (offset > CONTROL_BUFFER_SIZE)
@@ -3038,7 +3045,7 @@ static void rndis_wlan_media_specific_indication(struct usbnet *usbdev,
                        struct rndis_indicate *msg, int buflen)
 {
        struct ndis_80211_status_indication *indication;
-       int len, offset;
+       unsigned int len, offset;
 
        offset = offsetof(struct rndis_indicate, status) +
                        le32_to_cpu(msg->offset);
@@ -3050,7 +3057,7 @@ static void rndis_wlan_media_specific_indication(struct usbnet *usbdev,
                return;
        }
 
-       if (offset + len > buflen) {
+       if (len > buflen || offset > buflen || offset + len > buflen) {
                netdev_info(usbdev->net, "media specific indication, too large to fit to buffer (%i > %i)\n",
                            offset + len, buflen);
                return;
index a0a7854facc08e17a40f04f5eccd0a09a3c68c63..299c3879582da14e12ca00d7f11184da8c61bed7 100644 (file)
@@ -163,7 +163,7 @@ config RT2800USB_RT53XX
        depends on EXPERIMENTAL
        ---help---
          This adds support for rt53xx wireless chipset family to the
-         rt2800pci driver.
+         rt2800usb driver.
          Supported chips: RT5370
 
 config RT2800USB_UNKNOWN
index 06acabd02984cbea2d51d67a762aba3d47d743bd..e5c05d8c74486bf14ca435b0a4634e4ba5ecd050 100644 (file)
@@ -68,6 +68,7 @@
 #define RF3322                         0x000c
 #define RF3053                         0x000d
 #define RF5370                         0x5370
+#define RF5372                         0x5372
 #define RF5390                         0x5390
 
 /*
  * TX_PIN_CFG:
  */
 #define TX_PIN_CFG                     0x1328
+#define TX_PIN_CFG_PA_PE_DISABLE       0xfcfffff0
 #define TX_PIN_CFG_PA_PE_A0_EN         FIELD32(0x00000001)
 #define TX_PIN_CFG_PA_PE_G0_EN         FIELD32(0x00000002)
 #define TX_PIN_CFG_PA_PE_A1_EN         FIELD32(0x00000004)
 #define TX_PIN_CFG_RFTR_POL            FIELD32(0x00020000)
 #define TX_PIN_CFG_TRSW_EN             FIELD32(0x00040000)
 #define TX_PIN_CFG_TRSW_POL            FIELD32(0x00080000)
+#define TX_PIN_CFG_PA_PE_A2_EN         FIELD32(0x01000000)
+#define TX_PIN_CFG_PA_PE_G2_EN         FIELD32(0x02000000)
+#define TX_PIN_CFG_PA_PE_A2_POL                FIELD32(0x04000000)
+#define TX_PIN_CFG_PA_PE_G2_POL                FIELD32(0x08000000)
+#define TX_PIN_CFG_LNA_PE_A2_EN                FIELD32(0x10000000)
+#define TX_PIN_CFG_LNA_PE_G2_EN                FIELD32(0x20000000)
+#define TX_PIN_CFG_LNA_PE_A2_POL       FIELD32(0x40000000)
+#define TX_PIN_CFG_LNA_PE_G2_POL       FIELD32(0x80000000)
 
 /*
  * TX_BAND_CFG: 0x1 use upper 20MHz, 0x0 use lower 20MHz
@@ -1627,6 +1637,7 @@ struct mac_iveiv_entry {
 
 /*
  * H2M_MAILBOX_CSR: Host-to-MCU Mailbox.
+ * CMD_TOKEN: Command id, 0xff disable status reporting.
  */
 #define H2M_MAILBOX_CSR                        0x7010
 #define H2M_MAILBOX_CSR_ARG0           FIELD32(0x000000ff)
@@ -1636,6 +1647,8 @@ struct mac_iveiv_entry {
 
 /*
  * H2M_MAILBOX_CID:
+ * Free slots contain 0xff. MCU will store command's token to lowest free slot.
+ * If all slots are occupied status will be dropped.
  */
 #define H2M_MAILBOX_CID                        0x7014
 #define H2M_MAILBOX_CID_CMD0           FIELD32(0x000000ff)
@@ -1645,6 +1658,7 @@ struct mac_iveiv_entry {
 
 /*
  * H2M_MAILBOX_STATUS:
+ * Command status will be saved to same slot as command id.
  */
 #define H2M_MAILBOX_STATUS             0x701c
 
@@ -2288,6 +2302,12 @@ struct mac_iveiv_entry {
 
 /*
  * MCU mailbox commands.
+ * MCU_SLEEP - go to power-save mode.
+ *             arg1: 1: save as much power as possible, 0: save less power.
+ *             status: 1: success, 2: already asleep,
+ *                     3: maybe MAC is busy so can't finish this task.
+ * MCU_RADIO_OFF
+ *             arg0: 0: do power-saving, NOT turn off radio.
  */
 #define MCU_SLEEP                      0x30
 #define MCU_WAKEUP                     0x31
@@ -2308,7 +2328,10 @@ struct mac_iveiv_entry {
 /*
  * MCU mailbox tokens
  */
-#define TOKEN_WAKUP                    3
+#define TOKEN_SLEEP                    1
+#define TOKEN_RADIO_OFF                        2
+#define TOKEN_WAKEUP                   3
+
 
 /*
  * DMA descriptor defines.
index 772d4aec303ad9661588e661f36229ebb284a75d..474b5b9e6238a151cac006257153eae1c0a80d9e 100644 (file)
@@ -402,7 +402,8 @@ int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev,
 
        if (rt2x00_is_pci(rt2x00dev)) {
                if (rt2x00_rt(rt2x00dev, RT3572) ||
-                   rt2x00_rt(rt2x00dev, RT5390)) {
+                   rt2x00_rt(rt2x00dev, RT5390) ||
+                   rt2x00_rt(rt2x00dev, RT5392)) {
                        rt2800_register_read(rt2x00dev, AUX_CTRL, &reg);
                        rt2x00_set_field32(&reg, AUX_CTRL_FORCE_PCIE_CLK, 1);
                        rt2x00_set_field32(&reg, AUX_CTRL_WAKE_PCIE_EN, 1);
@@ -1989,7 +1990,8 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev,
                                                   r55_nonbt_rev[idx]);
                                rt2800_rfcsr_write(rt2x00dev, 59,
                                                   r59_nonbt_rev[idx]);
-                       } else if (rt2x00_rt(rt2x00dev, RT5390)) {
+                       } else if (rt2x00_rt(rt2x00dev, RT5390) ||
+                                          rt2x00_rt(rt2x00dev, RT5392)) {
                                static const char r59_non_bt[] = {0x8f, 0x8f,
                                        0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8d,
                                        0x8a, 0x88, 0x88, 0x87, 0x87, 0x86};
@@ -2039,6 +2041,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
                rt2800_config_channel_rf3052(rt2x00dev, conf, rf, info);
                break;
        case RF5370:
+       case RF5372:
        case RF5390:
                rt2800_config_channel_rf53xx(rt2x00dev, conf, rf, info);
                break;
@@ -2055,7 +2058,8 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
        rt2800_bbp_write(rt2x00dev, 86, 0);
 
        if (rf->channel <= 14) {
-               if (!rt2x00_rt(rt2x00dev, RT5390)) {
+               if (!rt2x00_rt(rt2x00dev, RT5390) &&
+                       !rt2x00_rt(rt2x00dev, RT5392)) {
                        if (test_bit(CAPABILITY_EXTERNAL_LNA_BG,
                                     &rt2x00dev->cap_flags)) {
                                rt2800_bbp_write(rt2x00dev, 82, 0x62);
@@ -2497,6 +2501,80 @@ void rt2800_gain_calibration(struct rt2x00_dev *rt2x00dev)
 }
 EXPORT_SYMBOL_GPL(rt2800_gain_calibration);
 
+void rt2800_vco_calibration(struct rt2x00_dev *rt2x00dev)
+{
+       u32     tx_pin;
+       u8      rfcsr;
+
+       /*
+        * A voltage-controlled oscillator(VCO) is an electronic oscillator
+        * designed to be controlled in oscillation frequency by a voltage
+        * input. Maybe the temperature will affect the frequency of
+        * oscillation to be shifted. The VCO calibration will be called
+        * periodically to adjust the frequency to be precision.
+       */
+
+       rt2800_register_read(rt2x00dev, TX_PIN_CFG, &tx_pin);
+       tx_pin &= TX_PIN_CFG_PA_PE_DISABLE;
+       rt2800_register_write(rt2x00dev, TX_PIN_CFG, tx_pin);
+
+       switch (rt2x00dev->chip.rf) {
+       case RF2020:
+       case RF3020:
+       case RF3021:
+       case RF3022:
+       case RF3320:
+       case RF3052:
+               rt2800_rfcsr_read(rt2x00dev, 7, &rfcsr);
+               rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1);
+               rt2800_rfcsr_write(rt2x00dev, 7, rfcsr);
+               break;
+       case RF5370:
+       case RF5372:
+       case RF5390:
+               rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr);
+               rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 1);
+               rt2800_rfcsr_write(rt2x00dev, 3, rfcsr);
+               break;
+       default:
+               return;
+       }
+
+       mdelay(1);
+
+       rt2800_register_read(rt2x00dev, TX_PIN_CFG, &tx_pin);
+       if (rt2x00dev->rf_channel <= 14) {
+               switch (rt2x00dev->default_ant.tx_chain_num) {
+               case 3:
+                       rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G2_EN, 1);
+                       /* fall through */
+               case 2:
+                       rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G1_EN, 1);
+                       /* fall through */
+               case 1:
+               default:
+                       rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G0_EN, 1);
+                       break;
+               }
+       } else {
+               switch (rt2x00dev->default_ant.tx_chain_num) {
+               case 3:
+                       rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A2_EN, 1);
+                       /* fall through */
+               case 2:
+                       rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A1_EN, 1);
+                       /* fall through */
+               case 1:
+               default:
+                       rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A0_EN, 1);
+                       break;
+               }
+       }
+       rt2800_register_write(rt2x00dev, TX_PIN_CFG, tx_pin);
+
+}
+EXPORT_SYMBOL_GPL(rt2800_vco_calibration);
+
 static void rt2800_config_retry_limit(struct rt2x00_dev *rt2x00dev,
                                      struct rt2x00lib_conf *libconf)
 {
@@ -2585,7 +2663,8 @@ static u8 rt2800_get_default_vgc(struct rt2x00_dev *rt2x00dev)
                    rt2x00_rt(rt2x00dev, RT3071) ||
                    rt2x00_rt(rt2x00dev, RT3090) ||
                    rt2x00_rt(rt2x00dev, RT3390) ||
-                   rt2x00_rt(rt2x00dev, RT5390))
+                   rt2x00_rt(rt2x00dev, RT5390) ||
+                   rt2x00_rt(rt2x00dev, RT5392))
                        return 0x1c + (2 * rt2x00dev->lna_gain);
                else
                        return 0x2e + rt2x00dev->lna_gain;
@@ -2720,7 +2799,8 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
        } else if (rt2x00_rt(rt2x00dev, RT3572)) {
                rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
                rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
-       } else if (rt2x00_rt(rt2x00dev, RT5390)) {
+       } else if (rt2x00_rt(rt2x00dev, RT5390) ||
+                          rt2x00_rt(rt2x00dev, RT5392)) {
                rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000404);
                rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
                rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
@@ -3096,7 +3176,8 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
                     rt2800_wait_bbp_ready(rt2x00dev)))
                return -EACCES;
 
-       if (rt2x00_rt(rt2x00dev, RT5390)) {
+       if (rt2x00_rt(rt2x00dev, RT5390) ||
+               rt2x00_rt(rt2x00dev, RT5392)) {
                rt2800_bbp_read(rt2x00dev, 4, &value);
                rt2x00_set_field8(&value, BBP4_MAC_IF_CTRL, 1);
                rt2800_bbp_write(rt2x00dev, 4, value);
@@ -3104,19 +3185,22 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
 
        if (rt2800_is_305x_soc(rt2x00dev) ||
            rt2x00_rt(rt2x00dev, RT3572) ||
-           rt2x00_rt(rt2x00dev, RT5390))
+           rt2x00_rt(rt2x00dev, RT5390) ||
+           rt2x00_rt(rt2x00dev, RT5392))
                rt2800_bbp_write(rt2x00dev, 31, 0x08);
 
        rt2800_bbp_write(rt2x00dev, 65, 0x2c);
        rt2800_bbp_write(rt2x00dev, 66, 0x38);
 
-       if (rt2x00_rt(rt2x00dev, RT5390))
+       if (rt2x00_rt(rt2x00dev, RT5390) ||
+               rt2x00_rt(rt2x00dev, RT5392))
                rt2800_bbp_write(rt2x00dev, 68, 0x0b);
 
        if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860C)) {
                rt2800_bbp_write(rt2x00dev, 69, 0x16);
                rt2800_bbp_write(rt2x00dev, 73, 0x12);
-       } else if (rt2x00_rt(rt2x00dev, RT5390)) {
+       } else if (rt2x00_rt(rt2x00dev, RT5390) ||
+                          rt2x00_rt(rt2x00dev, RT5392)) {
                rt2800_bbp_write(rt2x00dev, 69, 0x12);
                rt2800_bbp_write(rt2x00dev, 73, 0x13);
                rt2800_bbp_write(rt2x00dev, 75, 0x46);
@@ -3134,7 +3218,8 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
            rt2x00_rt(rt2x00dev, RT3090) ||
            rt2x00_rt(rt2x00dev, RT3390) ||
            rt2x00_rt(rt2x00dev, RT3572) ||
-           rt2x00_rt(rt2x00dev, RT5390)) {
+           rt2x00_rt(rt2x00dev, RT5390) ||
+           rt2x00_rt(rt2x00dev, RT5392)) {
                rt2800_bbp_write(rt2x00dev, 79, 0x13);
                rt2800_bbp_write(rt2x00dev, 80, 0x05);
                rt2800_bbp_write(rt2x00dev, 81, 0x33);
@@ -3146,64 +3231,88 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
        }
 
        rt2800_bbp_write(rt2x00dev, 82, 0x62);
-       if (rt2x00_rt(rt2x00dev, RT5390))
+       if (rt2x00_rt(rt2x00dev, RT5390) ||
+               rt2x00_rt(rt2x00dev, RT5392))
                rt2800_bbp_write(rt2x00dev, 83, 0x7a);
        else
                rt2800_bbp_write(rt2x00dev, 83, 0x6a);
 
        if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860D))
                rt2800_bbp_write(rt2x00dev, 84, 0x19);
-       else if (rt2x00_rt(rt2x00dev, RT5390))
+       else if (rt2x00_rt(rt2x00dev, RT5390) ||
+                        rt2x00_rt(rt2x00dev, RT5392))
                rt2800_bbp_write(rt2x00dev, 84, 0x9a);
        else
                rt2800_bbp_write(rt2x00dev, 84, 0x99);
 
-       if (rt2x00_rt(rt2x00dev, RT5390))
+       if (rt2x00_rt(rt2x00dev, RT5390) ||
+               rt2x00_rt(rt2x00dev, RT5392))
                rt2800_bbp_write(rt2x00dev, 86, 0x38);
        else
                rt2800_bbp_write(rt2x00dev, 86, 0x00);
 
+       if (rt2x00_rt(rt2x00dev, RT5392))
+               rt2800_bbp_write(rt2x00dev, 88, 0x90);
+
        rt2800_bbp_write(rt2x00dev, 91, 0x04);
 
-       if (rt2x00_rt(rt2x00dev, RT5390))
+       if (rt2x00_rt(rt2x00dev, RT5390) ||
+               rt2x00_rt(rt2x00dev, RT5392))
                rt2800_bbp_write(rt2x00dev, 92, 0x02);
        else
                rt2800_bbp_write(rt2x00dev, 92, 0x00);
 
+       if (rt2x00_rt(rt2x00dev, RT5392)) {
+               rt2800_bbp_write(rt2x00dev, 95, 0x9a);
+               rt2800_bbp_write(rt2x00dev, 98, 0x12);
+       }
+
        if (rt2x00_rt_rev_gte(rt2x00dev, RT3070, REV_RT3070F) ||
            rt2x00_rt_rev_gte(rt2x00dev, RT3071, REV_RT3071E) ||
            rt2x00_rt_rev_gte(rt2x00dev, RT3090, REV_RT3090E) ||
            rt2x00_rt_rev_gte(rt2x00dev, RT3390, REV_RT3390E) ||
            rt2x00_rt(rt2x00dev, RT3572) ||
            rt2x00_rt(rt2x00dev, RT5390) ||
+           rt2x00_rt(rt2x00dev, RT5392) ||
            rt2800_is_305x_soc(rt2x00dev))
                rt2800_bbp_write(rt2x00dev, 103, 0xc0);
        else
                rt2800_bbp_write(rt2x00dev, 103, 0x00);
 
-       if (rt2x00_rt(rt2x00dev, RT5390))
+       if (rt2x00_rt(rt2x00dev, RT5390) ||
+               rt2x00_rt(rt2x00dev, RT5392))
                rt2800_bbp_write(rt2x00dev, 104, 0x92);
 
        if (rt2800_is_305x_soc(rt2x00dev))
                rt2800_bbp_write(rt2x00dev, 105, 0x01);
-       else if (rt2x00_rt(rt2x00dev, RT5390))
+       else if (rt2x00_rt(rt2x00dev, RT5390) ||
+                        rt2x00_rt(rt2x00dev, RT5392))
                rt2800_bbp_write(rt2x00dev, 105, 0x3c);
        else
                rt2800_bbp_write(rt2x00dev, 105, 0x05);
 
        if (rt2x00_rt(rt2x00dev, RT5390))
                rt2800_bbp_write(rt2x00dev, 106, 0x03);
+       else if (rt2x00_rt(rt2x00dev, RT5392))
+               rt2800_bbp_write(rt2x00dev, 106, 0x12);
        else
                rt2800_bbp_write(rt2x00dev, 106, 0x35);
 
-       if (rt2x00_rt(rt2x00dev, RT5390))
+       if (rt2x00_rt(rt2x00dev, RT5390) ||
+               rt2x00_rt(rt2x00dev, RT5392))
                rt2800_bbp_write(rt2x00dev, 128, 0x12);
 
+       if (rt2x00_rt(rt2x00dev, RT5392)) {
+               rt2800_bbp_write(rt2x00dev, 134, 0xd0);
+               rt2800_bbp_write(rt2x00dev, 135, 0xf6);
+       }
+
        if (rt2x00_rt(rt2x00dev, RT3071) ||
            rt2x00_rt(rt2x00dev, RT3090) ||
            rt2x00_rt(rt2x00dev, RT3390) ||
            rt2x00_rt(rt2x00dev, RT3572) ||
-           rt2x00_rt(rt2x00dev, RT5390)) {
+           rt2x00_rt(rt2x00dev, RT5390) ||
+           rt2x00_rt(rt2x00dev, RT5392)) {
                rt2800_bbp_read(rt2x00dev, 138, &value);
 
                rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom);
@@ -3215,7 +3324,8 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
                rt2800_bbp_write(rt2x00dev, 138, value);
        }
 
-       if (rt2x00_rt(rt2x00dev, RT5390)) {
+       if (rt2x00_rt(rt2x00dev, RT5390) ||
+               rt2x00_rt(rt2x00dev, RT5392)) {
                int ant, div_mode;
 
                rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
@@ -3342,13 +3452,15 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
            !rt2x00_rt(rt2x00dev, RT3390) &&
            !rt2x00_rt(rt2x00dev, RT3572) &&
            !rt2x00_rt(rt2x00dev, RT5390) &&
+           !rt2x00_rt(rt2x00dev, RT5392) &&
            !rt2800_is_305x_soc(rt2x00dev))
                return 0;
 
        /*
         * Init RF calibration.
         */
-       if (rt2x00_rt(rt2x00dev, RT5390)) {
+       if (rt2x00_rt(rt2x00dev, RT5390) ||
+               rt2x00_rt(rt2x00dev, RT5392)) {
                rt2800_rfcsr_read(rt2x00dev, 2, &rfcsr);
                rt2x00_set_field8(&rfcsr, RFCSR2_RESCAL_EN, 1);
                rt2800_rfcsr_write(rt2x00dev, 2, rfcsr);
@@ -3566,6 +3678,66 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
                        rt2800_rfcsr_write(rt2x00dev, 61, 0xdd);
                rt2800_rfcsr_write(rt2x00dev, 62, 0x00);
                rt2800_rfcsr_write(rt2x00dev, 63, 0x00);
+       }       else if (rt2x00_rt(rt2x00dev, RT5392)) {
+                       rt2800_rfcsr_write(rt2x00dev, 1, 0x17);
+                       rt2800_rfcsr_write(rt2x00dev, 2, 0x80);
+                       rt2800_rfcsr_write(rt2x00dev, 3, 0x88);
+                       rt2800_rfcsr_write(rt2x00dev, 5, 0x10);
+                       rt2800_rfcsr_write(rt2x00dev, 6, 0xe0);
+                       rt2800_rfcsr_write(rt2x00dev, 7, 0x00);
+                       rt2800_rfcsr_write(rt2x00dev, 10, 0x53);
+                       rt2800_rfcsr_write(rt2x00dev, 11, 0x4a);
+                       rt2800_rfcsr_write(rt2x00dev, 12, 0x46);
+                       rt2800_rfcsr_write(rt2x00dev, 13, 0x9f);
+                       rt2800_rfcsr_write(rt2x00dev, 14, 0x00);
+                       rt2800_rfcsr_write(rt2x00dev, 15, 0x00);
+                       rt2800_rfcsr_write(rt2x00dev, 16, 0x00);
+                       rt2800_rfcsr_write(rt2x00dev, 18, 0x03);
+                       rt2800_rfcsr_write(rt2x00dev, 19, 0x4d);
+                       rt2800_rfcsr_write(rt2x00dev, 20, 0x00);
+                       rt2800_rfcsr_write(rt2x00dev, 21, 0x8d);
+                       rt2800_rfcsr_write(rt2x00dev, 22, 0x20);
+                       rt2800_rfcsr_write(rt2x00dev, 23, 0x0b);
+                       rt2800_rfcsr_write(rt2x00dev, 24, 0x44);
+                       rt2800_rfcsr_write(rt2x00dev, 25, 0x80);
+                       rt2800_rfcsr_write(rt2x00dev, 26, 0x82);
+                       rt2800_rfcsr_write(rt2x00dev, 27, 0x09);
+                       rt2800_rfcsr_write(rt2x00dev, 28, 0x00);
+                       rt2800_rfcsr_write(rt2x00dev, 29, 0x10);
+                       rt2800_rfcsr_write(rt2x00dev, 30, 0x10);
+                       rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
+                       rt2800_rfcsr_write(rt2x00dev, 32, 0x20);
+                       rt2800_rfcsr_write(rt2x00dev, 33, 0xC0);
+                       rt2800_rfcsr_write(rt2x00dev, 34, 0x07);
+                       rt2800_rfcsr_write(rt2x00dev, 35, 0x12);
+                       rt2800_rfcsr_write(rt2x00dev, 36, 0x00);
+                       rt2800_rfcsr_write(rt2x00dev, 37, 0x08);
+                       rt2800_rfcsr_write(rt2x00dev, 38, 0x89);
+                       rt2800_rfcsr_write(rt2x00dev, 39, 0x1b);
+                       rt2800_rfcsr_write(rt2x00dev, 40, 0x0f);
+                       rt2800_rfcsr_write(rt2x00dev, 41, 0xbb);
+                       rt2800_rfcsr_write(rt2x00dev, 42, 0xd5);
+                       rt2800_rfcsr_write(rt2x00dev, 43, 0x9b);
+                       rt2800_rfcsr_write(rt2x00dev, 44, 0x0e);
+                       rt2800_rfcsr_write(rt2x00dev, 45, 0xa2);
+                       rt2800_rfcsr_write(rt2x00dev, 46, 0x73);
+                       rt2800_rfcsr_write(rt2x00dev, 47, 0x0c);
+                       rt2800_rfcsr_write(rt2x00dev, 48, 0x10);
+                       rt2800_rfcsr_write(rt2x00dev, 49, 0x94);
+                       rt2800_rfcsr_write(rt2x00dev, 50, 0x94);
+                       rt2800_rfcsr_write(rt2x00dev, 51, 0x3a);
+                       rt2800_rfcsr_write(rt2x00dev, 52, 0x48);
+                       rt2800_rfcsr_write(rt2x00dev, 53, 0x44);
+                       rt2800_rfcsr_write(rt2x00dev, 54, 0x38);
+                       rt2800_rfcsr_write(rt2x00dev, 55, 0x43);
+                       rt2800_rfcsr_write(rt2x00dev, 56, 0xa1);
+                       rt2800_rfcsr_write(rt2x00dev, 57, 0x00);
+                       rt2800_rfcsr_write(rt2x00dev, 58, 0x39);
+                       rt2800_rfcsr_write(rt2x00dev, 59, 0x07);
+                       rt2800_rfcsr_write(rt2x00dev, 60, 0x45);
+                       rt2800_rfcsr_write(rt2x00dev, 61, 0x91);
+                       rt2800_rfcsr_write(rt2x00dev, 62, 0x39);
+                       rt2800_rfcsr_write(rt2x00dev, 63, 0x07);
        }
 
        if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F)) {
@@ -3639,7 +3811,8 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
        rt2800_bbp_read(rt2x00dev, 25, &drv_data->bbp25);
        rt2800_bbp_read(rt2x00dev, 26, &drv_data->bbp26);
 
-       if (!rt2x00_rt(rt2x00dev, RT5390)) {
+       if (!rt2x00_rt(rt2x00dev, RT5390) &&
+               !rt2x00_rt(rt2x00dev, RT5392)) {
                /*
                 * Set back to initial state
                 */
@@ -3667,7 +3840,8 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
        rt2x00_set_field32(&reg, OPT_14_CSR_BIT0, 1);
        rt2800_register_write(rt2x00dev, OPT_14_CSR, reg);
 
-       if (!rt2x00_rt(rt2x00dev, RT5390)) {
+       if (!rt2x00_rt(rt2x00dev, RT5390) &&
+               !rt2x00_rt(rt2x00dev, RT5392)) {
                rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr);
                rt2x00_set_field8(&rfcsr, RFCSR17_TX_LO1_EN, 0);
                if (rt2x00_rt(rt2x00dev, RT3070) ||
@@ -3732,7 +3906,8 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
                rt2800_rfcsr_write(rt2x00dev, 27, rfcsr);
        }
 
-       if (rt2x00_rt(rt2x00dev, RT5390)) {
+       if (rt2x00_rt(rt2x00dev, RT5390) ||
+               rt2x00_rt(rt2x00dev, RT5392)) {
                rt2800_rfcsr_read(rt2x00dev, 38, &rfcsr);
                rt2x00_set_field8(&rfcsr, RFCSR38_RX_LO1_EN, 0);
                rt2800_rfcsr_write(rt2x00dev, 38, rfcsr);
@@ -4033,7 +4208,8 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
         * RT53xx: defined in "EEPROM_CHIP_ID" field
         */
        rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
-       if (rt2x00_get_field32(reg, MAC_CSR0_CHIPSET) == RT5390)
+       if (rt2x00_get_field32(reg, MAC_CSR0_CHIPSET) == RT5390 ||
+               rt2x00_get_field32(reg, MAC_CSR0_CHIPSET) == RT5392)
                rt2x00_eeprom_read(rt2x00dev, EEPROM_CHIP_ID, &value);
        else
                value = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RF_TYPE);
@@ -4051,9 +4227,10 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
        case RT3390:
        case RT3572:
        case RT5390:
+       case RT5392:
                break;
        default:
-               ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
+               ERROR(rt2x00dev, "Invalid RT chipset 0x%04x detected.\n", rt2x00dev->chip.rt);
                return -ENODEV;
        }
 
@@ -4069,10 +4246,11 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
        case RF3052:
        case RF3320:
        case RF5370:
+       case RF5372:
        case RF5390:
                break;
        default:
-               ERROR(rt2x00dev, "Invalid RF chipset 0x%x detected.\n",
+               ERROR(rt2x00dev, "Invalid RF chipset 0x%04x detected.\n",
                      rt2x00dev->chip.rf);
                return -ENODEV;
        }
@@ -4375,6 +4553,7 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
                   rt2x00_rf(rt2x00dev, RF3022) ||
                   rt2x00_rf(rt2x00dev, RF3320) ||
                   rt2x00_rf(rt2x00dev, RF5370) ||
+                  rt2x00_rf(rt2x00dev, RF5372) ||
                   rt2x00_rf(rt2x00dev, RF5390)) {
                spec->num_channels = 14;
                spec->channels = rf_vals_3x;
@@ -4451,6 +4630,20 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
                }
        }
 
+       switch (rt2x00dev->chip.rf) {
+       case RF2020:
+       case RF3020:
+       case RF3021:
+       case RF3022:
+       case RF3320:
+       case RF3052:
+       case RF5370:
+       case RF5372:
+       case RF5390:
+               __set_bit(CAPABILITY_VCO_RECALIBRATION, &rt2x00dev->cap_flags);
+               break;
+       }
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(rt2800_probe_hw_mode);
index 8c3c281904fe7f4a08a4e9c16100920ea502e022..419e36cb06be3d393ec036ccc614414e4e3f2ddc 100644 (file)
@@ -184,6 +184,7 @@ void rt2800_reset_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual);
 void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual,
                       const u32 count);
 void rt2800_gain_calibration(struct rt2x00_dev *rt2x00dev);
+void rt2800_vco_calibration(struct rt2x00_dev *rt2x00dev);
 
 int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev);
 void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev);
index 6ad692914ee953c1950a763b60ccdbd36af98e56..9375db455456f316145e824db4957b46373726b9 100644 (file)
@@ -480,7 +480,8 @@ static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev)
 
        if (rt2x00_is_pcie(rt2x00dev) &&
            (rt2x00_rt(rt2x00dev, RT3572) ||
-            rt2x00_rt(rt2x00dev, RT5390))) {
+            rt2x00_rt(rt2x00dev, RT5390) ||
+            rt2x00_rt(rt2x00dev, RT5392))) {
                rt2x00pci_register_read(rt2x00dev, AUX_CTRL, &reg);
                rt2x00_set_field32(&reg, AUX_CTRL_FORCE_PCIE_CLK, 1);
                rt2x00_set_field32(&reg, AUX_CTRL_WAKE_PCIE_EN, 1);
@@ -501,11 +502,27 @@ static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev)
 
 static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev)
 {
+       int retval;
+
        if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev) ||
                     rt2800pci_init_queues(rt2x00dev)))
                return -EIO;
 
-       return rt2800_enable_radio(rt2x00dev);
+       retval = rt2800_enable_radio(rt2x00dev);
+       if (retval)
+               return retval;
+
+       /* After resume MCU_BOOT_SIGNAL will trash these. */
+       rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0);
+       rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
+
+       rt2800_mcu_request(rt2x00dev, MCU_SLEEP, TOKEN_RADIO_OFF, 0xff, 0x02);
+       rt2800pci_mcu_status(rt2x00dev, TOKEN_RADIO_OFF);
+
+       rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKEUP, 0, 0);
+       rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKEUP);
+
+       return retval;
 }
 
 static void rt2800pci_disable_radio(struct rt2x00_dev *rt2x00dev)
@@ -521,14 +538,16 @@ static int rt2800pci_set_state(struct rt2x00_dev *rt2x00dev,
                               enum dev_state state)
 {
        if (state == STATE_AWAKE) {
-               rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKUP, 0, 0x02);
-               rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKUP);
+               rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKEUP,
+                                  0, 0x02);
+               rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKEUP);
        } else if (state == STATE_SLEEP) {
                rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_STATUS,
                                         0xffffffff);
                rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID,
                                         0xffffffff);
-               rt2800_mcu_request(rt2x00dev, MCU_SLEEP, 0x01, 0xff, 0x01);
+               rt2800_mcu_request(rt2x00dev, MCU_SLEEP, TOKEN_SLEEP,
+                                  0xff, 0x01);
        }
 
        return 0;
@@ -541,13 +560,6 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev,
 
        switch (state) {
        case STATE_RADIO_ON:
-               /*
-                * Before the radio can be enabled, the device first has
-                * to be woken up. After that it needs a bit of time
-                * to be fully awake and then the radio can be enabled.
-                */
-               rt2800pci_set_state(rt2x00dev, STATE_AWAKE);
-               msleep(1);
                retval = rt2800pci_enable_radio(rt2x00dev);
                break;
        case STATE_RADIO_OFF:
@@ -1050,6 +1062,7 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
        .reset_tuner            = rt2800_reset_tuner,
        .link_tuner             = rt2800_link_tuner,
        .gain_calibration       = rt2800_gain_calibration,
+       .vco_calibration        = rt2800_vco_calibration,
        .start_queue            = rt2800pci_start_queue,
        .kick_queue             = rt2800pci_kick_queue,
        .stop_queue             = rt2800pci_stop_queue,
index d009b6b794bb99641d084cfeeb176ffe23864738..2c11137c1eb0dbf2bcfe8bf04dbc0cd5d68ad47d 100644 (file)
@@ -781,6 +781,7 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
        .reset_tuner            = rt2800_reset_tuner,
        .link_tuner             = rt2800_link_tuner,
        .gain_calibration       = rt2800_gain_calibration,
+       .vco_calibration        = rt2800_vco_calibration,
        .watchdog               = rt2800usb_watchdog,
        .start_queue            = rt2800usb_start_queue,
        .kick_queue             = rt2x00usb_kick_queue,
@@ -921,6 +922,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x07d1, 0x3c13) },
        { USB_DEVICE(0x07d1, 0x3c15) },
        { USB_DEVICE(0x07d1, 0x3c16) },
+       { USB_DEVICE(0x2001, 0x3c1b) },
        /* Draytek */
        { USB_DEVICE(0x07fa, 0x7712) },
        /* DVICO */
@@ -1100,12 +1102,26 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x5a57, 0x0284) },
 #endif
 #ifdef CONFIG_RT2800USB_RT53XX
+       /* Alpha */
+       { USB_DEVICE(0x2001, 0x3c15) },
+       { USB_DEVICE(0x2001, 0x3c19) },
+       /* Arcadyan */
+       { USB_DEVICE(0x043e, 0x7a12) },
        /* Azurewave */
        { USB_DEVICE(0x13d3, 0x3329) },
        { USB_DEVICE(0x13d3, 0x3365) },
+       /* LG innotek */
+       { USB_DEVICE(0x043e, 0x7a22) },
+       /* Panasonic */
+       { USB_DEVICE(0x04da, 0x1801) },
+       { USB_DEVICE(0x04da, 0x1800) },
+       /* Philips */
+       { USB_DEVICE(0x0471, 0x2104) },
        /* Ralink */
        { USB_DEVICE(0x148f, 0x5370) },
        { USB_DEVICE(0x148f, 0x5372) },
+       /* Unknown */
+       { USB_DEVICE(0x04da, 0x23f6) },
 #endif
 #ifdef CONFIG_RT2800USB_UNKNOWN
        /*
index ed2ae6efcaa3f9dddfbf7b245d06cae345d2e291..65275efcf279f3c2cd05739fa839f45dfc392f89 100644 (file)
@@ -192,6 +192,7 @@ struct rt2x00_chip {
 #define RT3593         0x3593
 #define RT3883         0x3883  /* WSOC */
 #define RT5390         0x5390  /* 2.4GHz */
+#define RT5392         0x5392  /* 2.4GHz */
 
        u16 rf;
        u16 rev;
@@ -355,6 +356,11 @@ struct link {
         * Work structure for scheduling periodic AGC adjustments.
         */
        struct delayed_work agc_work;
+
+       /*
+        * Work structure for scheduling periodic VCO calibration.
+        */
+       struct delayed_work vco_work;
 };
 
 enum rt2x00_delayed_flags {
@@ -579,6 +585,7 @@ struct rt2x00lib_ops {
        void (*link_tuner) (struct rt2x00_dev *rt2x00dev,
                            struct link_qual *qual, const u32 count);
        void (*gain_calibration) (struct rt2x00_dev *rt2x00dev);
+       void (*vco_calibration) (struct rt2x00_dev *rt2x00dev);
 
        /*
         * Data queue handlers.
@@ -722,6 +729,7 @@ enum rt2x00_capability_flags {
        CAPABILITY_EXTERNAL_LNA_BG,
        CAPABILITY_DOUBLE_ANTENNA,
        CAPABILITY_BT_COEXIST,
+       CAPABILITY_VCO_RECALIBRATION,
 };
 
 /*
@@ -977,6 +985,11 @@ struct rt2x00_dev {
        struct tasklet_struct rxdone_tasklet;
        struct tasklet_struct autowake_tasklet;
 
+       /*
+        * Used for VCO periodic calibration.
+        */
+       int rf_channel;
+
        /*
         * Protect the interrupt mask register.
         */
index b704e5b183d0bc539e8bec6d08776774854d5479..d7c0f86c9e435bfab86fc620c5ac6d49e5433784 100644 (file)
@@ -232,6 +232,9 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
                memcpy(&libconf.channel,
                       &rt2x00dev->spec.channels_info[hw_value],
                       sizeof(libconf.channel));
+
+               /* Used for VCO periodic calibration */
+               rt2x00dev->rf_channel = libconf.rf.channel;
        }
 
        if (test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) &&
index d62e64fe0b926a7c4a1bdf752290ae0848d60e5b..49a51b4195ef7a4a652a428c75cab5d8e2887f26 100644 (file)
@@ -88,6 +88,8 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
        rt2x00queue_start_queues(rt2x00dev);
        rt2x00link_start_tuner(rt2x00dev);
        rt2x00link_start_agc(rt2x00dev);
+       if (test_bit(CAPABILITY_VCO_RECALIBRATION, &rt2x00dev->cap_flags))
+               rt2x00link_start_vcocal(rt2x00dev);
 
        /*
         * Start watchdog monitoring.
@@ -111,6 +113,8 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev)
         * Stop all queues
         */
        rt2x00link_stop_agc(rt2x00dev);
+       if (test_bit(CAPABILITY_VCO_RECALIBRATION, &rt2x00dev->cap_flags))
+               rt2x00link_stop_vcocal(rt2x00dev);
        rt2x00link_stop_tuner(rt2x00dev);
        rt2x00queue_stop_queues(rt2x00dev);
        rt2x00queue_flush_queues(rt2x00dev, true);
index 4cdf247a870d6e21dbc5557e1e1aad18fa4253c7..78bd43b8961f74f1df8c89178faa5457482f6714 100644 (file)
@@ -33,6 +33,7 @@
 #define WATCHDOG_INTERVAL      round_jiffies_relative(HZ)
 #define LINK_TUNE_INTERVAL     round_jiffies_relative(HZ)
 #define AGC_INTERVAL           round_jiffies_relative(4 * HZ)
+#define VCO_INTERVAL           round_jiffies_relative(10 * HZ) /* 10 sec */
 
 /*
  * rt2x00_rate: Per rate device information
@@ -277,12 +278,24 @@ void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev);
  */
 void rt2x00link_start_agc(struct rt2x00_dev *rt2x00dev);
 
+/**
+ * rt2x00link_start_vcocal - Start periodic VCO calibration
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ */
+void rt2x00link_start_vcocal(struct rt2x00_dev *rt2x00dev);
+
 /**
  * rt2x00link_stop_agc - Stop periodic gain calibration
  * @rt2x00dev: Pointer to &struct rt2x00_dev.
  */
 void rt2x00link_stop_agc(struct rt2x00_dev *rt2x00dev);
 
+/**
+ * rt2x00link_stop_vcocal - Stop periodic VCO calibration
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ */
+void rt2x00link_stop_vcocal(struct rt2x00_dev *rt2x00dev);
+
 /**
  * rt2x00link_register - Initialize link tuning & watchdog functionality
  * @rt2x00dev: Pointer to &struct rt2x00_dev.
index ea10b0068f823f503e827f45d9e4c52dd9f8a74f..8368aab86f286ee6ff5be65b85a73940f3c24cd0 100644 (file)
@@ -447,11 +447,27 @@ void rt2x00link_start_agc(struct rt2x00_dev *rt2x00dev)
                                             AGC_INTERVAL);
 }
 
+void rt2x00link_start_vcocal(struct rt2x00_dev *rt2x00dev)
+{
+       struct link *link = &rt2x00dev->link;
+
+       if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
+           rt2x00dev->ops->lib->vco_calibration)
+               ieee80211_queue_delayed_work(rt2x00dev->hw,
+                                            &link->vco_work,
+                                            VCO_INTERVAL);
+}
+
 void rt2x00link_stop_agc(struct rt2x00_dev *rt2x00dev)
 {
        cancel_delayed_work_sync(&rt2x00dev->link.agc_work);
 }
 
+void rt2x00link_stop_vcocal(struct rt2x00_dev *rt2x00dev)
+{
+       cancel_delayed_work_sync(&rt2x00dev->link.vco_work);
+}
+
 static void rt2x00link_agc(struct work_struct *work)
 {
        struct rt2x00_dev *rt2x00dev =
@@ -473,9 +489,32 @@ static void rt2x00link_agc(struct work_struct *work)
                                             AGC_INTERVAL);
 }
 
+static void rt2x00link_vcocal(struct work_struct *work)
+{
+       struct rt2x00_dev *rt2x00dev =
+           container_of(work, struct rt2x00_dev, link.vco_work.work);
+       struct link *link = &rt2x00dev->link;
+
+       /*
+        * When the radio is shutting down we should
+        * immediately cease the VCO calibration.
+        */
+       if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+               return;
+
+       rt2x00dev->ops->lib->vco_calibration(rt2x00dev);
+
+       if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
+               ieee80211_queue_delayed_work(rt2x00dev->hw,
+                                            &link->vco_work,
+                                            VCO_INTERVAL);
+}
+
 void rt2x00link_register(struct rt2x00_dev *rt2x00dev)
 {
        INIT_DELAYED_WORK(&rt2x00dev->link.agc_work, rt2x00link_agc);
+       if (test_bit(CAPABILITY_VCO_RECALIBRATION, &rt2x00dev->cap_flags))
+               INIT_DELAYED_WORK(&rt2x00dev->link.vco_work, rt2x00link_vcocal);
        INIT_DELAYED_WORK(&rt2x00dev->link.watchdog_work, rt2x00link_watchdog);
        INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00link_tuner);
 }
index 638fbef693e676372e39c2f20d7a2e7127c1a083..cf53ac9d6f23f2787561883f15985a974abb7f8d 100644 (file)
@@ -8,7 +8,7 @@
  * Copyright 2005 Andrea Merello <andreamrl@tiscali.it>, et al.
  *
  * The driver was extended to the RTL8187B in 2008 by:
- *     Herton Ronaldo Krzesinski <herton@mandriva.com.br>
+ *     Herton Ronaldo Krzesinski <herton@mandriva.com.br>
  *     Hin-Tak Leung <htl10@users.sourceforge.net>
  *     Larry Finger <Larry.Finger@lwfinger.net>
  *
@@ -232,6 +232,7 @@ static void rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
        struct rtl8187_priv *priv = dev->priv;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_hdr *tx_hdr =  (struct ieee80211_hdr *)(skb->data);
        unsigned int ep;
        void *buf;
        struct urb *urb;
@@ -249,7 +250,7 @@ static void rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
        flags |= RTL818X_TX_DESC_FLAG_NO_ENC;
 
        flags |= ieee80211_get_tx_rate(dev, info)->hw_value << 24;
-       if (ieee80211_has_morefrags(((struct ieee80211_hdr *)skb->data)->frame_control))
+       if (ieee80211_has_morefrags(tx_hdr->frame_control))
                flags |= RTL818X_TX_DESC_FLAG_MOREFRAG;
        if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
                flags |= RTL818X_TX_DESC_FLAG_RTS;
@@ -261,6 +262,13 @@ static void rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
                flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
        }
 
+       if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
+               if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
+                       priv->seqno += 0x10;
+               tx_hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
+               tx_hdr->seq_ctrl |= cpu_to_le16(priv->seqno);
+       }
+
        if (!priv->is_rtl8187b) {
                struct rtl8187_tx_hdr *hdr =
                        (struct rtl8187_tx_hdr *)skb_push(skb, sizeof(*hdr));
@@ -274,8 +282,6 @@ static void rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
        } else {
                /* fc needs to be calculated before skb_push() */
                unsigned int epmap[4] = { 6, 7, 5, 4 };
-               struct ieee80211_hdr *tx_hdr =
-                       (struct ieee80211_hdr *)(skb->data);
                u16 fc = le16_to_cpu(tx_hdr->frame_control);
 
                struct rtl8187b_tx_hdr *hdr =
@@ -1031,10 +1037,61 @@ static void rtl8187_stop(struct ieee80211_hw *dev)
                cancel_delayed_work_sync(&priv->work);
 }
 
+static u64 rtl8187_get_tsf(struct ieee80211_hw *dev, struct ieee80211_vif *vif)
+{
+       struct rtl8187_priv *priv = dev->priv;
+
+       return rtl818x_ioread32(priv, &priv->map->TSFT[0]) |
+              (u64)(rtl818x_ioread32(priv, &priv->map->TSFT[1])) << 32;
+}
+
+
+static void rtl8187_beacon_work(struct work_struct *work)
+{
+       struct rtl8187_vif *vif_priv =
+               container_of(work, struct rtl8187_vif, beacon_work.work);
+       struct ieee80211_vif *vif =
+               container_of((void *)vif_priv, struct ieee80211_vif, drv_priv);
+       struct ieee80211_hw *dev = vif_priv->dev;
+       struct ieee80211_mgmt *mgmt;
+       struct sk_buff *skb;
+
+       /* don't overflow the tx ring */
+       if (ieee80211_queue_stopped(dev, 0))
+               goto resched;
+
+       /* grab a fresh beacon */
+       skb = ieee80211_beacon_get(dev, vif);
+       if (!skb)
+               goto resched;
+
+       /*
+        * update beacon timestamp w/ TSF value
+        * TODO: make hardware update beacon timestamp
+        */
+       mgmt = (struct ieee80211_mgmt *)skb->data;
+       mgmt->u.beacon.timestamp = cpu_to_le64(rtl8187_get_tsf(dev, vif));
+
+       /* TODO: use actual beacon queue */
+       skb_set_queue_mapping(skb, 0);
+
+       rtl8187_tx(dev, skb);
+
+resched:
+       /*
+        * schedule next beacon
+        * TODO: use hardware support for beacon timing
+        */
+       schedule_delayed_work(&vif_priv->beacon_work,
+                       usecs_to_jiffies(1024 * vif->bss_conf.beacon_int));
+}
+
+
 static int rtl8187_add_interface(struct ieee80211_hw *dev,
                                 struct ieee80211_vif *vif)
 {
        struct rtl8187_priv *priv = dev->priv;
+       struct rtl8187_vif *vif_priv;
        int i;
        int ret = -EOPNOTSUPP;
 
@@ -1044,6 +1101,7 @@ static int rtl8187_add_interface(struct ieee80211_hw *dev,
 
        switch (vif->type) {
        case NL80211_IFTYPE_STATION:
+       case NL80211_IFTYPE_ADHOC:
                break;
        default:
                goto exit;
@@ -1052,6 +1110,13 @@ static int rtl8187_add_interface(struct ieee80211_hw *dev,
        ret = 0;
        priv->vif = vif;
 
+       /* Initialize driver private area */
+       vif_priv = (struct rtl8187_vif *)&vif->drv_priv;
+       vif_priv->dev = dev;
+       INIT_DELAYED_WORK(&vif_priv->beacon_work, rtl8187_beacon_work);
+       vif_priv->enable_beacon = false;
+
+
        rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
        for (i = 0; i < ETH_ALEN; i++)
                rtl818x_iowrite8(priv, &priv->map->MAC[i],
@@ -1175,9 +1240,12 @@ static void rtl8187_bss_info_changed(struct ieee80211_hw *dev,
                                     u32 changed)
 {
        struct rtl8187_priv *priv = dev->priv;
+       struct rtl8187_vif *vif_priv;
        int i;
        u8 reg;
 
+       vif_priv = (struct rtl8187_vif *)&vif->drv_priv;
+
        if (changed & BSS_CHANGED_BSSID) {
                mutex_lock(&priv->conf_mutex);
                for (i = 0; i < ETH_ALEN; i++)
@@ -1189,8 +1257,12 @@ static void rtl8187_bss_info_changed(struct ieee80211_hw *dev,
                else
                        reg = 0;
 
-               if (is_valid_ether_addr(info->bssid))
-                       reg |= RTL818X_MSR_INFRA;
+               if (is_valid_ether_addr(info->bssid)) {
+                       if (vif->type == NL80211_IFTYPE_ADHOC)
+                               reg |= RTL818X_MSR_ADHOC;
+                       else
+                               reg |= RTL818X_MSR_INFRA;
+               }
                else
                        reg |= RTL818X_MSR_NO_LINK;
 
@@ -1202,6 +1274,16 @@ static void rtl8187_bss_info_changed(struct ieee80211_hw *dev,
        if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_ERP_PREAMBLE))
                rtl8187_conf_erp(priv, info->use_short_slot,
                                 info->use_short_preamble);
+
+       if (changed & BSS_CHANGED_BEACON_ENABLED)
+               vif_priv->enable_beacon = info->enable_beacon;
+
+       if (changed & (BSS_CHANGED_BEACON_ENABLED | BSS_CHANGED_BEACON)) {
+               cancel_delayed_work_sync(&vif_priv->beacon_work);
+               if (vif_priv->enable_beacon)
+                       schedule_work(&vif_priv->beacon_work.work);
+       }
+
 }
 
 static u64 rtl8187_prepare_multicast(struct ieee80211_hw *dev,
@@ -1279,13 +1361,6 @@ static int rtl8187_conf_tx(struct ieee80211_hw *dev,
        return 0;
 }
 
-static u64 rtl8187_get_tsf(struct ieee80211_hw *dev, struct ieee80211_vif *vif)
-{
-       struct rtl8187_priv *priv = dev->priv;
-
-       return rtl818x_ioread32(priv, &priv->map->TSFT[0]) |
-              (u64)(rtl818x_ioread32(priv, &priv->map->TSFT[1])) << 32;
-}
 
 static const struct ieee80211_ops rtl8187_ops = {
        .tx                     = rtl8187_tx,
@@ -1514,12 +1589,9 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
                if (reg & 0xFF00)
                        priv->rfkill_mask = RFKILL_MASK_8198;
        }
-
-       /*
-        * XXX: Once this driver supports anything that requires
-        *      beacons it must implement IEEE80211_TX_CTL_ASSIGN_SEQ.
-        */
-       dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+       dev->vif_data_size = sizeof(struct rtl8187_vif);
+       dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+                                     BIT(NL80211_IFTYPE_ADHOC) ;
 
        if ((id->driver_info == DEVICE_RTL8187) && priv->is_rtl8187b)
                printk(KERN_INFO "rtl8187: inconsistency between id with OEM"
index f1cc90751dbf519a576f5baee035e94aa183e378..e19a20a8e9558f38549df067334ad1b8ce81b793 100644 (file)
@@ -89,6 +89,14 @@ enum {
        DEVICE_RTL8187B
 };
 
+struct rtl8187_vif {
+       struct ieee80211_hw *dev;
+
+       /* beaconing */
+       struct delayed_work beacon_work;
+       bool enable_beacon;
+};
+
 struct rtl8187_priv {
        /* common between rtl818x drivers */
        struct rtl818x_csr *map;
@@ -141,6 +149,7 @@ struct rtl8187_priv {
                __le32 bits32;
        } *io_dmabuf;
        bool rfkill_off;
+       u16 seqno;
 };
 
 void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data);
index 44b9c0a57702dcdb37584ef4f099e8e6d093a461..cefac6a43601e17ca6ca9ef6db36589e7d055daf 100644 (file)
@@ -50,7 +50,7 @@ config RTLWIFI
        default m
 
 config RTLWIFI_DEBUG
-       tristate "Additional debugging output"
+       bool "Additional debugging output"
        depends on RTL8192CE || RTL8192CU || RTL8192SE || RTL8192DE
        default y
 
index df5655cc55c0a315f768073e994695d79043ffa6..510023554e5f43ba0105a2cd5de09e8987b861dd 100644 (file)
 #include <linux/module.h>
 
 /*
- *NOTICE!!!: This file will be very big, we hsould
- *keep it clear under follwing roles:
+ *NOTICE!!!: This file will be very big, we should
+ *keep it clear under following roles:
  *
- *This file include follwing part, so, if you add new
+ *This file include following parts, so, if you add new
  *functions into this file, please check which part it
  *should includes. or check if you should add new part
  *for this file:
index a64473556ea8ac5348c2240ef87b42875e7248f0..1208b753f62f30aaf24ed88ec7cd9d6014b46d76 100644 (file)
@@ -520,6 +520,10 @@ void rtl92c_dm_write_dig(struct ieee80211_hw *hw)
                 dm_digtable.cur_igvalue, dm_digtable.pre_igvalue,
                 dm_digtable.backoff_val);
 
+       dm_digtable.cur_igvalue += 2;
+       if (dm_digtable.cur_igvalue > 0x3f)
+               dm_digtable.cur_igvalue = 0x3f;
+
        if (dm_digtable.pre_igvalue != dm_digtable.cur_igvalue) {
                rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f,
                              dm_digtable.cur_igvalue);
@@ -1201,13 +1205,18 @@ static void rtl92c_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw)
                                 "PreState = %d, CurState = %d\n",
                                 p_ra->pre_ratr_state, p_ra->ratr_state);
 
-                       rcu_read_lock();
-                       sta = ieee80211_find_sta(mac->vif, mac->bssid);
+                       /* Only the PCI card uses sta in the update rate table
+                        * callback routine */
+                       if (rtlhal->interface == INTF_PCI) {
+                               rcu_read_lock();
+                               sta = ieee80211_find_sta(mac->vif, mac->bssid);
+                       }
                        rtlpriv->cfg->ops->update_rate_tbl(hw, sta,
                                        p_ra->ratr_state);
 
                        p_ra->pre_ratr_state = p_ra->ratr_state;
-                       rcu_read_unlock();
+                       if (rtlhal->interface == INTF_PCI)
+                               rcu_read_unlock();
                }
        }
 }
index bfff5fe8623c8da9d9c70bf1295412ac497fcdaf..1eec3a06d1f350935332a440f379367145b837d0 100644 (file)
@@ -177,7 +177,7 @@ u32 _rtl92c_phy_calculate_bit_shift(u32 bitmask)
        u32 i;
 
        for (i = 0; i <= 31; i++) {
-               if (((bitmask >> i) & 0x1) == 1)
+               if ((bitmask >> i) & 0x1)
                        break;
        }
        return i;
@@ -253,121 +253,51 @@ void _rtl92c_store_pwrIndex_diffrate_offset(struct ieee80211_hw *hw,
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       int index;
+
+       if (regaddr == RTXAGC_A_RATE18_06)
+               index = 0;
+       else if (regaddr == RTXAGC_A_RATE54_24)
+               index = 1;
+       else if (regaddr == RTXAGC_A_CCK1_MCS32)
+               index = 6;
+       else if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0xffffff00)
+               index = 7;
+       else if (regaddr == RTXAGC_A_MCS03_MCS00)
+               index = 2;
+       else if (regaddr == RTXAGC_A_MCS07_MCS04)
+               index = 3;
+       else if (regaddr == RTXAGC_A_MCS11_MCS08)
+               index = 4;
+       else if (regaddr == RTXAGC_A_MCS15_MCS12)
+               index = 5;
+       else if (regaddr == RTXAGC_B_RATE18_06)
+               index = 8;
+       else if (regaddr == RTXAGC_B_RATE54_24)
+               index = 9;
+       else if (regaddr == RTXAGC_B_CCK1_55_MCS32)
+               index = 14;
+       else if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0x000000ff)
+               index = 15;
+       else if (regaddr == RTXAGC_B_MCS03_MCS00)
+               index = 10;
+       else if (regaddr == RTXAGC_B_MCS07_MCS04)
+               index = 11;
+       else if (regaddr == RTXAGC_B_MCS11_MCS08)
+               index = 12;
+       else if (regaddr == RTXAGC_B_MCS15_MCS12)
+               index = 13;
+       else
+               return;
 
-       if (regaddr == RTXAGC_A_RATE18_06) {
-               rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][0] = data;
-               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-                        "MCSTxPowerLevelOriginalOffset[%d][0] = 0x%x\n",
-                        rtlphy->pwrgroup_cnt,
-                        rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][0]);
-       }
-       if (regaddr == RTXAGC_A_RATE54_24) {
-               rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][1] = data;
-               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-                        "MCSTxPowerLevelOriginalOffset[%d][1] = 0x%x\n",
-                        rtlphy->pwrgroup_cnt,
-                        rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][1]);
-       }
-       if (regaddr == RTXAGC_A_CCK1_MCS32) {
-               rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][6] = data;
-               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-                        "MCSTxPowerLevelOriginalOffset[%d][6] = 0x%x\n",
-                        rtlphy->pwrgroup_cnt,
-                        rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][6]);
-       }
-       if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0xffffff00) {
-               rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][7] = data;
-               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-                        "MCSTxPowerLevelOriginalOffset[%d][7] = 0x%x\n",
-                        rtlphy->pwrgroup_cnt,
-                        rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][7]);
-       }
-       if (regaddr == RTXAGC_A_MCS03_MCS00) {
-               rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][2] = data;
-               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-                        "MCSTxPowerLevelOriginalOffset[%d][2] = 0x%x\n",
-                        rtlphy->pwrgroup_cnt,
-                        rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][2]);
-       }
-       if (regaddr == RTXAGC_A_MCS07_MCS04) {
-               rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][3] = data;
-               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-                        "MCSTxPowerLevelOriginalOffset[%d][3] = 0x%x\n",
-                        rtlphy->pwrgroup_cnt,
-                        rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][3]);
-       }
-       if (regaddr == RTXAGC_A_MCS11_MCS08) {
-               rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][4] = data;
-               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-                        "MCSTxPowerLevelOriginalOffset[%d][4] = 0x%x\n",
-                        rtlphy->pwrgroup_cnt,
-                        rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][4]);
-       }
-       if (regaddr == RTXAGC_A_MCS15_MCS12) {
-               rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][5] = data;
-               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-                        "MCSTxPowerLevelOriginalOffset[%d][5] = 0x%x\n",
-                        rtlphy->pwrgroup_cnt,
-                        rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][5]);
-       }
-       if (regaddr == RTXAGC_B_RATE18_06) {
-               rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][8] = data;
-               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-                        "MCSTxPowerLevelOriginalOffset[%d][8] = 0x%x\n",
-                        rtlphy->pwrgroup_cnt,
-                        rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][8]);
-       }
-       if (regaddr == RTXAGC_B_RATE54_24) {
-               rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][9] = data;
-               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-                        "MCSTxPowerLevelOriginalOffset[%d][9] = 0x%x\n",
-                        rtlphy->pwrgroup_cnt,
-                        rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][9]);
-       }
-       if (regaddr == RTXAGC_B_CCK1_55_MCS32) {
-               rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][14] = data;
-               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-                        "MCSTxPowerLevelOriginalOffset[%d][14] = 0x%x\n",
-                        rtlphy->pwrgroup_cnt,
-                        rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][14]);
-       }
-       if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0x000000ff) {
-               rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][15] = data;
-               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-                        "MCSTxPowerLevelOriginalOffset[%d][15] = 0x%x\n",
-                        rtlphy->pwrgroup_cnt,
-                        rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][15]);
-       }
-       if (regaddr == RTXAGC_B_MCS03_MCS00) {
-               rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][10] = data;
-               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-                        "MCSTxPowerLevelOriginalOffset[%d][10] = 0x%x\n",
-                        rtlphy->pwrgroup_cnt,
-                        rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][10]);
-       }
-       if (regaddr == RTXAGC_B_MCS07_MCS04) {
-               rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][11] = data;
-               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-                        "MCSTxPowerLevelOriginalOffset[%d][11] = 0x%x\n",
-                        rtlphy->pwrgroup_cnt,
-                        rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][11]);
-       }
-       if (regaddr == RTXAGC_B_MCS11_MCS08) {
-               rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][12] = data;
-               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-                        "MCSTxPowerLevelOriginalOffset[%d][12] = 0x%x\n",
-                        rtlphy->pwrgroup_cnt,
-                        rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][12]);
-       }
-       if (regaddr == RTXAGC_B_MCS15_MCS12) {
-               rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][13] = data;
-               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-                        "MCSTxPowerLevelOriginalOffset[%d][13] = 0x%x\n",
-                        rtlphy->pwrgroup_cnt,
-                        rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][13]);
+       rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][index] = data;
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                "MCSTxPowerLevelOriginalOffset[%d][%d] = 0x%x\n",
+                rtlphy->pwrgroup_cnt, index,
+                rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][index]);
 
+       if (index == 13)
                rtlphy->pwrgroup_cnt++;
-       }
 }
 EXPORT_SYMBOL(_rtl92c_store_pwrIndex_diffrate_offset);
 
index 93eecbd89402ba2ed7362d814ea42a6a21c23384..34591eeb837617308284c5e5765e4f1440d5a7fd 100644 (file)
@@ -665,152 +665,51 @@ static void _rtl92d_store_pwrindex_diffrate_offset(struct ieee80211_hw *hw,
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       int index;
+
+       if (regaddr == RTXAGC_A_RATE18_06)
+               index = 0;
+       else if (regaddr == RTXAGC_A_RATE54_24)
+               index = 1;
+       else if (regaddr == RTXAGC_A_CCK1_MCS32)
+               index = 6;
+       else if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0xffffff00)
+               index = 7;
+       else if (regaddr == RTXAGC_A_MCS03_MCS00)
+               index = 2;
+       else if (regaddr == RTXAGC_A_MCS07_MCS04)
+               index = 3;
+       else if (regaddr == RTXAGC_A_MCS11_MCS08)
+               index = 4;
+       else if (regaddr == RTXAGC_A_MCS15_MCS12)
+               index = 5;
+       else if (regaddr == RTXAGC_B_RATE18_06)
+               index = 8;
+       else if (regaddr == RTXAGC_B_RATE54_24)
+               index = 9;
+       else if (regaddr == RTXAGC_B_CCK1_55_MCS32)
+               index = 14;
+       else if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0x000000ff)
+               index = 15;
+       else if (regaddr == RTXAGC_B_MCS03_MCS00)
+               index = 10;
+       else if (regaddr == RTXAGC_B_MCS07_MCS04)
+               index = 11;
+       else if (regaddr == RTXAGC_B_MCS11_MCS08)
+               index = 12;
+       else if (regaddr == RTXAGC_B_MCS15_MCS12)
+               index = 13;
+       else
+               return;
 
-       if (regaddr == RTXAGC_A_RATE18_06) {
-               rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][0] =
-                                                                        data;
-               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-                        "MCSTxPowerLevelOriginalOffset[%d][0] = 0x%ulx\n",
-                        rtlphy->pwrgroup_cnt,
-                        rtlphy->mcs_txpwrlevel_origoffset
-                        [rtlphy->pwrgroup_cnt][0]);
-       }
-       if (regaddr == RTXAGC_A_RATE54_24) {
-               rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][1] =
-                                                                        data;
-               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-                        "MCSTxPowerLevelOriginalOffset[%d][1] = 0x%ulx\n",
-                        rtlphy->pwrgroup_cnt,
-                        rtlphy->mcs_txpwrlevel_origoffset
-                        [rtlphy->pwrgroup_cnt][1]);
-       }
-       if (regaddr == RTXAGC_A_CCK1_MCS32) {
-               rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][6] =
-                                                                        data;
-               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-                        "MCSTxPowerLevelOriginalOffset[%d][6] = 0x%ulx\n",
-                        rtlphy->pwrgroup_cnt,
-                        rtlphy->mcs_txpwrlevel_origoffset
-                        [rtlphy->pwrgroup_cnt][6]);
-       }
-       if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0xffffff00) {
-               rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][7] =
-                                                                        data;
-               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-                        "MCSTxPowerLevelOriginalOffset[%d][7] = 0x%ulx\n",
-                        rtlphy->pwrgroup_cnt,
-                        rtlphy->mcs_txpwrlevel_origoffset
-                        [rtlphy->pwrgroup_cnt][7]);
-       }
-       if (regaddr == RTXAGC_A_MCS03_MCS00) {
-               rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][2] =
-                                                                        data;
-               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-                        "MCSTxPowerLevelOriginalOffset[%d][2] = 0x%ulx\n",
-                        rtlphy->pwrgroup_cnt,
-                        rtlphy->mcs_txpwrlevel_origoffset
-                        [rtlphy->pwrgroup_cnt][2]);
-       }
-       if (regaddr == RTXAGC_A_MCS07_MCS04) {
-               rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][3] =
-                                                                        data;
-               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-                        "MCSTxPowerLevelOriginalOffset[%d][3] = 0x%ulx\n",
-                        rtlphy->pwrgroup_cnt,
-                        rtlphy->mcs_txpwrlevel_origoffset
-                        [rtlphy->pwrgroup_cnt][3]);
-       }
-       if (regaddr == RTXAGC_A_MCS11_MCS08) {
-               rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][4] =
-                                                                        data;
-               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-                        "MCSTxPowerLevelOriginalOffset[%d][4] = 0x%ulx\n",
-                        rtlphy->pwrgroup_cnt,
-                        rtlphy->mcs_txpwrlevel_origoffset
-                        [rtlphy->pwrgroup_cnt][4]);
-       }
-       if (regaddr == RTXAGC_A_MCS15_MCS12) {
-               rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][5] =
-                                                                        data;
-               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-                        "MCSTxPowerLevelOriginalOffset[%d][5] = 0x%ulx\n",
-                        rtlphy->pwrgroup_cnt,
-                        rtlphy->mcs_txpwrlevel_origoffset
-                        [rtlphy->pwrgroup_cnt][5]);
-       }
-       if (regaddr == RTXAGC_B_RATE18_06) {
-               rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][8] =
-                                                                        data;
-               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-                        "MCSTxPowerLevelOriginalOffset[%d][8] = 0x%ulx\n",
-                        rtlphy->pwrgroup_cnt,
-                        rtlphy->mcs_txpwrlevel_origoffset
-                        [rtlphy->pwrgroup_cnt][8]);
-       }
-       if (regaddr == RTXAGC_B_RATE54_24) {
-               rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][9] =
-                                                                        data;
-               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-                        "MCSTxPowerLevelOriginalOffset[%d][9] = 0x%ulx\n",
-                        rtlphy->pwrgroup_cnt,
-                        rtlphy->mcs_txpwrlevel_origoffset
-                        [rtlphy->pwrgroup_cnt][9]);
-       }
-       if (regaddr == RTXAGC_B_CCK1_55_MCS32) {
-               rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][14] =
-                                                                        data;
-               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-                        "MCSTxPowerLevelOriginalOffset[%d][14] = 0x%ulx\n",
-                        rtlphy->pwrgroup_cnt,
-                        rtlphy->mcs_txpwrlevel_origoffset
-                        [rtlphy->pwrgroup_cnt][14]);
-       }
-       if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0x000000ff) {
-               rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][15] =
-                                                                        data;
-               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-                        "MCSTxPowerLevelOriginalOffset[%d][15] = 0x%ulx\n",
-                        rtlphy->pwrgroup_cnt,
-                        rtlphy->mcs_txpwrlevel_origoffset
-                        [rtlphy->pwrgroup_cnt][15]);
-       }
-       if (regaddr == RTXAGC_B_MCS03_MCS00) {
-               rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][10] =
-                                                                        data;
-               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-                        "MCSTxPowerLevelOriginalOffset[%d][10] = 0x%ulx\n",
-                        rtlphy->pwrgroup_cnt,
-                        rtlphy->mcs_txpwrlevel_origoffset
-                        [rtlphy->pwrgroup_cnt][10]);
-       }
-       if (regaddr == RTXAGC_B_MCS07_MCS04) {
-               rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][11] =
-                                                                        data;
-               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-                        "MCSTxPowerLevelOriginalOffset[%d][11] = 0x%ulx\n",
-                        rtlphy->pwrgroup_cnt,
-                        rtlphy->mcs_txpwrlevel_origoffset
-                        [rtlphy->pwrgroup_cnt][11]);
-       }
-       if (regaddr == RTXAGC_B_MCS11_MCS08) {
-               rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][12] =
-                                                                        data;
-               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-                        "MCSTxPowerLevelOriginalOffset[%d][12] = 0x%ulx\n",
-                        rtlphy->pwrgroup_cnt,
-                        rtlphy->mcs_txpwrlevel_origoffset
-                        [rtlphy->pwrgroup_cnt][12]);
-       }
-       if (regaddr == RTXAGC_B_MCS15_MCS12) {
-               rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][13] =
-                                                                        data;
-               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-                        "MCSTxPowerLevelOriginalOffset[%d][13] = 0x%ulx\n",
-                        rtlphy->pwrgroup_cnt,
-                        rtlphy->mcs_txpwrlevel_origoffset
-                        [rtlphy->pwrgroup_cnt][13]);
+       rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][index] = data;
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                "MCSTxPowerLevelOriginalOffset[%d][%d] = 0x%ulx\n",
+                rtlphy->pwrgroup_cnt, index,
+                rtlphy->mcs_txpwrlevel_origoffset
+                [rtlphy->pwrgroup_cnt][index]);
+       if (index == 13)
                rtlphy->pwrgroup_cnt++;
-       }
 }
 
 static bool _rtl92d_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw,
index babe85d4b6941704ad9e0c914f570bcced141c10..b4afff62643763f15db2f954d5abc6f1f59e3e3f 100644 (file)
@@ -30,6 +30,7 @@
 #define __REALTEK_FIRMWARE92S_H__
 
 #define RTL8190_MAX_FIRMWARE_CODE_SIZE         64000
+#define RTL8190_MAX_RAW_FIRMWARE_CODE_SIZE     90000
 #define RTL8190_CPU_START_OFFSET               0x80
 /* Firmware Local buffer size. 64k */
 #define        MAX_FIRMWARE_CODE_SIZE                  0xFF00
@@ -217,7 +218,7 @@ struct rt_firmware {
        u8 fw_emem[RTL8190_MAX_FIRMWARE_CODE_SIZE];
        u32 fw_imem_len;
        u32 fw_emem_len;
-       u8 sz_fw_tmpbuffer[164000];
+       u8 sz_fw_tmpbuffer[RTL8190_MAX_RAW_FIRMWARE_CODE_SIZE];
        u32 sz_fw_tmpbufferlen;
        u16 cmdpacket_fragthresold;
 };
index 3bfc411f13b8f50f5f234462d7168f60ef8a842c..4a499928e4c6ca740890ad98f3c0aabeceb3f8a5 100644 (file)
@@ -677,30 +677,28 @@ static void _rtl92s_store_pwrindex_diffrate_offset(struct ieee80211_hw *hw,
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       int index;
 
        if (reg_addr == RTXAGC_RATE18_06)
-               rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][0] =
-                                                                        data;
-       if (reg_addr == RTXAGC_RATE54_24)
-               rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][1] =
-                                                                        data;
-       if (reg_addr == RTXAGC_CCK_MCS32)
-               rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][6] =
-                                                                        data;
-       if (reg_addr == RTXAGC_MCS03_MCS00)
-               rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][2] =
-                                                                        data;
-       if (reg_addr == RTXAGC_MCS07_MCS04)
-               rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][3] =
-                                                                        data;
-       if (reg_addr == RTXAGC_MCS11_MCS08)
-               rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][4] =
-                                                                        data;
-       if (reg_addr == RTXAGC_MCS15_MCS12) {
-               rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][5] =
-                                                                        data;
+               index = 0;
+       else if (reg_addr == RTXAGC_RATE54_24)
+               index = 1;
+       else if (reg_addr == RTXAGC_CCK_MCS32)
+               index = 6;
+       else if (reg_addr == RTXAGC_MCS03_MCS00)
+               index = 2;
+       else if (reg_addr == RTXAGC_MCS07_MCS04)
+               index = 3;
+       else if (reg_addr == RTXAGC_MCS11_MCS08)
+               index = 4;
+       else if (reg_addr == RTXAGC_MCS15_MCS12)
+               index = 5;
+       else
+               return;
+
+       rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][index] = data;
+       if (index == 5)
                rtlphy->pwrgroup_cnt++;
-       }
 }
 
 static void _rtl92s_phy_init_register_definition(struct ieee80211_hw *hw)
index eda30b9d0f15b90724a23c43d3afb001cdddc118..f1b36005c6a2c9496bdce302e17571a144cf2393 100644 (file)
@@ -108,6 +108,7 @@ static void rtl92se_fw_cb(const struct firmware *firmware, void *context)
        if (firmware->size > rtlpriv->max_fw_size) {
                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
                         "Firmware is too big!\n");
+               rtlpriv->max_fw_size = 0;
                release_firmware(firmware);
                return;
        }
@@ -229,7 +230,7 @@ static int rtl92s_init_sw_vars(struct ieee80211_hw *hw)
        if (!rtlpriv->rtlhal.pfirmware)
                return 1;
 
-       rtlpriv->max_fw_size = sizeof(struct rt_firmware);
+       rtlpriv->max_fw_size = RTL8190_MAX_RAW_FIRMWARE_CODE_SIZE;
 
        pr_info("Driver for Realtek RTL8192SE/RTL8191SE\n"
                "Loading firmware %s\n", rtlpriv->cfg->fw_name);
index ffcf89fe45e4045f457b02d95c2ffc22c54151d5..2e1e352864bb88ad33489402aee1f19ef2aa4154 100644 (file)
@@ -346,9 +346,14 @@ static int _rtl_usb_init(struct ieee80211_hw *hw)
                         pep_desc->bEndpointAddress, pep_desc->wMaxPacketSize,
                         pep_desc->bInterval);
        }
-       if (rtlusb->in_ep_nums <  rtlpriv->cfg->usb_interface_cfg->in_ep_num)
-               return -EINVAL ;
-
+       if (rtlusb->in_ep_nums <  rtlpriv->cfg->usb_interface_cfg->in_ep_num) {
+               pr_err("Too few input end points found\n");
+               return -EINVAL;
+       }
+       if (rtlusb->out_ep_nums == 0) {
+               pr_err("No output end points found\n");
+               return -EINVAL;
+       }
        /* usb endpoint mapping */
        err = rtlpriv->cfg->usb_interface_cfg->usb_endpoint_mapping(hw);
        rtlusb->usb_mq_to_hwq =  rtlpriv->cfg->usb_interface_cfg->usb_mq_to_hwq;
@@ -357,7 +362,7 @@ static int _rtl_usb_init(struct ieee80211_hw *hw)
        return err;
 }
 
-static int _rtl_usb_init_sw(struct ieee80211_hw *hw)
+static void rtl_usb_init_sw(struct ieee80211_hw *hw)
 {
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
@@ -392,7 +397,6 @@ static int _rtl_usb_init_sw(struct ieee80211_hw *hw)
        /* HIMR_EX - turn all on */
        rtlusb->irq_mask[1] = 0xFFFFFFFF;
        rtlusb->disableHWSM =  true;
-       return 0;
 }
 
 #define __RADIO_TAP_SIZE_RSV   32
@@ -976,7 +980,9 @@ int __devinit rtl_usb_probe(struct usb_interface *intf,
        }
        rtlpriv->cfg->ops->init_sw_leds(hw);
        err = _rtl_usb_init(hw);
-       err = _rtl_usb_init_sw(hw);
+       if (err)
+               goto error_out;
+       rtl_usb_init_sw(hw);
        /* Init mac80211 sw */
        err = rtl_init_core(hw);
        if (err) {
index 58b4f935a3f634f89157e32389e90cbf29898310..a5c6328b5f725bd3e92e8292df48328f219b08f2 100644 (file)
@@ -6,3 +6,5 @@ wl1251_sdio-objs        += sdio.o
 obj-$(CONFIG_WL1251)           += wl1251.o
 obj-$(CONFIG_WL1251_SPI)       += wl1251_spi.o
 obj-$(CONFIG_WL1251_SDIO)      += wl1251_sdio.o
+
+ccflags-y += -D__CHECK_ENDIAN__
index d729daf8e8411f9de8ccdb388af37346e1a9a4da..a2e5241382da3ddab3fd71920863a9cca12ea4d3 100644 (file)
@@ -464,8 +464,6 @@ static int wl1251_boot_upload_nvs(struct wl1251 *wl)
                val = (nvs_ptr[0] | (nvs_ptr[1] << 8)
                       | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24));
 
-               val = cpu_to_le32(val);
-
                wl1251_debug(DEBUG_BOOT,
                             "nvs write table 0x%x: 0x%x",
                             nvs_start, val);
index c545e9d5f512a34f2cc8a61e847f829dc74d73bc..d382877c34cc179c35cb7b0f65a8efa42c2ed341 100644 (file)
 
 static inline u32 wl1251_read32(struct wl1251 *wl, int addr)
 {
-       u32 response;
-
-       wl->if_ops->read(wl, addr, &response, sizeof(u32));
+       wl->if_ops->read(wl, addr, &wl->buffer_32, sizeof(wl->buffer_32));
 
-       return response;
+       return le32_to_cpu(wl->buffer_32);
 }
 
 static inline void wl1251_write32(struct wl1251 *wl, int addr, u32 val)
 {
-       wl->if_ops->write(wl, addr, &val, sizeof(u32));
+       wl->buffer_32 = cpu_to_le32(val);
+       wl->if_ops->write(wl, addr, &wl->buffer_32, sizeof(wl->buffer_32));
 }
 
 static inline u32 wl1251_read_elp(struct wl1251 *wl, int addr)
index a77f1bbbed0ad063aae085ff857c4cc7abadd717..9d8f5816c6f91628d609ecd0090c438133c5b115 100644 (file)
@@ -380,7 +380,7 @@ struct wl1251 {
        struct wl1251_stats stats;
        struct wl1251_debugfs debugfs;
 
-       u32 buffer_32;
+       __le32 buffer_32;
        u32 buffer_cmd;
        u8 buffer_busyword[WL1251_BUSY_WORD_LEN];
        struct wl1251_rx_descriptor *rx_descriptor;
index fe67262ba19f7997b16c37b9a42395c25890e6ec..98f289c907a97db3f1ef619d391545478af0a7cb 100644 (file)
@@ -11,3 +11,5 @@ obj-$(CONFIG_WL12XX_SDIO)             += wl12xx_sdio.o
 
 # small builtin driver bit
 obj-$(CONFIG_WL12XX_PLATFORM_DATA)     += wl12xx_platform_data.o
+
+ccflags-y += -D__CHECK_ENDIAN__
index 7537c401a4487174a0d50680b1d84e68c3e16675..bc96db0683a5ce99d9fe58d3480813a529675e1a 100644 (file)
 #include "reg.h"
 #include "ps.h"
 
-int wl1271_acx_wake_up_conditions(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+int wl1271_acx_wake_up_conditions(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+                                 u8 wake_up_event, u8 listen_interval)
 {
        struct acx_wake_up_condition *wake_up;
        int ret;
 
-       wl1271_debug(DEBUG_ACX, "acx wake up conditions");
+       wl1271_debug(DEBUG_ACX, "acx wake up conditions (wake_up_event %d listen_interval %d)",
+                    wake_up_event, listen_interval);
 
        wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL);
        if (!wake_up) {
@@ -48,8 +50,8 @@ int wl1271_acx_wake_up_conditions(struct wl1271 *wl, struct wl12xx_vif *wlvif)
        }
 
        wake_up->role_id = wlvif->role_id;
-       wake_up->wake_up_event = wl->conf.conn.wake_up_event;
-       wake_up->listen_interval = wl->conf.conn.listen_interval;
+       wake_up->wake_up_event = wake_up_event;
+       wake_up->listen_interval = listen_interval;
 
        ret = wl1271_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS,
                                   wake_up, sizeof(*wake_up));
@@ -1459,9 +1461,10 @@ out:
        return ret;
 }
 
-int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime)
+int wl12xx_acx_tsf_info(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+                       u64 *mactime)
 {
-       struct wl1271_acx_fw_tsf_information *tsf_info;
+       struct wl12xx_acx_fw_tsf_information *tsf_info;
        int ret;
 
        tsf_info = kzalloc(sizeof(*tsf_info), GFP_KERNEL);
@@ -1470,6 +1473,8 @@ int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime)
                goto out;
        }
 
+       tsf_info->role_id = wlvif->role_id;
+
        ret = wl1271_cmd_interrogate(wl, ACX_TSF_INFO,
                                     tsf_info, sizeof(*tsf_info));
        if (ret < 0) {
index 69892b40c2dfc850cd44b434a155c5ce81da4c6c..a28fc044034c8e194a4e8bf82649a88a6231d4d0 100644 (file)
@@ -995,15 +995,17 @@ struct wl1271_acx_ba_receiver_setup {
        u8 padding[2];
 } __packed;
 
-struct wl1271_acx_fw_tsf_information {
+struct wl12xx_acx_fw_tsf_information {
        struct acx_header header;
 
+       u8 role_id;
+       u8 padding1[3];
        __le32 current_tsf_high;
        __le32 current_tsf_low;
        __le32 last_bttt_high;
        __le32 last_tbtt_low;
        u8 last_dtim_count;
-       u8 padding[3];
+       u8 padding2[3];
 } __packed;
 
 struct wl1271_acx_ps_rx_streaming {
@@ -1151,79 +1153,81 @@ struct wl12xx_acx_config_hangover {
 } __packed;
 
 enum {
-       ACX_WAKE_UP_CONDITIONS      = 0x0002,
-       ACX_MEM_CFG                 = 0x0003,
-       ACX_SLOT                    = 0x0004,
-       ACX_AC_CFG                  = 0x0007,
-       ACX_MEM_MAP                 = 0x0008,
-       ACX_AID                     = 0x000A,
-       ACX_MEDIUM_USAGE            = 0x000F,
-       ACX_TX_QUEUE_CFG            = 0x0011, /* FIXME: only used by wl1251 */
-       ACX_STATISTICS              = 0x0013, /* Debug API */
-       ACX_PWR_CONSUMPTION_STATISTICS = 0x0014,
-       ACX_FEATURE_CFG             = 0x0015,
-       ACX_TID_CFG                 = 0x001A,
-       ACX_PS_RX_STREAMING         = 0x001B,
-       ACX_BEACON_FILTER_OPT       = 0x001F,
-       ACX_NOISE_HIST              = 0x0021,
-       ACX_HDK_VERSION             = 0x0022, /* ??? */
-       ACX_PD_THRESHOLD            = 0x0023,
-       ACX_TX_CONFIG_OPT           = 0x0024,
-       ACX_CCA_THRESHOLD           = 0x0025,
-       ACX_EVENT_MBOX_MASK         = 0x0026,
-       ACX_CONN_MONIT_PARAMS       = 0x002D,
-       ACX_BCN_DTIM_OPTIONS        = 0x0031,
-       ACX_SG_ENABLE               = 0x0032,
-       ACX_SG_CFG                  = 0x0033,
-       ACX_FM_COEX_CFG             = 0x0034,
-       ACX_BEACON_FILTER_TABLE     = 0x0038,
-       ACX_ARP_IP_FILTER           = 0x0039,
-       ACX_ROAMING_STATISTICS_TBL  = 0x003B,
-       ACX_RATE_POLICY             = 0x003D,
-       ACX_CTS_PROTECTION          = 0x003E,
-       ACX_SLEEP_AUTH              = 0x003F,
-       ACX_PREAMBLE_TYPE           = 0x0040,
-       ACX_ERROR_CNT               = 0x0041,
-       ACX_IBSS_FILTER             = 0x0044,
-       ACX_SERVICE_PERIOD_TIMEOUT  = 0x0045,
-       ACX_TSF_INFO                = 0x0046,
-       ACX_CONFIG_PS_WMM           = 0x0049,
-       ACX_ENABLE_RX_DATA_FILTER   = 0x004A,
-       ACX_SET_RX_DATA_FILTER      = 0x004B,
-       ACX_GET_DATA_FILTER_STATISTICS = 0x004C,
-       ACX_RX_CONFIG_OPT           = 0x004E,
-       ACX_FRAG_CFG                = 0x004F,
-       ACX_BET_ENABLE              = 0x0050,
-       ACX_RSSI_SNR_TRIGGER        = 0x0051,
-       ACX_RSSI_SNR_WEIGHTS        = 0x0052,
-       ACX_KEEP_ALIVE_MODE         = 0x0053,
-       ACX_SET_KEEP_ALIVE_CONFIG   = 0x0054,
-       ACX_BA_SESSION_INIT_POLICY  = 0x0055,
-       ACX_BA_SESSION_RX_SETUP     = 0x0056,
-       ACX_PEER_HT_CAP             = 0x0057,
-       ACX_HT_BSS_OPERATION        = 0x0058,
-       ACX_COEX_ACTIVITY           = 0x0059,
-       ACX_BURST_MODE              = 0x005C,
-       ACX_SET_RATE_MGMT_PARAMS    = 0x005D,
-       ACX_SET_RATE_ADAPT_PARAMS   = 0x0060,
-       ACX_SET_DCO_ITRIM_PARAMS    = 0x0061,
-       ACX_GEN_FW_CMD              = 0x0070,
-       ACX_HOST_IF_CFG_BITMAP      = 0x0071,
-       ACX_MAX_TX_FAILURE          = 0x0072,
-       ACX_UPDATE_INCONNECTION_STA_LIST = 0x0073,
-       DOT11_RX_MSDU_LIFE_TIME     = 0x1004,
-       DOT11_CUR_TX_PWR            = 0x100D,
-       DOT11_RX_DOT11_MODE         = 0x1012,
-       DOT11_RTS_THRESHOLD         = 0x1013,
-       DOT11_GROUP_ADDRESS_TBL     = 0x1014,
-       ACX_PM_CONFIG               = 0x1016,
-       ACX_CONFIG_PS               = 0x1017,
-       ACX_CONFIG_HANGOVER         = 0x1018,
+       ACX_WAKE_UP_CONDITIONS           = 0x0000,
+       ACX_MEM_CFG                      = 0x0001,
+       ACX_SLOT                         = 0x0002,
+       ACX_AC_CFG                       = 0x0003,
+       ACX_MEM_MAP                      = 0x0004,
+       ACX_AID                          = 0x0005,
+       ACX_MEDIUM_USAGE                 = 0x0006,
+       ACX_STATISTICS                   = 0x0007,
+       ACX_PWR_CONSUMPTION_STATISTICS   = 0x0008,
+       ACX_TID_CFG                      = 0x0009,
+       ACX_PS_RX_STREAMING              = 0x000A,
+       ACX_BEACON_FILTER_OPT            = 0x000B,
+       ACX_NOISE_HIST                   = 0x000C,
+       ACX_HDK_VERSION                  = 0x000D,
+       ACX_PD_THRESHOLD                 = 0x000E,
+       ACX_TX_CONFIG_OPT                = 0x000F,
+       ACX_CCA_THRESHOLD                = 0x0010,
+       ACX_EVENT_MBOX_MASK              = 0x0011,
+       ACX_CONN_MONIT_PARAMS            = 0x0012,
+       ACX_DISABLE_BROADCASTS           = 0x0013,
+       ACX_BCN_DTIM_OPTIONS             = 0x0014,
+       ACX_SG_ENABLE                    = 0x0015,
+       ACX_SG_CFG                       = 0x0016,
+       ACX_FM_COEX_CFG                  = 0x0017,
+       ACX_BEACON_FILTER_TABLE          = 0x0018,
+       ACX_ARP_IP_FILTER                = 0x0019,
+       ACX_ROAMING_STATISTICS_TBL       = 0x001A,
+       ACX_RATE_POLICY                  = 0x001B,
+       ACX_CTS_PROTECTION               = 0x001C,
+       ACX_SLEEP_AUTH                   = 0x001D,
+       ACX_PREAMBLE_TYPE                = 0x001E,
+       ACX_ERROR_CNT                    = 0x001F,
+       ACX_IBSS_FILTER                  = 0x0020,
+       ACX_SERVICE_PERIOD_TIMEOUT       = 0x0021,
+       ACX_TSF_INFO                     = 0x0022,
+       ACX_CONFIG_PS_WMM                = 0x0023,
+       ACX_ENABLE_RX_DATA_FILTER        = 0x0024,
+       ACX_SET_RX_DATA_FILTER           = 0x0025,
+       ACX_GET_DATA_FILTER_STATISTICS   = 0x0026,
+       ACX_RX_CONFIG_OPT                = 0x0027,
+       ACX_FRAG_CFG                     = 0x0028,
+       ACX_BET_ENABLE                   = 0x0029,
+       ACX_RSSI_SNR_TRIGGER             = 0x002A,
+       ACX_RSSI_SNR_WEIGHTS             = 0x002B,
+       ACX_KEEP_ALIVE_MODE              = 0x002C,
+       ACX_SET_KEEP_ALIVE_CONFIG        = 0x002D,
+       ACX_BA_SESSION_INIT_POLICY       = 0x002E,
+       ACX_BA_SESSION_RX_SETUP          = 0x002F,
+       ACX_PEER_HT_CAP                  = 0x0030,
+       ACX_HT_BSS_OPERATION             = 0x0031,
+       ACX_COEX_ACTIVITY                = 0x0032,
+       ACX_BURST_MODE                   = 0x0033,
+       ACX_SET_RATE_MGMT_PARAMS         = 0x0034,
+       ACX_GET_RATE_MGMT_PARAMS         = 0x0035,
+       ACX_SET_RATE_ADAPT_PARAMS        = 0x0036,
+       ACX_SET_DCO_ITRIM_PARAMS         = 0x0037,
+       ACX_GEN_FW_CMD                   = 0x0038,
+       ACX_HOST_IF_CFG_BITMAP           = 0x0039,
+       ACX_MAX_TX_FAILURE               = 0x003A,
+       ACX_UPDATE_INCONNECTION_STA_LIST = 0x003B,
+       DOT11_RX_MSDU_LIFE_TIME          = 0x003C,
+       DOT11_CUR_TX_PWR                 = 0x003D,
+       DOT11_RTS_THRESHOLD              = 0x003E,
+       DOT11_GROUP_ADDRESS_TBL          = 0x003F,
+       ACX_PM_CONFIG                    = 0x0040,
+       ACX_CONFIG_PS                    = 0x0041,
+       ACX_CONFIG_HANGOVER              = 0x0042,
+       ACX_FEATURE_CFG                  = 0x0043,
+       ACX_PROTECTION_CFG               = 0x0044,
 };
 
 
 int wl1271_acx_wake_up_conditions(struct wl1271 *wl,
-                                 struct wl12xx_vif *wlvif);
+                                 struct wl12xx_vif *wlvif,
+                                 u8 wake_up_event, u8 listen_interval);
 int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth);
 int wl1271_acx_tx_power(struct wl1271 *wl, struct wl12xx_vif *wlvif,
                        int power);
@@ -1296,7 +1300,8 @@ int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl,
                                       struct wl12xx_vif *wlvif);
 int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index,
                                       u16 ssn, bool enable, u8 peer_hlid);
-int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime);
+int wl12xx_acx_tsf_info(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+                       u64 *mactime);
 int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
                               bool enable);
 int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl, struct wl12xx_vif *wlvif);
index 8f9cf5a816ea494601acb5cd4c55112530cd02f2..954101d03f068300e4ed731a8f8cbfa420af166d 100644 (file)
 #include "event.h"
 #include "rx.h"
 
-static struct wl1271_partition_set part_table[PART_TABLE_LEN] = {
-       [PART_DOWN] = {
-               .mem = {
-                       .start = 0x00000000,
-                       .size  = 0x000177c0
-               },
-               .reg = {
-                       .start = REGISTERS_BASE,
-                       .size  = 0x00008800
-               },
-               .mem2 = {
-                       .start = 0x00000000,
-                       .size  = 0x00000000
-               },
-               .mem3 = {
-                       .start = 0x00000000,
-                       .size  = 0x00000000
-               },
-       },
-
-       [PART_WORK] = {
-               .mem = {
-                       .start = 0x00040000,
-                       .size  = 0x00014fc0
-               },
-               .reg = {
-                       .start = REGISTERS_BASE,
-                       .size  = 0x0000a000
-               },
-               .mem2 = {
-                       .start = 0x003004f8,
-                       .size  = 0x00000004
-               },
-               .mem3 = {
-                       .start = 0x00040404,
-                       .size  = 0x00000000
-               },
-       },
-
-       [PART_DRPW] = {
-               .mem = {
-                       .start = 0x00040000,
-                       .size  = 0x00014fc0
-               },
-               .reg = {
-                       .start = DRPW_BASE,
-                       .size  = 0x00006000
-               },
-               .mem2 = {
-                       .start = 0x00000000,
-                       .size  = 0x00000000
-               },
-               .mem3 = {
-                       .start = 0x00000000,
-                       .size  = 0x00000000
-               }
-       }
-};
-
 static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag)
 {
        u32 cpu_ctrl;
@@ -181,13 +122,13 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
                return -ENOMEM;
        }
 
-       memcpy(&partition, &part_table[PART_DOWN], sizeof(partition));
+       memcpy(&partition, &wl12xx_part_table[PART_DOWN], sizeof(partition));
        partition.mem.start = dest;
        wl1271_set_partition(wl, &partition);
 
        /* 10.1 set partition limit and chunk num */
        chunk_num = 0;
-       partition_limit = part_table[PART_DOWN].mem.size;
+       partition_limit = wl12xx_part_table[PART_DOWN].mem.size;
 
        while (chunk_num < fw_data_len / CHUNK_SIZE) {
                /* 10.2 update partition, if needed */
@@ -195,7 +136,7 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
                if (addr > partition_limit) {
                        addr = dest + chunk_num * CHUNK_SIZE;
                        partition_limit = chunk_num * CHUNK_SIZE +
-                               part_table[PART_DOWN].mem.size;
+                               wl12xx_part_table[PART_DOWN].mem.size;
                        partition.mem.start = addr;
                        wl1271_set_partition(wl, &partition);
                }
@@ -317,12 +258,12 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
        }
 
        /* update current MAC address to NVS */
-       nvs_ptr[11] = wl->mac_addr[0];
-       nvs_ptr[10] = wl->mac_addr[1];
-       nvs_ptr[6] = wl->mac_addr[2];
-       nvs_ptr[5] = wl->mac_addr[3];
-       nvs_ptr[4] = wl->mac_addr[4];
-       nvs_ptr[3] = wl->mac_addr[5];
+       nvs_ptr[11] = wl->addresses[0].addr[0];
+       nvs_ptr[10] = wl->addresses[0].addr[1];
+       nvs_ptr[6] = wl->addresses[0].addr[2];
+       nvs_ptr[5] = wl->addresses[0].addr[3];
+       nvs_ptr[4] = wl->addresses[0].addr[4];
+       nvs_ptr[3] = wl->addresses[0].addr[5];
 
        /*
         * Layout before the actual NVS tables:
@@ -383,7 +324,7 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
        nvs_len -= nvs_ptr - (u8 *)wl->nvs;
 
        /* Now we must set the partition correctly */
-       wl1271_set_partition(wl, &part_table[PART_WORK]);
+       wl1271_set_partition(wl, &wl12xx_part_table[PART_WORK]);
 
        /* Copy the NVS tables to a new block to ensure alignment */
        nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL);
@@ -492,7 +433,7 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
        wl->event_box_addr = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR);
 
        /* set the working partition to its "running" mode offset */
-       wl1271_set_partition(wl, &part_table[PART_WORK]);
+       wl1271_set_partition(wl, &wl12xx_part_table[PART_WORK]);
 
        wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x",
                     wl->cmd_box_addr, wl->event_box_addr);
@@ -507,8 +448,7 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
        /* unmask required mbox events  */
        wl->event_mask = BSS_LOSE_EVENT_ID |
                SCAN_COMPLETE_EVENT_ID |
-               PS_REPORT_EVENT_ID |
-               DISCONNECT_EVENT_COMPLETE_ID |
+               ROLE_STOP_COMPLETE_EVENT_ID |
                RSSI_SNR_TRIGGER_0_EVENT_ID |
                PSPOLL_DELIVERY_FAILURE_EVENT_ID |
                SOFT_GEMINI_SENSE_EVENT_ID |
@@ -547,19 +487,6 @@ static int wl1271_boot_write_irq_polarity(struct wl1271 *wl)
        return 0;
 }
 
-static void wl1271_boot_hw_version(struct wl1271 *wl)
-{
-       u32 fuse;
-
-       if (wl->chip.id == CHIP_ID_1283_PG20)
-               fuse = wl1271_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1);
-       else
-               fuse = wl1271_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1);
-       fuse = (fuse & PG_VER_MASK) >> PG_VER_OFFSET;
-
-       wl->hw_pg_ver = (s8)fuse;
-}
-
 static int wl128x_switch_tcxo_to_fref(struct wl1271 *wl)
 {
        u16 spare_reg;
@@ -698,7 +625,7 @@ static int wl127x_boot_clk(struct wl1271 *wl)
        u32 pause;
        u32 clk;
 
-       if (((wl->hw_pg_ver & PG_MAJOR_VER_MASK) >> PG_MAJOR_VER_OFFSET) < 3)
+       if (WL127X_PG_GET_MAJOR(wl->hw_pg_ver) < 3)
                wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION;
 
        if (wl->ref_clock == CONF_REF_CLK_19_2_E ||
@@ -753,8 +680,6 @@ int wl1271_load_firmware(struct wl1271 *wl)
        u32 tmp, clk;
        int selected_clock = -1;
 
-       wl1271_boot_hw_version(wl);
-
        if (wl->chip.id == CHIP_ID_1283_PG20) {
                ret = wl128x_boot_clk(wl, &selected_clock);
                if (ret < 0)
@@ -769,7 +694,7 @@ int wl1271_load_firmware(struct wl1271 *wl)
        wl1271_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
        udelay(500);
 
-       wl1271_set_partition(wl, &part_table[PART_DRPW]);
+       wl1271_set_partition(wl, &wl12xx_part_table[PART_DRPW]);
 
        /* Read-modify-write DRPW_SCRATCH_START register (see next state)
           to be used by DRPw FW. The RTRIM value will be added by the FW
@@ -788,7 +713,7 @@ int wl1271_load_firmware(struct wl1271 *wl)
 
        wl1271_write32(wl, DRPW_SCRATCH_START, clk);
 
-       wl1271_set_partition(wl, &part_table[PART_WORK]);
+       wl1271_set_partition(wl, &wl12xx_part_table[PART_WORK]);
 
        /* Disable interrupts */
        wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
index 06dad9380fa7f427e5318d5f5e0e191a5c00f1cb..c3adc09f403dd1319fe99303d1a75357d21a9127 100644 (file)
@@ -55,16 +55,6 @@ struct wl1271_static_data {
 #define OCP_REG_CLK_POLARITY 0x0cb2
 #define OCP_REG_CLK_PULL     0x0cb4
 
-#define WL127X_REG_FUSE_DATA_2_1    0x050a
-#define WL128X_REG_FUSE_DATA_2_1    0x2152
-#define PG_VER_MASK          0x3c
-#define PG_VER_OFFSET        2
-
-#define PG_MAJOR_VER_MASK    0x3
-#define PG_MAJOR_VER_OFFSET  0x0
-#define PG_MINOR_VER_MASK    0xc
-#define PG_MINOR_VER_OFFSET  0x2
-
 #define CMD_MBOX_ADDRESS     0x407B4
 
 #define POLARITY_LOW         BIT(1)
index 25990bd38be633d57bc17ae13573875f3cce4a7a..3414fc11e9ba71da93eb4723d252bac693871899 100644 (file)
@@ -459,23 +459,39 @@ out:
 
 int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
 {
+       unsigned long flags;
        u8 link = find_first_zero_bit(wl->links_map, WL12XX_MAX_LINKS);
        if (link >= WL12XX_MAX_LINKS)
                return -EBUSY;
 
+       /* these bits are used by op_tx */
+       spin_lock_irqsave(&wl->wl_lock, flags);
        __set_bit(link, wl->links_map);
        __set_bit(link, wlvif->links_map);
+       spin_unlock_irqrestore(&wl->wl_lock, flags);
        *hlid = link;
        return 0;
 }
 
 void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
 {
+       unsigned long flags;
+
        if (*hlid == WL12XX_INVALID_LINK_ID)
                return;
 
+       /* these bits are used by op_tx */
+       spin_lock_irqsave(&wl->wl_lock, flags);
        __clear_bit(*hlid, wl->links_map);
        __clear_bit(*hlid, wlvif->links_map);
+       spin_unlock_irqrestore(&wl->wl_lock, flags);
+
+       /*
+        * At this point op_tx() will not add more packets to the queues. We
+        * can purge them.
+        */
+       wl1271_tx_reset_link_queues(wl, *hlid);
+
        *hlid = WL12XX_INVALID_LINK_ID;
 }
 
@@ -515,7 +531,7 @@ static int wl12xx_cmd_role_start_dev(struct wl1271 *wl,
                        goto out_free;
        }
        cmd->device.hlid = wlvif->dev_hlid;
-       cmd->device.session = wlvif->session_counter;
+       cmd->device.session = wl12xx_get_new_session_id(wl, wlvif);
 
        wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d",
                     cmd->role_id, cmd->device.hlid, cmd->device.session);
@@ -566,7 +582,7 @@ static int wl12xx_cmd_role_stop_dev(struct wl1271 *wl,
                goto out_free;
        }
 
-       ret = wl1271_cmd_wait_for_event(wl, DISCONNECT_EVENT_COMPLETE_ID);
+       ret = wl1271_cmd_wait_for_event(wl, ROLE_STOP_COMPLETE_EVENT_ID);
        if (ret < 0) {
                wl1271_error("cmd role stop dev event completion error");
                goto out_free;
@@ -715,6 +731,8 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif)
        cmd->ap.beacon_interval = cpu_to_le16(wlvif->beacon_int);
        cmd->ap.dtim_interval = bss_conf->dtim_period;
        cmd->ap.beacon_expiry = WL1271_AP_DEF_BEACON_EXP;
+       /* FIXME: Change when adding DFS */
+       cmd->ap.reset_tsf = 1;  /* By default reset AP TSF */
        cmd->channel = wlvif->channel;
 
        if (!bss_conf->hidden_ssid) {
@@ -994,7 +1012,7 @@ out:
 }
 
 int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
-                      u8 ps_mode)
+                      u8 ps_mode, u16 auto_ps_timeout)
 {
        struct wl1271_cmd_ps_params *ps_params = NULL;
        int ret = 0;
@@ -1009,6 +1027,7 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 
        ps_params->role_id = wlvif->role_id;
        ps_params->ps_mode = ps_mode;
+       ps_params->auto_ps_timeout = auto_ps_timeout;
 
        ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params,
                              sizeof(*ps_params), 0);
@@ -1022,13 +1041,15 @@ out:
        return ret;
 }
 
-int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
-                           void *buf, size_t buf_len, int index, u32 rates)
+int wl1271_cmd_template_set(struct wl1271 *wl, u8 role_id,
+                           u16 template_id, void *buf, size_t buf_len,
+                           int index, u32 rates)
 {
        struct wl1271_cmd_template_set *cmd;
        int ret = 0;
 
-       wl1271_debug(DEBUG_CMD, "cmd template_set %d", template_id);
+       wl1271_debug(DEBUG_CMD, "cmd template_set %d (role %d)",
+                    template_id, role_id);
 
        WARN_ON(buf_len > WL1271_CMD_TEMPL_MAX_SIZE);
        buf_len = min_t(size_t, buf_len, WL1271_CMD_TEMPL_MAX_SIZE);
@@ -1039,6 +1060,8 @@ int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
                goto out;
        }
 
+       /* during initialization wlvif is NULL */
+       cmd->role_id = role_id;
        cmd->len = cpu_to_le16(buf_len);
        cmd->template_type = template_id;
        cmd->enabled_rates = cpu_to_le32(rates);
@@ -1082,7 +1105,8 @@ int wl12xx_cmd_build_null_data(struct wl1271 *wl, struct wl12xx_vif *wlvif)
                ptr = skb->data;
        }
 
-       ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, ptr, size, 0,
+       ret = wl1271_cmd_template_set(wl, wlvif->role_id,
+                                     CMD_TEMPL_NULL_DATA, ptr, size, 0,
                                      wlvif->basic_rate);
 
 out:
@@ -1105,7 +1129,7 @@ int wl12xx_cmd_build_klv_null_data(struct wl1271 *wl,
        if (!skb)
                goto out;
 
-       ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV,
+       ret = wl1271_cmd_template_set(wl, wlvif->role_id, CMD_TEMPL_KLV,
                                      skb->data, skb->len,
                                      CMD_TEMPL_KLV_IDX_NULL_DATA,
                                      wlvif->basic_rate);
@@ -1130,7 +1154,8 @@ int wl1271_cmd_build_ps_poll(struct wl1271 *wl, struct wl12xx_vif *wlvif,
        if (!skb)
                goto out;
 
-       ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, skb->data,
+       ret = wl1271_cmd_template_set(wl, wlvif->role_id,
+                                     CMD_TEMPL_PS_POLL, skb->data,
                                      skb->len, 0, wlvif->basic_rate_set);
 
 out:
@@ -1138,9 +1163,10 @@ out:
        return ret;
 }
 
-int wl1271_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+                              u8 role_id, u8 band,
                               const u8 *ssid, size_t ssid_len,
-                              const u8 *ie, size_t ie_len, u8 band)
+                              const u8 *ie, size_t ie_len)
 {
        struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
        struct sk_buff *skb;
@@ -1158,10 +1184,12 @@ int wl1271_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 
        rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]);
        if (band == IEEE80211_BAND_2GHZ)
-               ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
+               ret = wl1271_cmd_template_set(wl, role_id,
+                                             CMD_TEMPL_CFG_PROBE_REQ_2_4,
                                              skb->data, skb->len, 0, rate);
        else
-               ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
+               ret = wl1271_cmd_template_set(wl, role_id,
+                                             CMD_TEMPL_CFG_PROBE_REQ_5,
                                              skb->data, skb->len, 0, rate);
 
 out:
@@ -1186,10 +1214,12 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
 
        rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[wlvif->band]);
        if (wlvif->band == IEEE80211_BAND_2GHZ)
-               ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
+               ret = wl1271_cmd_template_set(wl, wlvif->role_id,
+                                             CMD_TEMPL_CFG_PROBE_REQ_2_4,
                                              skb->data, skb->len, 0, rate);
        else
-               ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
+               ret = wl1271_cmd_template_set(wl, wlvif->role_id,
+                                             CMD_TEMPL_CFG_PROBE_REQ_5,
                                              skb->data, skb->len, 0, rate);
 
        if (ret < 0)
@@ -1199,32 +1229,34 @@ out:
        return skb;
 }
 
-int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif,
-                            __be32 ip_addr)
+int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif)
 {
-       int ret;
+       int ret, extra;
+       u16 fc;
        struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
-       struct wl12xx_arp_rsp_template tmpl;
+       struct sk_buff *skb;
+       struct wl12xx_arp_rsp_template *tmpl;
        struct ieee80211_hdr_3addr *hdr;
        struct arphdr *arp_hdr;
 
-       memset(&tmpl, 0, sizeof(tmpl));
+       skb = dev_alloc_skb(sizeof(*hdr) + sizeof(__le16) + sizeof(*tmpl) +
+                           WL1271_EXTRA_SPACE_MAX);
+       if (!skb) {
+               wl1271_error("failed to allocate buffer for arp rsp template");
+               return -ENOMEM;
+       }
 
-       /* mac80211 header */
-       hdr = &tmpl.hdr;
-       hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
-                                        IEEE80211_STYPE_DATA |
-                                        IEEE80211_FCTL_TODS);
-       memcpy(hdr->addr1, vif->bss_conf.bssid, ETH_ALEN);
-       memcpy(hdr->addr2, vif->addr, ETH_ALEN);
-       memset(hdr->addr3, 0xff, ETH_ALEN);
+       skb_reserve(skb, sizeof(*hdr) + WL1271_EXTRA_SPACE_MAX);
+
+       tmpl = (struct wl12xx_arp_rsp_template *)skb_put(skb, sizeof(*tmpl));
+       memset(tmpl, 0, sizeof(tmpl));
 
        /* llc layer */
-       memcpy(tmpl.llc_hdr, rfc1042_header, sizeof(rfc1042_header));
-       tmpl.llc_type = cpu_to_be16(ETH_P_ARP);
+       memcpy(tmpl->llc_hdr, rfc1042_header, sizeof(rfc1042_header));
+       tmpl->llc_type = cpu_to_be16(ETH_P_ARP);
 
        /* arp header */
-       arp_hdr = &tmpl.arp_hdr;
+       arp_hdr = &tmpl->arp_hdr;
        arp_hdr->ar_hrd = cpu_to_be16(ARPHRD_ETHER);
        arp_hdr->ar_pro = cpu_to_be16(ETH_P_IP);
        arp_hdr->ar_hln = ETH_ALEN;
@@ -1232,13 +1264,59 @@ int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif,
        arp_hdr->ar_op = cpu_to_be16(ARPOP_REPLY);
 
        /* arp payload */
-       memcpy(tmpl.sender_hw, vif->addr, ETH_ALEN);
-       tmpl.sender_ip = ip_addr;
+       memcpy(tmpl->sender_hw, vif->addr, ETH_ALEN);
+       tmpl->sender_ip = wlvif->ip_addr;
 
-       ret = wl1271_cmd_template_set(wl, CMD_TEMPL_ARP_RSP,
-                                     &tmpl, sizeof(tmpl), 0,
-                                     wlvif->basic_rate);
+       /* encryption space */
+       switch (wlvif->encryption_type) {
+       case KEY_TKIP:
+               extra = WL1271_EXTRA_SPACE_TKIP;
+               break;
+       case KEY_AES:
+               extra = WL1271_EXTRA_SPACE_AES;
+               break;
+       case KEY_NONE:
+       case KEY_WEP:
+       case KEY_GEM:
+               extra = 0;
+               break;
+       default:
+               wl1271_warning("Unknown encryption type: %d",
+                              wlvif->encryption_type);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (extra) {
+               u8 *space = skb_push(skb, extra);
+               memset(space, 0, extra);
+       }
+
+       /* QoS header - BE */
+       if (wlvif->sta.qos)
+               memset(skb_push(skb, sizeof(__le16)), 0, sizeof(__le16));
 
+       /* mac80211 header */
+       hdr = (struct ieee80211_hdr_3addr *)skb_push(skb, sizeof(*hdr));
+       memset(hdr, 0, sizeof(hdr));
+       fc = IEEE80211_FTYPE_DATA | IEEE80211_FCTL_TODS;
+       if (wlvif->sta.qos)
+               fc |= IEEE80211_STYPE_QOS_DATA;
+       else
+               fc |= IEEE80211_STYPE_DATA;
+       if (wlvif->encryption_type != KEY_NONE)
+               fc |= IEEE80211_FCTL_PROTECTED;
+
+       hdr->frame_control = cpu_to_le16(fc);
+       memcpy(hdr->addr1, vif->bss_conf.bssid, ETH_ALEN);
+       memcpy(hdr->addr2, vif->addr, ETH_ALEN);
+       memset(hdr->addr3, 0xff, ETH_ALEN);
+
+       ret = wl1271_cmd_template_set(wl, wlvif->role_id, CMD_TEMPL_ARP_RSP,
+                                     skb->data, skb->len, 0,
+                                     wlvif->basic_rate);
+out:
+       dev_kfree_skb(skb);
        return ret;
 }
 
@@ -1260,7 +1338,8 @@ int wl1271_build_qos_null_data(struct wl1271 *wl, struct ieee80211_vif *vif)
        /* FIXME: not sure what priority to use here */
        template.qos_ctrl = cpu_to_le16(0);
 
-       return wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, &template,
+       return wl1271_cmd_template_set(wl, wlvif->role_id,
+                                      CMD_TEMPL_QOS_NULL_DATA, &template,
                                       sizeof(template), 0,
                                       wlvif->basic_rate);
 }
@@ -1739,11 +1818,20 @@ int wl12xx_croc(struct wl1271 *wl, u8 role_id)
                goto out;
 
        __clear_bit(role_id, wl->roc_map);
+
+       /*
+        * Rearm the tx watchdog when removing the last ROC. This prevents
+        * recoveries due to just finished ROCs - when Tx hasn't yet had
+        * a chance to get out.
+        */
+       if (find_first_bit(wl->roc_map, WL12XX_MAX_ROLES) >= WL12XX_MAX_ROLES)
+               wl12xx_rearm_tx_watchdog_locked(wl);
 out:
        return ret;
 }
 
 int wl12xx_cmd_channel_switch(struct wl1271 *wl,
+                             struct wl12xx_vif *wlvif,
                              struct ieee80211_channel_switch *ch_switch)
 {
        struct wl12xx_cmd_channel_switch *cmd;
@@ -1757,10 +1845,13 @@ int wl12xx_cmd_channel_switch(struct wl1271 *wl,
                goto out;
        }
 
+       cmd->role_id = wlvif->role_id;
        cmd->channel = ch_switch->channel->hw_value;
        cmd->switch_time = ch_switch->count;
-       cmd->tx_suspend = ch_switch->block_tx;
-       cmd->flush = 0; /* this value is ignored by the FW */
+       cmd->stop_tx = ch_switch->block_tx;
+
+       /* FIXME: control from mac80211 in the future */
+       cmd->post_switch_tx_disable = 0;  /* Enable TX on the target channel */
 
        ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0);
        if (ret < 0) {
index 3f7d0b93c24d76c2853fc17ce43580646904e283..de217d92516b4efede360f4c1f187b156b76a294 100644 (file)
@@ -51,22 +51,23 @@ int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len);
 int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len);
 int wl1271_cmd_data_path(struct wl1271 *wl, bool enable);
 int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
-                      u8 ps_mode);
+                      u8 ps_mode, u16 auto_ps_timeout);
 int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
                           size_t len);
-int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
-                           void *buf, size_t buf_len, int index, u32 rates);
+int wl1271_cmd_template_set(struct wl1271 *wl, u8 role_id,
+                           u16 template_id, void *buf, size_t buf_len,
+                           int index, u32 rates);
 int wl12xx_cmd_build_null_data(struct wl1271 *wl, struct wl12xx_vif *wlvif);
 int wl1271_cmd_build_ps_poll(struct wl1271 *wl, struct wl12xx_vif *wlvif,
                             u16 aid);
-int wl1271_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+                              u8 role_id, u8 band,
                               const u8 *ssid, size_t ssid_len,
-                              const u8 *ie, size_t ie_len, u8 band);
+                              const u8 *ie, size_t ie_len);
 struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
                                              struct wl12xx_vif *wlvif,
                                              struct sk_buff *skb);
-int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif,
-                            __be32 ip_addr);
+int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif);
 int wl1271_build_qos_null_data(struct wl1271 *wl, struct ieee80211_vif *vif);
 int wl12xx_cmd_build_klv_null_data(struct wl1271 *wl,
                                   struct wl12xx_vif *wlvif);
@@ -89,6 +90,7 @@ int wl12xx_cmd_config_fwlog(struct wl1271 *wl);
 int wl12xx_cmd_start_fwlog(struct wl1271 *wl);
 int wl12xx_cmd_stop_fwlog(struct wl1271 *wl);
 int wl12xx_cmd_channel_switch(struct wl1271 *wl,
+                             struct wl12xx_vif *wlvif,
                              struct ieee80211_channel_switch *ch_switch);
 int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl);
 int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif,
@@ -96,62 +98,65 @@ int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid);
 
 enum wl1271_commands {
-       CMD_INTERROGATE     = 1,    /*use this to read information elements*/
-       CMD_CONFIGURE       = 2,    /*use this to write information elements*/
-       CMD_ENABLE_RX       = 3,
-       CMD_ENABLE_TX       = 4,
-       CMD_DISABLE_RX      = 5,
-       CMD_DISABLE_TX      = 6,
-       CMD_SCAN            = 8,
-       CMD_STOP_SCAN       = 9,
-       CMD_SET_KEYS        = 12,
-       CMD_READ_MEMORY     = 13,
-       CMD_WRITE_MEMORY    = 14,
-       CMD_SET_TEMPLATE    = 19,
-       CMD_TEST            = 23,
-       CMD_NOISE_HIST      = 28,
-       CMD_QUIET_ELEMENT_SET_STATE  = 29,
-       CMD_SET_BCN_MODE    = 33,
-       CMD_MEASUREMENT      = 34,
-       CMD_STOP_MEASUREMENT = 35,
-       CMD_SET_PS_MODE      = 37,
-       CMD_CHANNEL_SWITCH   = 38,
-       CMD_STOP_CHANNEL_SWICTH = 39,
-       CMD_AP_DISCOVERY     = 40,
-       CMD_STOP_AP_DISCOVERY = 41,
-       CMD_HEALTH_CHECK     = 45,
-       CMD_DEBUG            = 46,
-       CMD_TRIGGER_SCAN_TO  = 47,
-       CMD_CONNECTION_SCAN_CFG      = 48,
-       CMD_CONNECTION_SCAN_SSID_CFG = 49,
-       CMD_START_PERIODIC_SCAN      = 50,
-       CMD_STOP_PERIODIC_SCAN       = 51,
-       CMD_SET_PEER_STATE           = 52,
-       CMD_REMAIN_ON_CHANNEL        = 53,
-       CMD_CANCEL_REMAIN_ON_CHANNEL = 54,
-
-       CMD_CONFIG_FWLOGGER          = 55,
-       CMD_START_FWLOGGER           = 56,
-       CMD_STOP_FWLOGGER            = 57,
-
-       /* AP commands */
-       CMD_ADD_PEER                 = 62,
-       CMD_REMOVE_PEER              = 63,
+       CMD_INTERROGATE = 1, /* use this to read information elements */
+       CMD_CONFIGURE   = 2, /* use this to write information elements */
+       CMD_ENABLE_RX   = 3,
+       CMD_ENABLE_TX   = 4,
+       CMD_DISABLE_RX  = 5,
+       CMD_DISABLE_TX  = 6,
+       CMD_SCAN        = 7,
+       CMD_STOP_SCAN   = 8,
+       CMD_SET_KEYS    = 9,
+       CMD_READ_MEMORY = 10,
+       CMD_WRITE_MEMORY        = 11,
+       CMD_SET_TEMPLATE        = 12,
+       CMD_TEST                = 13,
+       CMD_NOISE_HIST          = 14,
+       CMD_QUIET_ELEMENT_SET_STATE = 15,
+       CMD_SET_BCN_MODE        = 16,
+
+       CMD_MEASUREMENT         = 17,
+       CMD_STOP_MEASUREMENT    = 18,
+       CMD_SET_PS_MODE         = 19,
+       CMD_CHANNEL_SWITCH      = 20,
+       CMD_STOP_CHANNEL_SWICTH = 21,
+       CMD_AP_DISCOVERY        = 22,
+       CMD_STOP_AP_DISCOVERY   = 23,
+       CMD_HEALTH_CHECK        = 24,
+       CMD_DEBUG               = 25,
+       CMD_TRIGGER_SCAN_TO     = 26,
+       CMD_CONNECTION_SCAN_CFG = 27,
+       CMD_CONNECTION_SCAN_SSID_CFG    = 28,
+       CMD_START_PERIODIC_SCAN = 29,
+       CMD_STOP_PERIODIC_SCAN  = 30,
+       CMD_SET_PEER_STATE      = 31,
+       CMD_REMAIN_ON_CHANNEL   = 32,
+       CMD_CANCEL_REMAIN_ON_CHANNEL    = 33,
+       CMD_CONFIG_FWLOGGER             = 34,
+       CMD_START_FWLOGGER                      = 35,
+       CMD_STOP_FWLOGGER                       = 36,
+
+       /* Access point commands */
+       CMD_ADD_PEER            = 37,
+       CMD_REMOVE_PEER         = 38,
 
        /* Role API */
-       CMD_ROLE_ENABLE              = 70,
-       CMD_ROLE_DISABLE             = 71,
-       CMD_ROLE_START               = 72,
-       CMD_ROLE_STOP                = 73,
+       CMD_ROLE_ENABLE         = 39,
+       CMD_ROLE_DISABLE        = 40,
+       CMD_ROLE_START          = 41,
+       CMD_ROLE_STOP           = 42,
 
-       /* WIFI Direct */
-       CMD_WFD_START_DISCOVERY      = 80,
-       CMD_WFD_STOP_DISCOVERY       = 81,
-       CMD_WFD_ATTRIBUTE_CONFIG     = 82,
+       /* DFS */
+       CMD_START_RADAR_DETECTION       = 43,
+       CMD_STOP_RADAR_DETECTION        = 44,
 
-       CMD_NOP                      = 100,
+       /* WIFI Direct */
+       CMD_WFD_START_DISCOVERY = 45,
+       CMD_WFD_STOP_DISCOVERY  = 46,
+       CMD_WFD_ATTRIBUTE_CONFIG        = 47,
+       CMD_NOP                 = 48,
+       CMD_LAST_COMMAND,
 
-       NUM_COMMANDS,
        MAX_COMMAND_ID = 0xFFFF,
 };
 
@@ -191,7 +196,7 @@ enum cmd_templ {
 /* unit ms */
 #define WL1271_COMMAND_TIMEOUT     2000
 #define WL1271_CMD_TEMPL_DFLT_SIZE 252
-#define WL1271_CMD_TEMPL_MAX_SIZE  548
+#define WL1271_CMD_TEMPL_MAX_SIZE  512
 #define WL1271_EVENT_TIMEOUT       750
 
 struct wl1271_cmd_header {
@@ -339,7 +344,9 @@ struct wl12xx_cmd_role_start {
                        u8 ssid_len;
                        u8 ssid[IEEE80211_MAX_SSID_LEN];
 
-                       u8 padding_1[5];
+                       u8 reset_tsf;
+
+                       u8 padding_1[4];
                } __packed ap;
        };
 } __packed;
@@ -364,14 +371,18 @@ struct cmd_enabledisable_path {
 struct wl1271_cmd_template_set {
        struct wl1271_cmd_header header;
 
-       __le16 len;
+       u8 role_id;
        u8 template_type;
+       __le16 len;
        u8 index;  /* relevant only for KLV_TEMPLATE type */
+       u8 padding[3];
+
        __le32 enabled_rates;
        u8 short_retry_limit;
        u8 long_retry_limit;
        u8 aflags;
        u8 reserved;
+
        u8 template_data[WL1271_CMD_TEMPL_MAX_SIZE];
 } __packed;
 
@@ -388,6 +399,7 @@ struct wl1271_tim {
 } __packed;
 
 enum wl1271_cmd_ps_mode {
+       STATION_AUTO_PS_MODE,   /* Dynamic Power Save */
        STATION_ACTIVE_MODE,
        STATION_POWER_SAVE_MODE
 };
@@ -397,7 +409,7 @@ struct wl1271_cmd_ps_params {
 
        u8 role_id;
        u8 ps_mode; /* STATION_* */
-       u8 padding[2];
+       u16 auto_ps_timeout;
 } __packed;
 
 /* HW encryption keys */
@@ -695,14 +707,18 @@ struct wl12xx_cmd_stop_fwlog {
 struct wl12xx_cmd_channel_switch {
        struct wl1271_cmd_header header;
 
+       u8 role_id;
+
        /* The new serving channel */
        u8 channel;
        /* Relative time of the serving channel switch in TBTT units */
        u8 switch_time;
-       /* 1: Suspend TX till switch time; 0: Do not suspend TX */
-       u8 tx_suspend;
-       /* 1: Flush TX at switch time; 0: Do not flush */
-       u8 flush;
+       /* Stop the role TX, should expect it after radar detection */
+       u8 stop_tx;
+       /* The target channel tx status 1-stopped 0-open*/
+       u8 post_switch_tx_disable;
+
+       u8 padding[3];
 } __packed;
 
 struct wl12xx_cmd_stop_channel_switch {
index 1bcfb017058d19da42682bdb817488575d8be6d1..3e581e19424c85f68afc272e7ec33ba458f1baf3 100644 (file)
@@ -66,7 +66,8 @@ enum {
 };
 
 enum {
-       CONF_HW_RXTX_RATE_MCS7 = 0,
+       CONF_HW_RXTX_RATE_MCS7_SGI = 0,
+       CONF_HW_RXTX_RATE_MCS7,
        CONF_HW_RXTX_RATE_MCS6,
        CONF_HW_RXTX_RATE_MCS5,
        CONF_HW_RXTX_RATE_MCS4,
@@ -91,6 +92,10 @@ enum {
        CONF_HW_RXTX_RATE_UNSUPPORTED = 0xff
 };
 
+/* Rates between and including these are MCS rates */
+#define CONF_HW_RXTX_RATE_MCS_MIN CONF_HW_RXTX_RATE_MCS7_SGI
+#define CONF_HW_RXTX_RATE_MCS_MAX CONF_HW_RXTX_RATE_MCS0
+
 enum {
        CONF_SG_DISABLE = 0,
        CONF_SG_PROTECTIVE,
@@ -312,6 +317,10 @@ enum {
        CONF_AP_BT_ACL_VAL_BT_SERVE_TIME,
        CONF_AP_BT_ACL_VAL_WL_SERVE_TIME,
 
+       /* CTS Diluting params */
+       CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH,
+       CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER,
+
        CONF_SG_TEMP_PARAM_1,
        CONF_SG_TEMP_PARAM_2,
        CONF_SG_TEMP_PARAM_3,
@@ -681,6 +690,9 @@ struct conf_tx_settings {
         */
        u8 tmpl_short_retry_limit;
        u8 tmpl_long_retry_limit;
+
+       /* Time in ms for Tx watchdog timer to expire */
+       u32 tx_watchdog_timeout;
 };
 
 enum {
@@ -809,6 +821,19 @@ struct conf_conn_settings {
         */
        u8 listen_interval;
 
+       /*
+        * Firmware wakeup conditions during suspend
+        * Range: CONF_WAKE_UP_EVENT_*
+        */
+       u8 suspend_wake_up_event;
+
+       /*
+        * Listen interval during suspend.
+        * Currently will be in DTIMs (1-10)
+        *
+        */
+       u8 suspend_listen_interval;
+
        /*
         * Enable or disable the beacon filtering.
         *
@@ -867,13 +892,6 @@ struct conf_conn_settings {
         */
        u8 ps_poll_threshold;
 
-       /*
-        * PS Poll failure recovery ACTIVE period length
-        *
-        * Range: u32 (ms)
-        */
-       u32 ps_poll_recovery_period;
-
        /*
         * Configuration of signal average weights.
         */
@@ -921,6 +939,18 @@ struct conf_conn_settings {
         */
        u8 psm_entry_nullfunc_retries;
 
+       /*
+        * Specifies the dynamic PS timeout in ms that will be used
+        * by the FW when in AUTO_PS mode
+        */
+       u16 dynamic_ps_timeout;
+
+       /*
+        * Specifies whether dynamic PS should be disabled and PSM forced.
+        * This is required for certain WiFi certification tests.
+        */
+       u8 forced_ps;
+
        /*
         *
         * Specifies the interval of the connection keep-alive null-func
@@ -1055,6 +1085,14 @@ struct conf_scan_settings {
         */
        u16 num_probe_reqs;
 
+       /*
+        * Scan trigger (split scan) timeout. The FW will split the scan
+        * operation into slices of the given time and allow the FW to schedule
+        * other tasks in between.
+        *
+        * Range: u32 Microsecs
+        */
+       u32 split_scan_timeout;
 };
 
 struct conf_sched_scan_settings {
index b85fd8c41e8f04065535b34eee0a3777190b8599..ec0fdc25b28027c58a39d711fc846c25b356eaee 100644 (file)
@@ -51,6 +51,7 @@ enum {
        DEBUG_FILTERS   = BIT(15),
        DEBUG_ADHOC     = BIT(16),
        DEBUG_AP        = BIT(17),
+       DEBUG_PROBE     = BIT(18),
        DEBUG_MASTER    = (DEBUG_ADHOC | DEBUG_AP),
        DEBUG_ALL       = ~0,
 };
index 15eb3a9c30ca11907ea92ef4aaf3ce794c91ea0c..e1cf727659650a90f9ae43f8636003409404eb00 100644 (file)
@@ -113,7 +113,7 @@ static void wl1271_debugfs_update_stats(struct wl1271 *wl)
        if (ret < 0)
                goto out;
 
-       if (wl->state == WL1271_STATE_ON &&
+       if (wl->state == WL1271_STATE_ON && !wl->plt &&
            time_after(jiffies, wl->stats.fw_stats_update +
                       msecs_to_jiffies(WL1271_DEBUGFS_STATS_LIFETIME))) {
                wl1271_acx_statistics(wl, wl->stats.fw_stats);
@@ -312,6 +312,181 @@ static const struct file_operations start_recovery_ops = {
        .llseek = default_llseek,
 };
 
+static ssize_t dynamic_ps_timeout_read(struct file *file, char __user *user_buf,
+                         size_t count, loff_t *ppos)
+{
+       struct wl1271 *wl = file->private_data;
+
+       return wl1271_format_buffer(user_buf, count,
+                                   ppos, "%d\n",
+                                   wl->conf.conn.dynamic_ps_timeout);
+}
+
+static ssize_t dynamic_ps_timeout_write(struct file *file,
+                                   const char __user *user_buf,
+                                   size_t count, loff_t *ppos)
+{
+       struct wl1271 *wl = file->private_data;
+       struct wl12xx_vif *wlvif;
+       unsigned long value;
+       int ret;
+
+       ret = kstrtoul_from_user(user_buf, count, 10, &value);
+       if (ret < 0) {
+               wl1271_warning("illegal value in dynamic_ps");
+               return -EINVAL;
+       }
+
+       if (value < 1 || value > 65535) {
+               wl1271_warning("dyanmic_ps_timeout is not in valid range");
+               return -ERANGE;
+       }
+
+       mutex_lock(&wl->mutex);
+
+       wl->conf.conn.dynamic_ps_timeout = value;
+
+       if (wl->state == WL1271_STATE_OFF)
+               goto out;
+
+       ret = wl1271_ps_elp_wakeup(wl);
+       if (ret < 0)
+               goto out;
+
+       /* In case we're already in PSM, trigger it again to set new timeout
+        * immediately without waiting for re-association
+        */
+
+       wl12xx_for_each_wlvif_sta(wl, wlvif) {
+               if (test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags))
+                       wl1271_ps_set_mode(wl, wlvif, STATION_AUTO_PS_MODE);
+       }
+
+       wl1271_ps_elp_sleep(wl);
+
+out:
+       mutex_unlock(&wl->mutex);
+       return count;
+}
+
+static const struct file_operations dynamic_ps_timeout_ops = {
+       .read = dynamic_ps_timeout_read,
+       .write = dynamic_ps_timeout_write,
+       .open = wl1271_open_file_generic,
+       .llseek = default_llseek,
+};
+
+static ssize_t forced_ps_read(struct file *file, char __user *user_buf,
+                         size_t count, loff_t *ppos)
+{
+       struct wl1271 *wl = file->private_data;
+
+       return wl1271_format_buffer(user_buf, count,
+                                   ppos, "%d\n",
+                                   wl->conf.conn.forced_ps);
+}
+
+static ssize_t forced_ps_write(struct file *file,
+                                   const char __user *user_buf,
+                                   size_t count, loff_t *ppos)
+{
+       struct wl1271 *wl = file->private_data;
+       struct wl12xx_vif *wlvif;
+       unsigned long value;
+       int ret, ps_mode;
+
+       ret = kstrtoul_from_user(user_buf, count, 10, &value);
+       if (ret < 0) {
+               wl1271_warning("illegal value in forced_ps");
+               return -EINVAL;
+       }
+
+       if (value != 1 && value != 0) {
+               wl1271_warning("forced_ps should be either 0 or 1");
+               return -ERANGE;
+       }
+
+       mutex_lock(&wl->mutex);
+
+       if (wl->conf.conn.forced_ps == value)
+               goto out;
+
+       wl->conf.conn.forced_ps = value;
+
+       if (wl->state == WL1271_STATE_OFF)
+               goto out;
+
+       ret = wl1271_ps_elp_wakeup(wl);
+       if (ret < 0)
+               goto out;
+
+       /* In case we're already in PSM, trigger it again to switch mode
+        * immediately without waiting for re-association
+        */
+
+       ps_mode = value ? STATION_POWER_SAVE_MODE : STATION_AUTO_PS_MODE;
+
+       wl12xx_for_each_wlvif_sta(wl, wlvif) {
+               if (test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags))
+                       wl1271_ps_set_mode(wl, wlvif, ps_mode);
+       }
+
+       wl1271_ps_elp_sleep(wl);
+
+out:
+       mutex_unlock(&wl->mutex);
+       return count;
+}
+
+static const struct file_operations forced_ps_ops = {
+       .read = forced_ps_read,
+       .write = forced_ps_write,
+       .open = wl1271_open_file_generic,
+       .llseek = default_llseek,
+};
+
+static ssize_t split_scan_timeout_read(struct file *file, char __user *user_buf,
+                         size_t count, loff_t *ppos)
+{
+       struct wl1271 *wl = file->private_data;
+
+       return wl1271_format_buffer(user_buf, count,
+                                   ppos, "%d\n",
+                                   wl->conf.scan.split_scan_timeout / 1000);
+}
+
+static ssize_t split_scan_timeout_write(struct file *file,
+                                   const char __user *user_buf,
+                                   size_t count, loff_t *ppos)
+{
+       struct wl1271 *wl = file->private_data;
+       unsigned long value;
+       int ret;
+
+       ret = kstrtoul_from_user(user_buf, count, 10, &value);
+       if (ret < 0) {
+               wl1271_warning("illegal value in split_scan_timeout");
+               return -EINVAL;
+       }
+
+       if (value == 0)
+               wl1271_info("split scan will be disabled");
+
+       mutex_lock(&wl->mutex);
+
+       wl->conf.scan.split_scan_timeout = value * 1000;
+
+       mutex_unlock(&wl->mutex);
+       return count;
+}
+
+static const struct file_operations split_scan_timeout_ops = {
+       .read = split_scan_timeout_read,
+       .write = split_scan_timeout_write,
+       .open = wl1271_open_file_generic,
+       .llseek = default_llseek,
+};
+
 static ssize_t driver_state_read(struct file *file, char __user *user_buf,
                                 size_t count, loff_t *ppos)
 {
@@ -446,6 +621,7 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf,
                        VIF_STATE_PRINT_INT(sta.basic_rate_idx);
                        VIF_STATE_PRINT_INT(sta.ap_rate_idx);
                        VIF_STATE_PRINT_INT(sta.p2p_rate_idx);
+                       VIF_STATE_PRINT_INT(sta.qos);
                } else {
                        VIF_STATE_PRINT_INT(ap.global_hlid);
                        VIF_STATE_PRINT_INT(ap.bcast_hlid);
@@ -471,7 +647,6 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf,
                VIF_STATE_PRINT_INT(default_key);
                VIF_STATE_PRINT_INT(aid);
                VIF_STATE_PRINT_INT(session_counter);
-               VIF_STATE_PRINT_INT(ps_poll_failures);
                VIF_STATE_PRINT_INT(psm_entry_retry);
                VIF_STATE_PRINT_INT(power_level);
                VIF_STATE_PRINT_INT(rssi_thold);
@@ -562,6 +737,64 @@ static const struct file_operations dtim_interval_ops = {
        .llseek = default_llseek,
 };
 
+
+
+static ssize_t suspend_dtim_interval_read(struct file *file,
+                                         char __user *user_buf,
+                                         size_t count, loff_t *ppos)
+{
+       struct wl1271 *wl = file->private_data;
+       u8 value;
+
+       if (wl->conf.conn.suspend_wake_up_event == CONF_WAKE_UP_EVENT_DTIM ||
+           wl->conf.conn.suspend_wake_up_event == CONF_WAKE_UP_EVENT_N_DTIM)
+               value = wl->conf.conn.suspend_listen_interval;
+       else
+               value = 0;
+
+       return wl1271_format_buffer(user_buf, count, ppos, "%d\n", value);
+}
+
+static ssize_t suspend_dtim_interval_write(struct file *file,
+                                          const char __user *user_buf,
+                                          size_t count, loff_t *ppos)
+{
+       struct wl1271 *wl = file->private_data;
+       unsigned long value;
+       int ret;
+
+       ret = kstrtoul_from_user(user_buf, count, 10, &value);
+       if (ret < 0) {
+               wl1271_warning("illegal value for suspend_dtim_interval");
+               return -EINVAL;
+       }
+
+       if (value < 1 || value > 10) {
+               wl1271_warning("suspend_dtim value is not in valid range");
+               return -ERANGE;
+       }
+
+       mutex_lock(&wl->mutex);
+
+       wl->conf.conn.suspend_listen_interval = value;
+       /* for some reason there are different event types for 1 and >1 */
+       if (value == 1)
+               wl->conf.conn.suspend_wake_up_event = CONF_WAKE_UP_EVENT_DTIM;
+       else
+               wl->conf.conn.suspend_wake_up_event = CONF_WAKE_UP_EVENT_N_DTIM;
+
+       mutex_unlock(&wl->mutex);
+       return count;
+}
+
+
+static const struct file_operations suspend_dtim_interval_ops = {
+       .read = suspend_dtim_interval_read,
+       .write = suspend_dtim_interval_write,
+       .open = wl1271_open_file_generic,
+       .llseek = default_llseek,
+};
+
 static ssize_t beacon_interval_read(struct file *file, char __user *user_buf,
                                    size_t count, loff_t *ppos)
 {
@@ -886,8 +1119,12 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl,
        DEBUGFS_ADD(driver_state, rootdir);
        DEBUGFS_ADD(vifs_state, rootdir);
        DEBUGFS_ADD(dtim_interval, rootdir);
+       DEBUGFS_ADD(suspend_dtim_interval, rootdir);
        DEBUGFS_ADD(beacon_interval, rootdir);
        DEBUGFS_ADD(beacon_filtering, rootdir);
+       DEBUGFS_ADD(dynamic_ps_timeout, rootdir);
+       DEBUGFS_ADD(forced_ps, rootdir);
+       DEBUGFS_ADD(split_scan_timeout, rootdir);
 
        streaming = debugfs_create_dir("rx_streaming", rootdir);
        if (!streaming || IS_ERR(streaming))
index d3280df68f5dee8de32537c22e6200f53fa69e60..c953717f38ebab69ed3acdbd117563925916a139 100644 (file)
 #include "scan.h"
 #include "wl12xx_80211.h"
 
-void wl1271_pspoll_work(struct work_struct *work)
-{
-       struct ieee80211_vif *vif;
-       struct wl12xx_vif *wlvif;
-       struct delayed_work *dwork;
-       struct wl1271 *wl;
-       int ret;
-
-       dwork = container_of(work, struct delayed_work, work);
-       wlvif = container_of(dwork, struct wl12xx_vif, pspoll_work);
-       vif = container_of((void *)wlvif, struct ieee80211_vif, drv_priv);
-       wl = wlvif->wl;
-
-       wl1271_debug(DEBUG_EVENT, "pspoll work");
-
-       mutex_lock(&wl->mutex);
-
-       if (unlikely(wl->state == WL1271_STATE_OFF))
-               goto out;
-
-       if (!test_and_clear_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags))
-               goto out;
-
-       if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
-               goto out;
-
-       /*
-        * if we end up here, then we were in powersave when the pspoll
-        * delivery failure occurred, and no-one changed state since, so
-        * we should go back to powersave.
-        */
-       ret = wl1271_ps_elp_wakeup(wl);
-       if (ret < 0)
-               goto out;
-
-       wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE,
-                          wlvif->basic_rate, true);
-
-       wl1271_ps_elp_sleep(wl);
-out:
-       mutex_unlock(&wl->mutex);
-};
-
-static void wl1271_event_pspoll_delivery_fail(struct wl1271 *wl,
-                                             struct wl12xx_vif *wlvif)
-{
-       int delay = wl->conf.conn.ps_poll_recovery_period;
-       int ret;
-
-       wlvif->ps_poll_failures++;
-       if (wlvif->ps_poll_failures == 1)
-               wl1271_info("AP with dysfunctional ps-poll, "
-                           "trying to work around it.");
-
-       /* force active mode receive data from the AP */
-       if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
-               ret = wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE,
-                                        wlvif->basic_rate, true);
-               if (ret < 0)
-                       return;
-               set_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags);
-               ieee80211_queue_delayed_work(wl->hw, &wlvif->pspoll_work,
-                                            msecs_to_jiffies(delay));
-       }
-
-       /*
-        * If already in active mode, lets we should be getting data from
-        * the AP right away. If we enter PSM too fast after this, and data
-        * remains on the AP, we will get another event like this, and we'll
-        * go into active once more.
-        */
-}
-
-static int wl1271_event_ps_report(struct wl1271 *wl,
-                                 struct wl12xx_vif *wlvif,
-                                 struct event_mailbox *mbox,
-                                 bool *beacon_loss)
-{
-       int ret = 0;
-       u32 total_retries = wl->conf.conn.psm_entry_retries;
-
-       wl1271_debug(DEBUG_EVENT, "ps_status: 0x%x", mbox->ps_status);
-
-       switch (mbox->ps_status) {
-       case EVENT_ENTER_POWER_SAVE_FAIL:
-               wl1271_debug(DEBUG_PSM, "PSM entry failed");
-
-               if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
-                       /* remain in active mode */
-                       wlvif->psm_entry_retry = 0;
-                       break;
-               }
-
-               if (wlvif->psm_entry_retry < total_retries) {
-                       wlvif->psm_entry_retry++;
-                       ret = wl1271_ps_set_mode(wl, wlvif,
-                                                STATION_POWER_SAVE_MODE,
-                                                wlvif->basic_rate, true);
-               } else {
-                       wl1271_info("No ack to nullfunc from AP.");
-                       wlvif->psm_entry_retry = 0;
-                       *beacon_loss = true;
-               }
-               break;
-       case EVENT_ENTER_POWER_SAVE_SUCCESS:
-               wlvif->psm_entry_retry = 0;
-
-               /*
-                * BET has only a minor effect in 5GHz and masks
-                * channel switch IEs, so we only enable BET on 2.4GHz
-               */
-               if (wlvif->band == IEEE80211_BAND_2GHZ)
-                       /* enable beacon early termination */
-                       ret = wl1271_acx_bet_enable(wl, wlvif, true);
-
-               if (wlvif->ps_compl) {
-                       complete(wlvif->ps_compl);
-                       wlvif->ps_compl = NULL;
-               }
-               break;
-       default:
-               break;
-       }
-
-       return ret;
-}
-
 static void wl1271_event_rssi_trigger(struct wl1271 *wl,
                                      struct wl12xx_vif *wlvif,
                                      struct event_mailbox *mbox)
@@ -205,21 +78,13 @@ static void wl1271_stop_ba_event(struct wl1271 *wl, struct wl12xx_vif *wlvif)
 static void wl12xx_event_soft_gemini_sense(struct wl1271 *wl,
                                               u8 enable)
 {
-       struct ieee80211_vif *vif;
        struct wl12xx_vif *wlvif;
 
        if (enable) {
-               /* disable dynamic PS when requested by the firmware */
-               wl12xx_for_each_wlvif_sta(wl, wlvif) {
-                       vif = wl12xx_wlvif_to_vif(wlvif);
-                       ieee80211_disable_dyn_ps(vif);
-               }
                set_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags);
        } else {
                clear_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags);
                wl12xx_for_each_wlvif_sta(wl, wlvif) {
-                       vif = wl12xx_wlvif_to_vif(wlvif);
-                       ieee80211_enable_dyn_ps(vif);
                        wl1271_recalc_rx_streaming(wl, wlvif);
                }
        }
@@ -237,7 +102,6 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
 {
        struct ieee80211_vif *vif;
        struct wl12xx_vif *wlvif;
-       int ret;
        u32 vector;
        bool beacon_loss = false;
        bool disconnect_sta = false;
@@ -293,21 +157,6 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
                beacon_loss = true;
        }
 
-       if (vector & PS_REPORT_EVENT_ID) {
-               wl1271_debug(DEBUG_EVENT, "PS_REPORT_EVENT");
-               wl12xx_for_each_wlvif_sta(wl, wlvif) {
-                       ret = wl1271_event_ps_report(wl, wlvif,
-                                                    mbox, &beacon_loss);
-                       if (ret < 0)
-                               return ret;
-               }
-       }
-
-       if (vector & PSPOLL_DELIVERY_FAILURE_EVENT_ID)
-               wl12xx_for_each_wlvif_sta(wl, wlvif) {
-                       wl1271_event_pspoll_delivery_fail(wl, wlvif);
-               }
-
        if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) {
                /* TODO: check actual multi-role support */
                wl1271_debug(DEBUG_EVENT, "RSSI_SNR_TRIGGER_0_EVENT");
@@ -344,7 +193,6 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
 
                /* TODO: configure only the relevant vif */
                wl12xx_for_each_wlvif_sta(wl, wlvif) {
-                       struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
                        bool success;
 
                        if (!test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS,
@@ -352,6 +200,8 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
                                continue;
 
                        success = mbox->channel_switch_status ? false : true;
+                       vif = wl12xx_wlvif_to_vif(wlvif);
+
                        ieee80211_chswitch_done(vif, success);
                }
        }
index 1d878ba47bf47b1dc85e9af485963a610ff92e59..057d193d3525c39adce0b26e4ac170b8688c08bc 100644 (file)
@@ -51,10 +51,10 @@ enum {
        SCAN_COMPLETE_EVENT_ID                   = BIT(10),
        WFD_DISCOVERY_COMPLETE_EVENT_ID          = BIT(11),
        AP_DISCOVERY_COMPLETE_EVENT_ID           = BIT(12),
-       PS_REPORT_EVENT_ID                       = BIT(13),
+       RESERVED1                                = BIT(13),
        PSPOLL_DELIVERY_FAILURE_EVENT_ID         = BIT(14),
-       DISCONNECT_EVENT_COMPLETE_ID             = BIT(15),
-       /* BIT(16) is reserved */
+       ROLE_STOP_COMPLETE_EVENT_ID              = BIT(15),
+       RADAR_DETECTED_EVENT_ID                  = BIT(16),
        CHANNEL_SWITCH_COMPLETE_EVENT_ID         = BIT(17),
        BSS_LOSE_EVENT_ID                        = BIT(18),
        REGAINED_BSS_EVENT_ID                    = BIT(19),
@@ -94,9 +94,9 @@ struct event_mailbox {
        u8 soft_gemini_sense_info;
        u8 soft_gemini_protective_info;
        s8 rssi_snr_trigger_metric[NUM_OF_RSSI_SNR_TRIGGERS];
-       u8 channel_switch_status;
+       u8 change_auto_mode_timeout;
        u8 scheduled_scan_status;
-       u8 ps_status;
+       u8 reserved4;
        /* tuned channel (roc) */
        u8 roc_channel;
 
@@ -119,17 +119,21 @@ struct event_mailbox {
        u8 rx_ba_allowed;
        u8 reserved_6[2];
 
+       /* Channel switch results */
+
+       u8 channel_switch_role_id;
+       u8 channel_switch_status;
+       u8 reserved_7[2];
+
        u8 ps_poll_delivery_failure_role_ids;
        u8 stopped_role_ids;
        u8 started_role_ids;
-       u8 change_auto_mode_timeout;
 
-       u8 reserved_7[12];
+       u8 reserved_8[9];
 } __packed;
 
 int wl1271_event_unmask(struct wl1271 *wl);
 void wl1271_event_mbox_config(struct wl1271 *wl);
 int wl1271_event_handle(struct wl1271 *wl, u8 mbox);
-void wl1271_pspoll_work(struct work_struct *work);
 
 #endif
index ca7ee59e4505b297c104197bfde176e34336458b..203fbebf09eb472e8fa49a9178264181c0b15b3b 100644 (file)
 int wl1271_init_templates_config(struct wl1271 *wl)
 {
        int ret, i;
+       size_t max_size;
 
        /* send empty templates for fw memory reservation */
-       ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL,
-                                     WL1271_CMD_TEMPL_DFLT_SIZE,
+       ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
+                                     CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL,
+                                     WL1271_CMD_TEMPL_MAX_SIZE,
                                      0, WL1271_RATE_AUTOMATIC);
        if (ret < 0)
                return ret;
 
-       ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
-                                     NULL, WL1271_CMD_TEMPL_DFLT_SIZE, 0,
+       ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
+                                     CMD_TEMPL_CFG_PROBE_REQ_5,
+                                     NULL, WL1271_CMD_TEMPL_MAX_SIZE, 0,
                                      WL1271_RATE_AUTOMATIC);
        if (ret < 0)
                return ret;
 
-       ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL,
+       ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
+                                     CMD_TEMPL_NULL_DATA, NULL,
                                      sizeof(struct wl12xx_null_data_template),
                                      0, WL1271_RATE_AUTOMATIC);
        if (ret < 0)
                return ret;
 
-       ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, NULL,
+       ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
+                                     CMD_TEMPL_PS_POLL, NULL,
                                      sizeof(struct wl12xx_ps_poll_template),
                                      0, WL1271_RATE_AUTOMATIC);
        if (ret < 0)
                return ret;
 
-       ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, NULL,
+       ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
+                                     CMD_TEMPL_QOS_NULL_DATA, NULL,
                                      sizeof
                                      (struct ieee80211_qos_hdr),
                                      0, WL1271_RATE_AUTOMATIC);
        if (ret < 0)
                return ret;
 
-       ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE, NULL,
+       ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
+                                     CMD_TEMPL_PROBE_RESPONSE, NULL,
                                      WL1271_CMD_TEMPL_DFLT_SIZE,
                                      0, WL1271_RATE_AUTOMATIC);
        if (ret < 0)
                return ret;
 
-       ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, NULL,
+       ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
+                                     CMD_TEMPL_BEACON, NULL,
                                      WL1271_CMD_TEMPL_DFLT_SIZE,
                                      0, WL1271_RATE_AUTOMATIC);
        if (ret < 0)
                return ret;
 
-       ret = wl1271_cmd_template_set(wl, CMD_TEMPL_ARP_RSP, NULL,
-                                     sizeof
-                                     (struct wl12xx_arp_rsp_template),
+       max_size = sizeof(struct wl12xx_arp_rsp_template) +
+                  WL1271_EXTRA_SPACE_MAX;
+       ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
+                                     CMD_TEMPL_ARP_RSP, NULL,
+                                     max_size,
                                      0, WL1271_RATE_AUTOMATIC);
        if (ret < 0)
                return ret;
@@ -93,19 +103,22 @@ int wl1271_init_templates_config(struct wl1271 *wl)
         * Put very large empty placeholders for all templates. These
         * reserve memory for later.
         */
-       ret = wl1271_cmd_template_set(wl, CMD_TEMPL_AP_PROBE_RESPONSE, NULL,
+       ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
+                                     CMD_TEMPL_AP_PROBE_RESPONSE, NULL,
                                      WL1271_CMD_TEMPL_MAX_SIZE,
                                      0, WL1271_RATE_AUTOMATIC);
        if (ret < 0)
                return ret;
 
-       ret = wl1271_cmd_template_set(wl, CMD_TEMPL_AP_BEACON, NULL,
+       ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
+                                     CMD_TEMPL_AP_BEACON, NULL,
                                      WL1271_CMD_TEMPL_MAX_SIZE,
                                      0, WL1271_RATE_AUTOMATIC);
        if (ret < 0)
                return ret;
 
-       ret = wl1271_cmd_template_set(wl, CMD_TEMPL_DEAUTH_AP, NULL,
+       ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
+                                     CMD_TEMPL_DEAUTH_AP, NULL,
                                      sizeof
                                      (struct wl12xx_disconn_template),
                                      0, WL1271_RATE_AUTOMATIC);
@@ -113,7 +126,8 @@ int wl1271_init_templates_config(struct wl1271 *wl)
                return ret;
 
        for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) {
-               ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, NULL,
+               ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
+                                             CMD_TEMPL_KLV, NULL,
                                              sizeof(struct ieee80211_qos_hdr),
                                              i, WL1271_RATE_AUTOMATIC);
                if (ret < 0)
@@ -140,7 +154,8 @@ static int wl1271_ap_init_deauth_template(struct wl1271 *wl,
                                             IEEE80211_STYPE_DEAUTH);
 
        rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
-       ret = wl1271_cmd_template_set(wl, CMD_TEMPL_DEAUTH_AP,
+       ret = wl1271_cmd_template_set(wl, wlvif->role_id,
+                                     CMD_TEMPL_DEAUTH_AP,
                                      tmpl, sizeof(*tmpl), 0, rate);
 
 out:
@@ -172,7 +187,8 @@ static int wl1271_ap_init_null_template(struct wl1271 *wl,
        memcpy(nullfunc->addr3, vif->addr, ETH_ALEN);
 
        rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
-       ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, nullfunc,
+       ret = wl1271_cmd_template_set(wl, wlvif->role_id,
+                                     CMD_TEMPL_NULL_DATA, nullfunc,
                                      sizeof(*nullfunc), 0, rate);
 
 out:
@@ -204,7 +220,8 @@ static int wl1271_ap_init_qos_null_template(struct wl1271 *wl,
        memcpy(qosnull->addr3, vif->addr, ETH_ALEN);
 
        rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
-       ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, qosnull,
+       ret = wl1271_cmd_template_set(wl, wlvif->role_id,
+                                     CMD_TEMPL_QOS_NULL_DATA, qosnull,
                                      sizeof(*qosnull), 0, rate);
 
 out:
index 079ad380e8ff7902ea2359d8e99a203e19941b81..c574a3b31e3127e514d74ab7d09a3e8e9664f15f 100644 (file)
 #define OCP_STATUS_REQ_FAILED 0x20000
 #define OCP_STATUS_RESP_ERROR 0x30000
 
+struct wl1271_partition_set wl12xx_part_table[PART_TABLE_LEN] = {
+       [PART_DOWN] = {
+               .mem = {
+                       .start = 0x00000000,
+                       .size  = 0x000177c0
+               },
+               .reg = {
+                       .start = REGISTERS_BASE,
+                       .size  = 0x00008800
+               },
+               .mem2 = {
+                       .start = 0x00000000,
+                       .size  = 0x00000000
+               },
+               .mem3 = {
+                       .start = 0x00000000,
+                       .size  = 0x00000000
+               },
+       },
+
+       [PART_WORK] = {
+               .mem = {
+                       .start = 0x00040000,
+                       .size  = 0x00014fc0
+               },
+               .reg = {
+                       .start = REGISTERS_BASE,
+                       .size  = 0x0000a000
+               },
+               .mem2 = {
+                       .start = 0x003004f8,
+                       .size  = 0x00000004
+               },
+               .mem3 = {
+                       .start = 0x00040404,
+                       .size  = 0x00000000
+               },
+       },
+
+       [PART_DRPW] = {
+               .mem = {
+                       .start = 0x00040000,
+                       .size  = 0x00014fc0
+               },
+               .reg = {
+                       .start = DRPW_BASE,
+                       .size  = 0x00006000
+               },
+               .mem2 = {
+                       .start = 0x00000000,
+                       .size  = 0x00000000
+               },
+               .mem3 = {
+                       .start = 0x00000000,
+                       .size  = 0x00000000
+               }
+       }
+};
+
 bool wl1271_set_block_size(struct wl1271 *wl)
 {
        if (wl->if_ops->set_block_size) {
index d398cbcea98677ae4b2c952b3077ed7d10c8920d..4fb3dab8c3b2124516ccac22ef9f71d82a9a50e2 100644 (file)
@@ -43,6 +43,8 @@
 
 #define HW_ACCESS_PRAM_MAX_RANGE       0x3c000
 
+extern struct wl1271_partition_set wl12xx_part_table[PART_TABLE_LEN];
+
 struct wl1271;
 
 void wl1271_disable_interrupts(struct wl1271 *wl);
index f8748cedbae19bfb4753ec579cec9c9040030fdf..39002363611e19460473f9bca60504c4475db640 100644 (file)
@@ -1,3 +1,4 @@
+
 /*
  * This file is part of wl1271
  *
@@ -115,6 +116,9 @@ static struct conf_drv_settings default_conf = {
                        [CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
                        [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
                        [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
+                       /* CTS Diluting params */
+                       [CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH] = 0,
+                       [CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER] = 0,
                },
                .state = CONF_SG_PROTECTIVE,
        },
@@ -213,10 +217,13 @@ static struct conf_drv_settings default_conf = {
                .basic_rate_5                = CONF_HW_BIT_RATE_6MBPS,
                .tmpl_short_retry_limit      = 10,
                .tmpl_long_retry_limit       = 10,
+               .tx_watchdog_timeout         = 5000,
        },
        .conn = {
                .wake_up_event               = CONF_WAKE_UP_EVENT_DTIM,
                .listen_interval             = 1,
+               .suspend_wake_up_event       = CONF_WAKE_UP_EVENT_N_DTIM,
+               .suspend_listen_interval     = 3,
                .bcn_filt_mode               = CONF_BCN_FILT_MODE_ENABLED,
                .bcn_filt_ie_count           = 2,
                .bcn_filt_ie = {
@@ -235,12 +242,13 @@ static struct conf_drv_settings default_conf = {
                .broadcast_timeout           = 20000,
                .rx_broadcast_in_ps          = 1,
                .ps_poll_threshold           = 10,
-               .ps_poll_recovery_period     = 700,
                .bet_enable                  = CONF_BET_MODE_ENABLE,
                .bet_max_consecutive         = 50,
                .psm_entry_retries           = 8,
                .psm_exit_retries            = 16,
                .psm_entry_nullfunc_retries  = 3,
+               .dynamic_ps_timeout          = 200,
+               .forced_ps                   = false,
                .keep_alive_interval         = 55000,
                .max_listen_interval         = 20,
        },
@@ -265,6 +273,7 @@ static struct conf_drv_settings default_conf = {
                .min_dwell_time_passive       = 100000,
                .max_dwell_time_passive       = 100000,
                .num_probe_reqs               = 2,
+               .split_scan_timeout           = 50000,
        },
        .sched_scan = {
                /* sched_scan requires dwell times in TU instead of TU/1000 */
@@ -384,15 +393,15 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
 static void wl1271_op_stop(struct ieee80211_hw *hw);
 static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif);
 
-static DEFINE_MUTEX(wl_list_mutex);
-static LIST_HEAD(wl_list);
-
-static int wl1271_check_operstate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
-                                 unsigned char operstate)
+static int wl12xx_set_authorized(struct wl1271 *wl,
+                                struct wl12xx_vif *wlvif)
 {
        int ret;
 
-       if (operstate != IF_OPER_UP)
+       if (WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS))
+               return -EINVAL;
+
+       if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
                return 0;
 
        if (test_and_set_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags))
@@ -407,76 +416,6 @@ static int wl1271_check_operstate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
        wl1271_info("Association completed.");
        return 0;
 }
-static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
-                            void *arg)
-{
-       struct net_device *dev = arg;
-       struct wireless_dev *wdev;
-       struct wiphy *wiphy;
-       struct ieee80211_hw *hw;
-       struct wl1271 *wl;
-       struct wl1271 *wl_temp;
-       struct wl12xx_vif *wlvif;
-       int ret = 0;
-
-       /* Check that this notification is for us. */
-       if (what != NETDEV_CHANGE)
-               return NOTIFY_DONE;
-
-       wdev = dev->ieee80211_ptr;
-       if (wdev == NULL)
-               return NOTIFY_DONE;
-
-       wiphy = wdev->wiphy;
-       if (wiphy == NULL)
-               return NOTIFY_DONE;
-
-       hw = wiphy_priv(wiphy);
-       if (hw == NULL)
-               return NOTIFY_DONE;
-
-       wl_temp = hw->priv;
-       mutex_lock(&wl_list_mutex);
-       list_for_each_entry(wl, &wl_list, list) {
-               if (wl == wl_temp)
-                       break;
-       }
-       mutex_unlock(&wl_list_mutex);
-       if (wl != wl_temp)
-               return NOTIFY_DONE;
-
-       mutex_lock(&wl->mutex);
-
-       if (wl->state == WL1271_STATE_OFF)
-               goto out;
-
-       if (dev->operstate != IF_OPER_UP)
-               goto out;
-       /*
-        * The correct behavior should be just getting the appropriate wlvif
-        * from the given dev, but currently we don't have a mac80211
-        * interface for it.
-        */
-       wl12xx_for_each_wlvif_sta(wl, wlvif) {
-               struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
-
-               if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
-                       continue;
-
-               ret = wl1271_ps_elp_wakeup(wl);
-               if (ret < 0)
-                       goto out;
-
-               wl1271_check_operstate(wl, wlvif,
-                                      ieee80211_get_operstate(vif));
-
-               wl1271_ps_elp_sleep(wl);
-       }
-out:
-       mutex_unlock(&wl->mutex);
-
-       return NOTIFY_OK;
-}
 
 static int wl1271_reg_notify(struct wiphy *wiphy,
                             struct regulatory_request *request)
@@ -615,6 +554,80 @@ static void wl1271_rx_streaming_timer(unsigned long data)
        ieee80211_queue_work(wl->hw, &wlvif->rx_streaming_disable_work);
 }
 
+/* wl->mutex must be taken */
+void wl12xx_rearm_tx_watchdog_locked(struct wl1271 *wl)
+{
+       /* if the watchdog is not armed, don't do anything */
+       if (wl->tx_allocated_blocks == 0)
+               return;
+
+       cancel_delayed_work(&wl->tx_watchdog_work);
+       ieee80211_queue_delayed_work(wl->hw, &wl->tx_watchdog_work,
+               msecs_to_jiffies(wl->conf.tx.tx_watchdog_timeout));
+}
+
+static void wl12xx_tx_watchdog_work(struct work_struct *work)
+{
+       struct delayed_work *dwork;
+       struct wl1271 *wl;
+
+       dwork = container_of(work, struct delayed_work, work);
+       wl = container_of(dwork, struct wl1271, tx_watchdog_work);
+
+       mutex_lock(&wl->mutex);
+
+       if (unlikely(wl->state == WL1271_STATE_OFF))
+               goto out;
+
+       /* Tx went out in the meantime - everything is ok */
+       if (unlikely(wl->tx_allocated_blocks == 0))
+               goto out;
+
+       /*
+        * if a ROC is in progress, we might not have any Tx for a long
+        * time (e.g. pending Tx on the non-ROC channels)
+        */
+       if (find_first_bit(wl->roc_map, WL12XX_MAX_ROLES) < WL12XX_MAX_ROLES) {
+               wl1271_debug(DEBUG_TX, "No Tx (in FW) for %d ms due to ROC",
+                            wl->conf.tx.tx_watchdog_timeout);
+               wl12xx_rearm_tx_watchdog_locked(wl);
+               goto out;
+       }
+
+       /*
+        * if a scan is in progress, we might not have any Tx for a long
+        * time
+        */
+       if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
+               wl1271_debug(DEBUG_TX, "No Tx (in FW) for %d ms due to scan",
+                            wl->conf.tx.tx_watchdog_timeout);
+               wl12xx_rearm_tx_watchdog_locked(wl);
+               goto out;
+       }
+
+       /*
+       * AP might cache a frame for a long time for a sleeping station,
+       * so rearm the timer if there's an AP interface with stations. If
+       * Tx is genuinely stuck we will most hopefully discover it when all
+       * stations are removed due to inactivity.
+       */
+       if (wl->active_sta_count) {
+               wl1271_debug(DEBUG_TX, "No Tx (in FW) for %d ms. AP has "
+                            " %d stations",
+                             wl->conf.tx.tx_watchdog_timeout,
+                             wl->active_sta_count);
+               wl12xx_rearm_tx_watchdog_locked(wl);
+               goto out;
+       }
+
+       wl1271_error("Tx stuck (in FW) for %d ms. Starting recovery",
+                    wl->conf.tx.tx_watchdog_timeout);
+       wl12xx_queue_recovery_work(wl);
+
+out:
+       mutex_unlock(&wl->mutex);
+}
+
 static void wl1271_conf_init(struct wl1271 *wl)
 {
 
@@ -672,8 +685,6 @@ static int wl1271_plt_init(struct wl1271 *wl)
                if (ret < 0)
                        return ret;
        }
-       if (ret < 0)
-               return ret;
 
        /* Chip-specific initializations */
        ret = wl1271_chip_specific_init(wl);
@@ -809,6 +820,18 @@ static void wl12xx_fw_status(struct wl1271 *wl,
 
        wl->tx_allocated_blocks -= freed_blocks;
 
+       /*
+        * If the FW freed some blocks:
+        * If we still have allocated blocks - re-arm the timer, Tx is
+        * not stuck. Otherwise, cancel the timer (no Tx currently).
+        */
+       if (freed_blocks) {
+               if (wl->tx_allocated_blocks)
+                       wl12xx_rearm_tx_watchdog_locked(wl);
+               else
+                       cancel_delayed_work(&wl->tx_watchdog_work);
+       }
+
        avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
 
        /*
@@ -985,16 +1008,70 @@ out:
        return IRQ_HANDLED;
 }
 
-static int wl1271_fetch_firmware(struct wl1271 *wl)
+struct vif_counter_data {
+       u8 counter;
+
+       struct ieee80211_vif *cur_vif;
+       bool cur_vif_running;
+};
+
+static void wl12xx_vif_count_iter(void *data, u8 *mac,
+                                 struct ieee80211_vif *vif)
+{
+       struct vif_counter_data *counter = data;
+
+       counter->counter++;
+       if (counter->cur_vif == vif)
+               counter->cur_vif_running = true;
+}
+
+/* caller must not hold wl->mutex, as it might deadlock */
+static void wl12xx_get_vif_count(struct ieee80211_hw *hw,
+                              struct ieee80211_vif *cur_vif,
+                              struct vif_counter_data *data)
+{
+       memset(data, 0, sizeof(*data));
+       data->cur_vif = cur_vif;
+
+       ieee80211_iterate_active_interfaces(hw,
+                                           wl12xx_vif_count_iter, data);
+}
+
+static int wl12xx_fetch_firmware(struct wl1271 *wl, bool plt)
 {
        const struct firmware *fw;
        const char *fw_name;
+       enum wl12xx_fw_type fw_type;
        int ret;
 
-       if (wl->chip.id == CHIP_ID_1283_PG20)
-               fw_name = WL128X_FW_NAME;
-       else
-               fw_name = WL127X_FW_NAME;
+       if (plt) {
+               fw_type = WL12XX_FW_TYPE_PLT;
+               if (wl->chip.id == CHIP_ID_1283_PG20)
+                       fw_name = WL128X_PLT_FW_NAME;
+               else
+                       fw_name = WL127X_PLT_FW_NAME;
+       } else {
+               /*
+                * we can't call wl12xx_get_vif_count() here because
+                * wl->mutex is taken, so use the cached last_vif_count value
+                */
+               if (wl->last_vif_count > 1) {
+                       fw_type = WL12XX_FW_TYPE_MULTI;
+                       if (wl->chip.id == CHIP_ID_1283_PG20)
+                               fw_name = WL128X_FW_NAME_MULTI;
+                       else
+                               fw_name = WL127X_FW_NAME_MULTI;
+               } else {
+                       fw_type = WL12XX_FW_TYPE_NORMAL;
+                       if (wl->chip.id == CHIP_ID_1283_PG20)
+                               fw_name = WL128X_FW_NAME_SINGLE;
+                       else
+                               fw_name = WL127X_FW_NAME_SINGLE;
+               }
+       }
+
+       if (wl->fw_type == fw_type)
+               return 0;
 
        wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
 
@@ -1013,6 +1090,7 @@ static int wl1271_fetch_firmware(struct wl1271 *wl)
        }
 
        vfree(wl->fw);
+       wl->fw_type = WL12XX_FW_TYPE_NONE;
        wl->fw_len = fw->size;
        wl->fw = vmalloc(wl->fw_len);
 
@@ -1024,7 +1102,7 @@ static int wl1271_fetch_firmware(struct wl1271 *wl)
 
        memcpy(wl->fw, fw->data, wl->fw_len);
        ret = 0;
-
+       wl->fw_type = fw_type;
 out:
        release_firmware(fw);
 
@@ -1152,7 +1230,7 @@ static void wl1271_recovery_work(struct work_struct *work)
 
        mutex_lock(&wl->mutex);
 
-       if (wl->state != WL1271_STATE_ON)
+       if (wl->state != WL1271_STATE_ON || wl->plt)
                goto out_unlock;
 
        /* Avoid a recursive recovery */
@@ -1163,7 +1241,8 @@ static void wl1271_recovery_work(struct work_struct *work)
        wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
                    wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
 
-       BUG_ON(bug_on_recovery);
+       BUG_ON(bug_on_recovery &&
+              !test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags));
 
        /*
         * Advance security sequence number to overcome potential progress
@@ -1232,10 +1311,9 @@ static int wl1271_setup(struct wl1271 *wl)
        return 0;
 }
 
-static int wl1271_chip_wakeup(struct wl1271 *wl)
+static int wl12xx_set_power_on(struct wl1271 *wl)
 {
-       struct wl1271_partition_set partition;
-       int ret = 0;
+       int ret;
 
        msleep(WL1271_PRE_POWER_ON_SLEEP);
        ret = wl1271_power_on(wl);
@@ -1245,20 +1323,22 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
        wl1271_io_reset(wl);
        wl1271_io_init(wl);
 
-       /* We don't need a real memory partition here, because we only want
-        * to use the registers at this point. */
-       memset(&partition, 0, sizeof(partition));
-       partition.reg.start = REGISTERS_BASE;
-       partition.reg.size = REGISTERS_DOWN_SIZE;
-       wl1271_set_partition(wl, &partition);
+       wl1271_set_partition(wl, &wl12xx_part_table[PART_DOWN]);
 
        /* ELP module wake up */
        wl1271_fw_wakeup(wl);
 
-       /* whal_FwCtrl_BootSm() */
+out:
+       return ret;
+}
+
+static int wl12xx_chip_wakeup(struct wl1271 *wl, bool plt)
+{
+       int ret = 0;
 
-       /* 0. read chip id from CHIP_ID */
-       wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
+       ret = wl12xx_set_power_on(wl);
+       if (ret < 0)
+               goto out;
 
        /*
         * For wl127x based devices we could use the default block
@@ -1307,11 +1387,9 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
                goto out;
        }
 
-       if (wl->fw == NULL) {
-               ret = wl1271_fetch_firmware(wl);
-               if (ret < 0)
-                       goto out;
-       }
+       ret = wl12xx_fetch_firmware(wl, plt);
+       if (ret < 0)
+               goto out;
 
        /* No NVS from netlink, try to get it from the filesystem */
        if (wl->nvs == NULL) {
@@ -1343,7 +1421,7 @@ int wl1271_plt_start(struct wl1271 *wl)
 
        while (retries) {
                retries--;
-               ret = wl1271_chip_wakeup(wl);
+               ret = wl12xx_chip_wakeup(wl, true);
                if (ret < 0)
                        goto power_off;
 
@@ -1355,7 +1433,8 @@ int wl1271_plt_start(struct wl1271 *wl)
                if (ret < 0)
                        goto irq_disable;
 
-               wl->state = WL1271_STATE_PLT;
+               wl->plt = true;
+               wl->state = WL1271_STATE_ON;
                wl1271_notice("firmware booted in PLT mode (%s)",
                              wl->chip.fw_ver_str);
 
@@ -1391,41 +1470,52 @@ out:
        return ret;
 }
 
-static int __wl1271_plt_stop(struct wl1271 *wl)
+int wl1271_plt_stop(struct wl1271 *wl)
 {
        int ret = 0;
 
        wl1271_notice("power down");
 
-       if (wl->state != WL1271_STATE_PLT) {
+       /*
+        * Interrupts must be disabled before setting the state to OFF.
+        * Otherwise, the interrupt handler might be called and exit without
+        * reading the interrupt status.
+        */
+       wl1271_disable_interrupts(wl);
+       mutex_lock(&wl->mutex);
+       if (!wl->plt) {
+               mutex_unlock(&wl->mutex);
+
+               /*
+                * This will not necessarily enable interrupts as interrupts
+                * may have been disabled when op_stop was called. It will,
+                * however, balance the above call to disable_interrupts().
+                */
+               wl1271_enable_interrupts(wl);
+
                wl1271_error("cannot power down because not in PLT "
                             "state: %d", wl->state);
                ret = -EBUSY;
                goto out;
        }
 
-       wl1271_power_off(wl);
-
-       wl->state = WL1271_STATE_OFF;
-       wl->rx_counter = 0;
-
        mutex_unlock(&wl->mutex);
-       wl1271_disable_interrupts(wl);
+
        wl1271_flush_deferred_work(wl);
        cancel_work_sync(&wl->netstack_work);
        cancel_work_sync(&wl->recovery_work);
-       mutex_lock(&wl->mutex);
-out:
-       return ret;
-}
-
-int wl1271_plt_stop(struct wl1271 *wl)
-{
-       int ret;
+       cancel_delayed_work_sync(&wl->elp_work);
+       cancel_delayed_work_sync(&wl->tx_watchdog_work);
 
        mutex_lock(&wl->mutex);
-       ret = __wl1271_plt_stop(wl);
+       wl1271_power_off(wl);
+       wl->flags = 0;
+       wl->state = WL1271_STATE_OFF;
+       wl->plt = false;
+       wl->rx_counter = 0;
        mutex_unlock(&wl->mutex);
+
+out:
        return ret;
 }
 
@@ -1457,7 +1547,8 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
                goto out;
        }
 
-       wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
+       wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d len %d",
+                    hlid, q, skb->len);
        skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
 
        wl->tx_queue_count[q]++;
@@ -1555,10 +1646,6 @@ static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
 }
 
 
-static struct notifier_block wl1271_dev_notifier = {
-       .notifier_call = wl1271_dev_notify,
-};
-
 #ifdef CONFIG_PM
 static int wl1271_configure_suspend_sta(struct wl1271 *wl,
                                        struct wl12xx_vif *wlvif)
@@ -1574,38 +1661,16 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl,
        if (ret < 0)
                goto out_unlock;
 
-       /* enter psm if needed*/
-       if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
-               DECLARE_COMPLETION_ONSTACK(compl);
-
-               wlvif->ps_compl = &compl;
-               ret = wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE,
-                                  wlvif->basic_rate, true);
-               if (ret < 0)
-                       goto out_sleep;
-
-               /* we must unlock here so we will be able to get events */
-               wl1271_ps_elp_sleep(wl);
-               mutex_unlock(&wl->mutex);
+       ret = wl1271_acx_wake_up_conditions(wl, wlvif,
+                                   wl->conf.conn.suspend_wake_up_event,
+                                   wl->conf.conn.suspend_listen_interval);
 
-               ret = wait_for_completion_timeout(
-                       &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
+       if (ret < 0)
+               wl1271_error("suspend: set wake up conditions failed: %d", ret);
 
-               mutex_lock(&wl->mutex);
-               if (ret <= 0) {
-                       wl1271_warning("couldn't enter ps mode!");
-                       ret = -EBUSY;
-                       goto out_cleanup;
-               }
 
-               ret = wl1271_ps_elp_wakeup(wl);
-               if (ret < 0)
-                       goto out_cleanup;
-       }
-out_sleep:
        wl1271_ps_elp_sleep(wl);
-out_cleanup:
-       wlvif->ps_compl = NULL;
+
 out_unlock:
        mutex_unlock(&wl->mutex);
        return ret;
@@ -1648,11 +1713,11 @@ static int wl1271_configure_suspend(struct wl1271 *wl,
 static void wl1271_configure_resume(struct wl1271 *wl,
                                    struct wl12xx_vif *wlvif)
 {
-       int ret;
-       bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
+       int ret = 0;
        bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
+       bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
 
-       if (!is_sta && !is_ap)
+       if ((!is_ap) && (!is_sta))
                return;
 
        mutex_lock(&wl->mutex);
@@ -1661,12 +1726,16 @@ static void wl1271_configure_resume(struct wl1271 *wl,
                goto out;
 
        if (is_sta) {
-               /* exit psm if it wasn't configured */
-               if (!test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags))
-                       wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE,
-                                          wlvif->basic_rate, true);
+               ret = wl1271_acx_wake_up_conditions(wl, wlvif,
+                                   wl->conf.conn.wake_up_event,
+                                   wl->conf.conn.listen_interval);
+
+               if (ret < 0)
+                       wl1271_error("resume: wake up conditions failed: %d",
+                                    ret);
+
        } else if (is_ap) {
-               wl1271_acx_beacon_filter_opt(wl, wlvif, false);
+               ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
        }
 
        wl1271_ps_elp_sleep(wl);
@@ -1684,6 +1753,8 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
        wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
        WARN_ON(!wow || !wow->any);
 
+       wl1271_tx_flush(wl);
+
        wl->wow_enabled = true;
        wl12xx_for_each_wlvif(wl, wlvif) {
                ret = wl1271_configure_suspend(wl, wlvif);
@@ -1709,9 +1780,6 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
 
        wl1271_enable_interrupts(wl);
        flush_work(&wl->tx_work);
-       wl12xx_for_each_wlvif(wl, wlvif) {
-               flush_delayed_work(&wlvif->pspoll_work);
-       }
        flush_delayed_work(&wl->elp_work);
 
        return 0;
@@ -1778,11 +1846,25 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
 
        wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
 
+       /*
+        * Interrupts must be disabled before setting the state to OFF.
+        * Otherwise, the interrupt handler might be called and exit without
+        * reading the interrupt status.
+        */
+       wl1271_disable_interrupts(wl);
        mutex_lock(&wl->mutex);
        if (wl->state == WL1271_STATE_OFF) {
                mutex_unlock(&wl->mutex);
+
+               /*
+                * This will not necessarily enable interrupts as interrupts
+                * may have been disabled when op_stop was called. It will,
+                * however, balance the above call to disable_interrupts().
+                */
+               wl1271_enable_interrupts(wl);
                return;
        }
+
        /*
         * this must be before the cancel_work calls below, so that the work
         * functions don't perform further work.
@@ -1790,16 +1872,12 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
        wl->state = WL1271_STATE_OFF;
        mutex_unlock(&wl->mutex);
 
-       mutex_lock(&wl_list_mutex);
-       list_del(&wl->list);
-       mutex_unlock(&wl_list_mutex);
-
-       wl1271_disable_interrupts(wl);
        wl1271_flush_deferred_work(wl);
        cancel_delayed_work_sync(&wl->scan_complete_work);
        cancel_work_sync(&wl->netstack_work);
        cancel_work_sync(&wl->tx_work);
        cancel_delayed_work_sync(&wl->elp_work);
+       cancel_delayed_work_sync(&wl->tx_watchdog_work);
 
        /* let's notify MAC80211 about the remaining pending TX frames */
        wl12xx_tx_reset(wl, true);
@@ -1969,7 +2047,6 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
                  wl1271_rx_streaming_enable_work);
        INIT_WORK(&wlvif->rx_streaming_disable_work,
                  wl1271_rx_streaming_disable_work);
-       INIT_DELAYED_WORK(&wlvif->pspoll_work, wl1271_pspoll_work);
        INIT_LIST_HEAD(&wlvif->list);
 
        setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
@@ -1986,7 +2063,7 @@ static bool wl12xx_init_fw(struct wl1271 *wl)
 
        while (retries) {
                retries--;
-               ret = wl1271_chip_wakeup(wl);
+               ret = wl12xx_chip_wakeup(wl, false);
                if (ret < 0)
                        goto power_off;
 
@@ -2051,11 +2128,60 @@ static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif)
        return wlvif->dev_hlid != WL12XX_INVALID_LINK_ID;
 }
 
+/*
+ * Check whether a fw switch (i.e. moving from one loaded
+ * fw to another) is needed. This function is also responsible
+ * for updating wl->last_vif_count, so it must be called before
+ * loading a non-plt fw (so the correct fw (single-role/multi-role)
+ * will be used).
+ */
+static bool wl12xx_need_fw_change(struct wl1271 *wl,
+                                 struct vif_counter_data vif_counter_data,
+                                 bool add)
+{
+       enum wl12xx_fw_type current_fw = wl->fw_type;
+       u8 vif_count = vif_counter_data.counter;
+
+       if (test_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags))
+               return false;
+
+       /* increase the vif count if this is a new vif */
+       if (add && !vif_counter_data.cur_vif_running)
+               vif_count++;
+
+       wl->last_vif_count = vif_count;
+
+       /* no need for fw change if the device is OFF */
+       if (wl->state == WL1271_STATE_OFF)
+               return false;
+
+       if (vif_count > 1 && current_fw == WL12XX_FW_TYPE_NORMAL)
+               return true;
+       if (vif_count <= 1 && current_fw == WL12XX_FW_TYPE_MULTI)
+               return true;
+
+       return false;
+}
+
+/*
+ * Enter "forced psm". Make sure the sta is in psm against the ap,
+ * to make the fw switch a bit more disconnection-persistent.
+ */
+static void wl12xx_force_active_psm(struct wl1271 *wl)
+{
+       struct wl12xx_vif *wlvif;
+
+       wl12xx_for_each_wlvif_sta(wl, wlvif) {
+               wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE);
+       }
+}
+
 static int wl1271_op_add_interface(struct ieee80211_hw *hw,
                                   struct ieee80211_vif *vif)
 {
        struct wl1271 *wl = hw->priv;
        struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
+       struct vif_counter_data vif_count;
        int ret = 0;
        u8 role_type;
        bool booted = false;
@@ -2066,18 +2192,13 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
        wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
                     ieee80211_vif_type_p2p(vif), vif->addr);
 
+       wl12xx_get_vif_count(hw, vif, &vif_count);
+
        mutex_lock(&wl->mutex);
        ret = wl1271_ps_elp_wakeup(wl);
        if (ret < 0)
                goto out_unlock;
 
-       if (wl->vif) {
-               wl1271_debug(DEBUG_MAC80211,
-                            "multiple vifs are not supported yet");
-               ret = -EBUSY;
-               goto out;
-       }
-
        /*
         * in some very corner case HW recovery scenarios its possible to
         * get here before __wl1271_op_remove_interface is complete, so
@@ -2089,6 +2210,7 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
                goto out;
        }
 
+
        ret = wl12xx_init_vif_data(wl, vif);
        if (ret < 0)
                goto out;
@@ -2100,6 +2222,14 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
                goto out;
        }
 
+       if (wl12xx_need_fw_change(wl, vif_count, true)) {
+               wl12xx_force_active_psm(wl);
+               set_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags);
+               mutex_unlock(&wl->mutex);
+               wl1271_recovery_work(&wl->recovery_work);
+               return 0;
+       }
+
        /*
         * TODO: after the nvs issue will be solved, move this block
         * to start(), and make sure here the driver is ON.
@@ -2109,7 +2239,7 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
                 * we still need this in order to configure the fw
                 * while uploading the nvs
                 */
-               memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
+               memcpy(wl->addresses[0].addr, vif->addr, ETH_ALEN);
 
                booted = wl12xx_init_fw(wl);
                if (!booted) {
@@ -2142,7 +2272,6 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
        if (ret < 0)
                goto out;
 
-       wl->vif = vif;
        list_add(&wlvif->list, &wl->wlvif_list);
        set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
 
@@ -2155,11 +2284,6 @@ out:
 out_unlock:
        mutex_unlock(&wl->mutex);
 
-       mutex_lock(&wl_list_mutex);
-       if (!ret)
-               list_add(&wl->list, &wl_list);
-       mutex_unlock(&wl_list_mutex);
-
        return ret;
 }
 
@@ -2175,20 +2299,20 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
        if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
                return;
 
-       wl->vif = NULL;
-
        /* because of hardware recovery, we may get here twice */
        if (wl->state != WL1271_STATE_ON)
                return;
 
        wl1271_info("down");
 
-       /* enable dyn ps just in case (if left on due to fw crash etc) */
-       if (wlvif->bss_type == BSS_TYPE_STA_BSS)
-               ieee80211_enable_dyn_ps(vif);
-
        if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
            wl->scan_vif == vif) {
+               /*
+                * Rearm the tx watchdog just before idling scan. This
+                * prevents just-finished scans from triggering the watchdog
+                */
+               wl12xx_rearm_tx_watchdog_locked(wl);
+
                wl->scan.state = WL1271_SCAN_STATE_IDLE;
                memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
                wl->scan_vif = NULL;
@@ -2253,10 +2377,10 @@ deinit:
                wl->sta_count--;
 
        mutex_unlock(&wl->mutex);
+
        del_timer_sync(&wlvif->rx_streaming_timer);
        cancel_work_sync(&wlvif->rx_streaming_enable_work);
        cancel_work_sync(&wlvif->rx_streaming_disable_work);
-       cancel_delayed_work_sync(&wlvif->pspoll_work);
 
        mutex_lock(&wl->mutex);
 }
@@ -2267,7 +2391,10 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
        struct wl1271 *wl = hw->priv;
        struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
        struct wl12xx_vif *iter;
+       struct vif_counter_data vif_count;
+       bool cancel_recovery = true;
 
+       wl12xx_get_vif_count(hw, vif, &vif_count);
        mutex_lock(&wl->mutex);
 
        if (wl->state == WL1271_STATE_OFF ||
@@ -2286,20 +2413,34 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
                break;
        }
        WARN_ON(iter != wlvif);
+       if (wl12xx_need_fw_change(wl, vif_count, false)) {
+               wl12xx_force_active_psm(wl);
+               set_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags);
+               wl12xx_queue_recovery_work(wl);
+               cancel_recovery = false;
+       }
 out:
        mutex_unlock(&wl->mutex);
-       cancel_work_sync(&wl->recovery_work);
+       if (cancel_recovery)
+               cancel_work_sync(&wl->recovery_work);
 }
 
 static int wl12xx_op_change_interface(struct ieee80211_hw *hw,
                                      struct ieee80211_vif *vif,
                                      enum nl80211_iftype new_type, bool p2p)
 {
+       struct wl1271 *wl = hw->priv;
+       int ret;
+
+       set_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags);
        wl1271_op_remove_interface(hw, vif);
 
-       vif->type = ieee80211_iftype_p2p(new_type, p2p);
+       vif->type = new_type;
        vif->p2p = p2p;
-       return wl1271_op_add_interface(hw, vif);
+       ret = wl1271_op_add_interface(hw, vif);
+
+       clear_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags);
+       return ret;
 }
 
 static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
@@ -2320,6 +2461,9 @@ static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
        if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
                wl1271_info("JOIN while associated.");
 
+       /* clear encryption type */
+       wlvif->encryption_type = KEY_NONE;
+
        if (set_assoc)
                set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
 
@@ -2470,71 +2614,61 @@ static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
                                wl1271_warning("rate policy for channel "
                                               "failed %d", ret);
 
-                       if (test_bit(WLVIF_FLAG_STA_ASSOCIATED,
-                                    &wlvif->flags)) {
-                               if (wl12xx_dev_role_started(wlvif)) {
-                                       /* roaming */
-                                       ret = wl12xx_croc(wl,
-                                                         wlvif->dev_role_id);
-                                       if (ret < 0)
-                                               return ret;
-                               }
-                               ret = wl1271_join(wl, wlvif, false);
+                       /*
+                        * change the ROC channel. do it only if we are
+                        * not idle. otherwise, CROC will be called
+                        * anyway.
+                        */
+                       if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED,
+                                     &wlvif->flags) &&
+                           wl12xx_dev_role_started(wlvif) &&
+                           !(conf->flags & IEEE80211_CONF_IDLE)) {
+                               ret = wl12xx_stop_dev(wl, wlvif);
                                if (ret < 0)
-                                       wl1271_warning("cmd join on channel "
-                                                      "failed %d", ret);
-                       } else {
-                               /*
-                                * change the ROC channel. do it only if we are
-                                * not idle. otherwise, CROC will be called
-                                * anyway.
-                                */
-                               if (wl12xx_dev_role_started(wlvif) &&
-                                   !(conf->flags & IEEE80211_CONF_IDLE)) {
-                                       ret = wl12xx_stop_dev(wl, wlvif);
-                                       if (ret < 0)
-                                               return ret;
+                                       return ret;
 
-                                       ret = wl12xx_start_dev(wl, wlvif);
-                                       if (ret < 0)
-                                               return ret;
-                               }
+                               ret = wl12xx_start_dev(wl, wlvif);
+                               if (ret < 0)
+                                       return ret;
                        }
                }
        }
 
-       /*
-        * if mac80211 changes the PSM mode, make sure the mode is not
-        * incorrectly changed after the pspoll failure active window.
-        */
-       if (changed & IEEE80211_CONF_CHANGE_PS)
-               clear_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags);
+       if ((changed & IEEE80211_CONF_CHANGE_PS) && !is_ap) {
 
-       if (conf->flags & IEEE80211_CONF_PS &&
-           !test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
-               set_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
+               if ((conf->flags & IEEE80211_CONF_PS) &&
+                   test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
+                   !test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
 
-               /*
-                * We enter PSM only if we're already associated.
-                * If we're not, we'll enter it when joining an SSID,
-                * through the bss_info_changed() hook.
-                */
-               if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
-                       wl1271_debug(DEBUG_PSM, "psm enabled");
-                       ret = wl1271_ps_set_mode(wl, wlvif,
-                                                STATION_POWER_SAVE_MODE,
-                                                wlvif->basic_rate, true);
-               }
-       } else if (!(conf->flags & IEEE80211_CONF_PS) &&
-                  test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
-               wl1271_debug(DEBUG_PSM, "psm disabled");
+                       int ps_mode;
+                       char *ps_mode_str;
+
+                       if (wl->conf.conn.forced_ps) {
+                               ps_mode = STATION_POWER_SAVE_MODE;
+                               ps_mode_str = "forced";
+                       } else {
+                               ps_mode = STATION_AUTO_PS_MODE;
+                               ps_mode_str = "auto";
+                       }
+
+                       wl1271_debug(DEBUG_PSM, "%s ps enabled", ps_mode_str);
+
+                       ret = wl1271_ps_set_mode(wl, wlvif, ps_mode);
+
+                       if (ret < 0)
+                               wl1271_warning("enter %s ps failed %d",
+                                              ps_mode_str, ret);
+
+               } else if (!(conf->flags & IEEE80211_CONF_PS) &&
+                          test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
 
-               clear_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
+                       wl1271_debug(DEBUG_PSM, "auto ps disabled");
 
-               if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags))
                        ret = wl1271_ps_set_mode(wl, wlvif,
-                                                STATION_ACTIVE_MODE,
-                                                wlvif->basic_rate, true);
+                                                STATION_ACTIVE_MODE);
+                       if (ret < 0)
+                               wl1271_warning("exit auto ps failed %d", ret);
+               }
        }
 
        if (conf->power_level != wlvif->power_level) {
@@ -2974,6 +3108,21 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                        wl1271_error("Could not add or replace key");
                        goto out_sleep;
                }
+
+               /*
+                * reconfiguring arp response if the unicast (or common)
+                * encryption key type was changed
+                */
+               if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
+                   (sta || key_type == KEY_WEP) &&
+                   wlvif->encryption_type != key_type) {
+                       wlvif->encryption_type = key_type;
+                       ret = wl1271_cmd_build_arp_rsp(wl, wlvif);
+                       if (ret < 0) {
+                               wl1271_warning("build arp rsp failed: %d", ret);
+                               goto out_sleep;
+                       }
+               }
                break;
 
        case DISABLE_KEY:
@@ -3007,8 +3156,6 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
                             struct cfg80211_scan_request *req)
 {
        struct wl1271 *wl = hw->priv;
-       struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
-
        int ret;
        u8 *ssid = NULL;
        size_t len = 0;
@@ -3036,17 +3183,13 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
        if (ret < 0)
                goto out;
 
-       if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
-           test_bit(wlvif->role_id, wl->roc_map)) {
+       /* fail if there is any role in ROC */
+       if (find_first_bit(wl->roc_map, WL12XX_MAX_ROLES) < WL12XX_MAX_ROLES) {
                /* don't allow scanning right now */
                ret = -EBUSY;
                goto out_sleep;
        }
 
-       /* cancel ROC before scanning */
-       if (wl12xx_dev_role_started(wlvif))
-               wl12xx_stop_dev(wl, wlvif);
-
        ret = wl1271_scan(hw->priv, vif, ssid, len, req);
 out_sleep:
        wl1271_ps_elp_sleep(wl);
@@ -3081,6 +3224,13 @@ static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
                if (ret < 0)
                        goto out_sleep;
        }
+
+       /*
+        * Rearm the tx watchdog just before idling scan. This
+        * prevents just-finished scans from triggering the watchdog
+        */
+       wl12xx_rearm_tx_watchdog_locked(wl);
+
        wl->scan.state = WL1271_SCAN_STATE_IDLE;
        memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
        wl->scan_vif = NULL;
@@ -3108,6 +3258,11 @@ static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
 
        mutex_lock(&wl->mutex);
 
+       if (wl->state == WL1271_STATE_OFF) {
+               ret = -EAGAIN;
+               goto out;
+       }
+
        ret = wl1271_ps_elp_wakeup(wl);
        if (ret < 0)
                goto out;
@@ -3139,6 +3294,9 @@ static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
 
        mutex_lock(&wl->mutex);
 
+       if (wl->state == WL1271_STATE_OFF)
+               goto out;
+
        ret = wl1271_ps_elp_wakeup(wl);
        if (ret < 0)
                goto out;
@@ -3266,6 +3424,7 @@ static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
 static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,
                                         struct ieee80211_vif *vif)
 {
+       struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
        struct sk_buff *skb;
        int ret;
 
@@ -3273,7 +3432,7 @@ static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,
        if (!skb)
                return -EOPNOTSUPP;
 
-       ret = wl1271_cmd_template_set(wl,
+       ret = wl1271_cmd_template_set(wl, wlvif->role_id,
                                      CMD_TEMPL_AP_PROBE_RESPONSE,
                                      skb->data,
                                      skb->len, 0,
@@ -3297,7 +3456,7 @@ static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl,
 
        /* no need to change probe response if the SSID is set correctly */
        if (wlvif->ssid_len > 0)
-               return wl1271_cmd_template_set(wl,
+               return wl1271_cmd_template_set(wl, wlvif->role_id,
                                               CMD_TEMPL_AP_PROBE_RESPONSE,
                                               probe_rsp_data,
                                               probe_rsp_len, 0,
@@ -3334,7 +3493,7 @@ static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl,
               ptr, probe_rsp_len - (ptr - probe_rsp_data));
        templ_len += probe_rsp_len - (ptr - probe_rsp_data);
 
-       return wl1271_cmd_template_set(wl,
+       return wl1271_cmd_template_set(wl, wlvif->role_id,
                                       CMD_TEMPL_AP_PROBE_RESPONSE,
                                       probe_rsp_templ,
                                       templ_len, 0,
@@ -3431,7 +3590,7 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
                min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
                tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
                                  CMD_TEMPL_BEACON;
-               ret = wl1271_cmd_template_set(wl, tmpl_id,
+               ret = wl1271_cmd_template_set(wl, wlvif->role_id, tmpl_id,
                                              beacon->data,
                                              beacon->len, 0,
                                              min_rate);
@@ -3470,7 +3629,7 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
                                                beacon->len,
                                                min_rate);
                else
-                       ret = wl1271_cmd_template_set(wl,
+                       ret = wl1271_cmd_template_set(wl, wlvif->role_id,
                                                CMD_TEMPL_PROBE_RESPONSE,
                                                beacon->data,
                                                beacon->len, 0,
@@ -3595,10 +3754,8 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
                        ibss_joined = true;
                } else {
                        if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED,
-                                              &wlvif->flags)) {
+                                              &wlvif->flags))
                                wl1271_unjoin(wl, wlvif);
-                               wl12xx_start_dev(wl, wlvif);
-                       }
                }
        }
 
@@ -3616,7 +3773,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
                do_join = true;
        }
 
-       if (changed & BSS_CHANGED_IDLE) {
+       if (changed & BSS_CHANGED_IDLE && !is_ibss) {
                ret = wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle);
                if (ret < 0)
                        wl1271_warning("idle mode change failed %d", ret);
@@ -3634,7 +3791,8 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
                wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
        }
 
-       if (changed & BSS_CHANGED_BSSID)
+       if (changed & BSS_CHANGED_BSSID &&
+           (is_ibss || bss_conf->assoc))
                if (!is_zero_ether_addr(bss_conf->bssid)) {
                        ret = wl12xx_cmd_build_null_data(wl, wlvif);
                        if (ret < 0)
@@ -3671,10 +3829,9 @@ sta_not_found:
                        u32 rates;
                        int ieoffset;
                        wlvif->aid = bss_conf->aid;
+                       wlvif->beacon_int = bss_conf->beacon_int;
                        set_assoc = true;
 
-                       wlvif->ps_poll_failures = 0;
-
                        /*
                         * use basic rates from AP, and determine lowest rate
                         * to use with control frames.
@@ -3734,9 +3891,6 @@ sta_not_found:
                        dev_kfree_skb(wlvif->probereq);
                        wlvif->probereq = NULL;
 
-                       /* re-enable dynamic ps - just in case */
-                       ieee80211_enable_dyn_ps(vif);
-
                        /* revert back to minimum rates for the current band */
                        wl1271_set_band_rate(wl, wlvif);
                        wlvif->basic_rate =
@@ -3756,7 +3910,6 @@ sta_not_found:
 
                        /* restore the bssid filter and go to dummy bssid */
                        if (was_assoc) {
-                               u32 conf_flags = wl->hw->conf.flags;
                                /*
                                 * we might have to disable roc, if there was
                                 * no IF_OPER_UP notification.
@@ -3779,7 +3932,7 @@ sta_not_found:
                                }
 
                                wl1271_unjoin(wl, wlvif);
-                               if (!(conf_flags & IEEE80211_CONF_IDLE))
+                               if (!bss_conf->idle)
                                        wl12xx_start_dev(wl, wlvif);
                        }
                }
@@ -3810,34 +3963,6 @@ sta_not_found:
        if (ret < 0)
                goto out;
 
-       if (changed & BSS_CHANGED_ARP_FILTER) {
-               __be32 addr = bss_conf->arp_addr_list[0];
-               WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
-
-               if (bss_conf->arp_addr_cnt == 1 &&
-                   bss_conf->arp_filter_enabled) {
-                       /*
-                        * The template should have been configured only upon
-                        * association. however, it seems that the correct ip
-                        * isn't being set (when sending), so we have to
-                        * reconfigure the template upon every ip change.
-                        */
-                       ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr);
-                       if (ret < 0) {
-                               wl1271_warning("build arp rsp failed: %d", ret);
-                               goto out;
-                       }
-
-                       ret = wl1271_acx_arp_ip_filter(wl, wlvif,
-                               ACX_ARP_FILTER_ARP_FILTERING,
-                               addr);
-               } else
-                       ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
-
-               if (ret < 0)
-                       goto out;
-       }
-
        if (do_join) {
                ret = wl1271_join(wl, wlvif, set_assoc);
                if (ret < 0) {
@@ -3851,8 +3976,8 @@ sta_not_found:
                        if (ret < 0)
                                goto out;
 
-                       wl1271_check_operstate(wl, wlvif,
-                                              ieee80211_get_operstate(vif));
+                       if (test_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags))
+                               wl12xx_set_authorized(wl, wlvif);
                }
                /*
                 * stop device role if started (we might already be in
@@ -3863,19 +3988,6 @@ sta_not_found:
                        if (ret < 0)
                                goto out;
                }
-
-               /* If we want to go in PSM but we're not there yet */
-               if (test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags) &&
-                   !test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
-                       enum wl1271_cmd_ps_mode mode;
-
-                       mode = STATION_POWER_SAVE_MODE;
-                       ret = wl1271_ps_set_mode(wl, wlvif, mode,
-                                                wlvif->basic_rate,
-                                                true);
-                       if (ret < 0)
-                               goto out;
-               }
        }
 
        /* Handle new association with HT. Do this after join. */
@@ -3917,6 +4029,41 @@ sta_not_found:
                }
        }
 
+       /* Handle arp filtering. Done after join. */
+       if ((changed & BSS_CHANGED_ARP_FILTER) ||
+           (!is_ibss && (changed & BSS_CHANGED_QOS))) {
+               __be32 addr = bss_conf->arp_addr_list[0];
+               wlvif->sta.qos = bss_conf->qos;
+               WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
+
+               if (bss_conf->arp_addr_cnt == 1 &&
+                   bss_conf->arp_filter_enabled) {
+                       wlvif->ip_addr = addr;
+                       /*
+                        * The template should have been configured only upon
+                        * association. however, it seems that the correct ip
+                        * isn't being set (when sending), so we have to
+                        * reconfigure the template upon every ip change.
+                        */
+                       ret = wl1271_cmd_build_arp_rsp(wl, wlvif);
+                       if (ret < 0) {
+                               wl1271_warning("build arp rsp failed: %d", ret);
+                               goto out;
+                       }
+
+                       ret = wl1271_acx_arp_ip_filter(wl, wlvif,
+                               (ACX_ARP_FILTER_ARP_FILTERING |
+                                ACX_ARP_FILTER_AUTO_ARP),
+                               addr);
+               } else {
+                       wlvif->ip_addr = 0;
+                       ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
+               }
+
+               if (ret < 0)
+                       goto out;
+       }
+
 out:
        return;
 }
@@ -4012,6 +4159,7 @@ static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
 {
 
        struct wl1271 *wl = hw->priv;
+       struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
        u64 mactime = ULLONG_MAX;
        int ret;
 
@@ -4026,7 +4174,7 @@ static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
        if (ret < 0)
                goto out;
 
-       ret = wl1271_acx_tsf_info(wl, &mactime);
+       ret = wl12xx_acx_tsf_info(wl, wlvif, &mactime);
        if (ret < 0)
                goto out_sleep;
 
@@ -4088,107 +4236,155 @@ void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
        clear_bit(hlid, wlvif->ap.sta_hlid_map);
        memset(wl->links[hlid].addr, 0, ETH_ALEN);
        wl->links[hlid].ba_bitmap = 0;
-       wl1271_tx_reset_link_queues(wl, hlid);
        __clear_bit(hlid, &wl->ap_ps_map);
        __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
        wl12xx_free_link(wl, wlvif, &hlid);
        wl->active_sta_count--;
+
+       /*
+        * rearm the tx watchdog when the last STA is freed - give the FW a
+        * chance to return STA-buffered packets before complaining.
+        */
+       if (wl->active_sta_count == 0)
+               wl12xx_rearm_tx_watchdog_locked(wl);
 }
 
-static int wl1271_op_sta_add(struct ieee80211_hw *hw,
-                            struct ieee80211_vif *vif,
-                            struct ieee80211_sta *sta)
+static int wl12xx_sta_add(struct wl1271 *wl,
+                         struct wl12xx_vif *wlvif,
+                         struct ieee80211_sta *sta)
 {
-       struct wl1271 *wl = hw->priv;
-       struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
        struct wl1271_station *wl_sta;
        int ret = 0;
        u8 hlid;
 
-       mutex_lock(&wl->mutex);
-
-       if (unlikely(wl->state == WL1271_STATE_OFF))
-               goto out;
-
-       if (wlvif->bss_type != BSS_TYPE_AP_BSS)
-               goto out;
-
        wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
 
        ret = wl1271_allocate_sta(wl, wlvif, sta);
        if (ret < 0)
-               goto out;
+               return ret;
 
        wl_sta = (struct wl1271_station *)sta->drv_priv;
        hlid = wl_sta->hlid;
 
-       ret = wl1271_ps_elp_wakeup(wl);
-       if (ret < 0)
-               goto out_free_sta;
-
        ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
        if (ret < 0)
-               goto out_sleep;
+               wl1271_free_sta(wl, wlvif, hlid);
 
-       ret = wl12xx_cmd_set_peer_state(wl, hlid);
-       if (ret < 0)
-               goto out_sleep;
+       return ret;
+}
 
-       ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
-       if (ret < 0)
-               goto out_sleep;
+static int wl12xx_sta_remove(struct wl1271 *wl,
+                            struct wl12xx_vif *wlvif,
+                            struct ieee80211_sta *sta)
+{
+       struct wl1271_station *wl_sta;
+       int ret = 0, id;
 
-out_sleep:
-       wl1271_ps_elp_sleep(wl);
+       wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
+
+       wl_sta = (struct wl1271_station *)sta->drv_priv;
+       id = wl_sta->hlid;
+       if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
+               return -EINVAL;
 
-out_free_sta:
+       ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
        if (ret < 0)
-               wl1271_free_sta(wl, wlvif, hlid);
+               return ret;
 
-out:
-       mutex_unlock(&wl->mutex);
+       wl1271_free_sta(wl, wlvif, wl_sta->hlid);
        return ret;
 }
 
-static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
-                               struct ieee80211_vif *vif,
-                               struct ieee80211_sta *sta)
+static int wl12xx_update_sta_state(struct wl1271 *wl,
+                                  struct wl12xx_vif *wlvif,
+                                  struct ieee80211_sta *sta,
+                                  enum ieee80211_sta_state old_state,
+                                  enum ieee80211_sta_state new_state)
 {
-       struct wl1271 *wl = hw->priv;
-       struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
        struct wl1271_station *wl_sta;
-       int ret = 0, id;
+       u8 hlid;
+       bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
+       bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
+       int ret;
 
-       mutex_lock(&wl->mutex);
+       wl_sta = (struct wl1271_station *)sta->drv_priv;
+       hlid = wl_sta->hlid;
 
-       if (unlikely(wl->state == WL1271_STATE_OFF))
-               goto out;
+       /* Add station (AP mode) */
+       if (is_ap &&
+           old_state == IEEE80211_STA_NOTEXIST &&
+           new_state == IEEE80211_STA_NONE)
+               return wl12xx_sta_add(wl, wlvif, sta);
+
+       /* Remove station (AP mode) */
+       if (is_ap &&
+           old_state == IEEE80211_STA_NONE &&
+           new_state == IEEE80211_STA_NOTEXIST) {
+               /* must not fail */
+               wl12xx_sta_remove(wl, wlvif, sta);
+               return 0;
+       }
 
-       if (wlvif->bss_type != BSS_TYPE_AP_BSS)
-               goto out;
+       /* Authorize station (AP mode) */
+       if (is_ap &&
+           new_state == IEEE80211_STA_AUTHORIZED) {
+               ret = wl12xx_cmd_set_peer_state(wl, hlid);
+               if (ret < 0)
+                       return ret;
 
-       wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
+               ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true,
+                                                    hlid);
+               return ret;
+       }
 
-       wl_sta = (struct wl1271_station *)sta->drv_priv;
-       id = wl_sta->hlid;
-       if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
+       /* Authorize station */
+       if (is_sta &&
+           new_state == IEEE80211_STA_AUTHORIZED) {
+               set_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags);
+               return wl12xx_set_authorized(wl, wlvif);
+       }
+
+       if (is_sta &&
+           old_state == IEEE80211_STA_AUTHORIZED &&
+           new_state == IEEE80211_STA_ASSOC) {
+               clear_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags);
+               return 0;
+       }
+
+       return 0;
+}
+
+static int wl12xx_op_sta_state(struct ieee80211_hw *hw,
+                              struct ieee80211_vif *vif,
+                              struct ieee80211_sta *sta,
+                              enum ieee80211_sta_state old_state,
+                              enum ieee80211_sta_state new_state)
+{
+       struct wl1271 *wl = hw->priv;
+       struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
+       int ret;
+
+       wl1271_debug(DEBUG_MAC80211, "mac80211 sta %d state=%d->%d",
+                    sta->aid, old_state, new_state);
+
+       mutex_lock(&wl->mutex);
+
+       if (unlikely(wl->state == WL1271_STATE_OFF)) {
+               ret = -EBUSY;
                goto out;
+       }
 
        ret = wl1271_ps_elp_wakeup(wl);
        if (ret < 0)
                goto out;
 
-       ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
-       if (ret < 0)
-               goto out_sleep;
+       ret = wl12xx_update_sta_state(wl, wlvif, sta, old_state, new_state);
 
-       wl1271_free_sta(wl, wlvif, wl_sta->hlid);
-
-out_sleep:
        wl1271_ps_elp_sleep(wl);
-
 out:
        mutex_unlock(&wl->mutex);
+       if (new_state < old_state)
+               return 0;
        return ret;
 }
 
@@ -4357,6 +4553,8 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
 
        wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
 
+       wl1271_tx_flush(wl);
+
        mutex_lock(&wl->mutex);
 
        if (unlikely(wl->state == WL1271_STATE_OFF)) {
@@ -4373,7 +4571,7 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
 
        /* TODO: change mac80211 to pass vif as param */
        wl12xx_for_each_wlvif_sta(wl, wlvif) {
-               ret = wl12xx_cmd_channel_switch(wl, ch_switch);
+               ret = wl12xx_cmd_channel_switch(wl, wlvif, ch_switch);
 
                if (!ret)
                        set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
@@ -4467,6 +4665,7 @@ static struct ieee80211_channel wl1271_channels[] = {
 /* mapping to indexes for wl1271_rates */
 static const u8 wl1271_rate_to_idx_2ghz[] = {
        /* MCS rates are used only with 11n */
+       7,                            /* CONF_HW_RXTX_RATE_MCS7_SGI */
        7,                            /* CONF_HW_RXTX_RATE_MCS7 */
        6,                            /* CONF_HW_RXTX_RATE_MCS6 */
        5,                            /* CONF_HW_RXTX_RATE_MCS5 */
@@ -4588,6 +4787,7 @@ static struct ieee80211_channel wl1271_channels_5ghz[] = {
 /* mapping to indexes for wl1271_rates_5ghz */
 static const u8 wl1271_rate_to_idx_5ghz[] = {
        /* MCS rates are used only with 11n */
+       7,                            /* CONF_HW_RXTX_RATE_MCS7_SGI */
        7,                            /* CONF_HW_RXTX_RATE_MCS7 */
        6,                            /* CONF_HW_RXTX_RATE_MCS6 */
        5,                            /* CONF_HW_RXTX_RATE_MCS5 */
@@ -4653,8 +4853,7 @@ static const struct ieee80211_ops wl1271_ops = {
        .conf_tx = wl1271_op_conf_tx,
        .get_tsf = wl1271_op_get_tsf,
        .get_survey = wl1271_op_get_survey,
-       .sta_add = wl1271_op_sta_add,
-       .sta_remove = wl1271_op_sta_remove,
+       .sta_state = wl12xx_op_sta_state,
        .ampdu_action = wl1271_op_ampdu_action,
        .tx_frames_pending = wl1271_tx_frames_pending,
        .set_bitrate_mask = wl12xx_set_bitrate_mask,
@@ -4828,13 +5027,120 @@ static struct bin_attribute fwlog_attr = {
        .read = wl1271_sysfs_read_fwlog,
 };
 
+static bool wl12xx_mac_in_fuse(struct wl1271 *wl)
+{
+       bool supported = false;
+       u8 major, minor;
+
+       if (wl->chip.id == CHIP_ID_1283_PG20) {
+               major = WL128X_PG_GET_MAJOR(wl->hw_pg_ver);
+               minor = WL128X_PG_GET_MINOR(wl->hw_pg_ver);
+
+               /* in wl128x we have the MAC address if the PG is >= (2, 1) */
+               if (major > 2 || (major == 2 && minor >= 1))
+                       supported = true;
+       } else {
+               major = WL127X_PG_GET_MAJOR(wl->hw_pg_ver);
+               minor = WL127X_PG_GET_MINOR(wl->hw_pg_ver);
+
+               /* in wl127x we have the MAC address if the PG is >= (3, 1) */
+               if (major == 3 && minor >= 1)
+                       supported = true;
+       }
+
+       wl1271_debug(DEBUG_PROBE,
+                    "PG Ver major = %d minor = %d, MAC %s present",
+                    major, minor, supported ? "is" : "is not");
+
+       return supported;
+}
+
+static void wl12xx_derive_mac_addresses(struct wl1271 *wl,
+                                       u32 oui, u32 nic, int n)
+{
+       int i;
+
+       wl1271_debug(DEBUG_PROBE, "base address: oui %06x nic %06x, n %d",
+                    oui, nic, n);
+
+       if (nic + n - 1 > 0xffffff)
+               wl1271_warning("NIC part of the MAC address wraps around!");
+
+       for (i = 0; i < n; i++) {
+               wl->addresses[i].addr[0] = (u8)(oui >> 16);
+               wl->addresses[i].addr[1] = (u8)(oui >> 8);
+               wl->addresses[i].addr[2] = (u8) oui;
+               wl->addresses[i].addr[3] = (u8)(nic >> 16);
+               wl->addresses[i].addr[4] = (u8)(nic >> 8);
+               wl->addresses[i].addr[5] = (u8) nic;
+               nic++;
+       }
+
+       wl->hw->wiphy->n_addresses = n;
+       wl->hw->wiphy->addresses = wl->addresses;
+}
+
+static void wl12xx_get_fuse_mac(struct wl1271 *wl)
+{
+       u32 mac1, mac2;
+
+       wl1271_set_partition(wl, &wl12xx_part_table[PART_DRPW]);
+
+       mac1 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_1);
+       mac2 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_2);
+
+       /* these are the two parts of the BD_ADDR */
+       wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) +
+               ((mac1 & 0xff000000) >> 24);
+       wl->fuse_nic_addr = mac1 & 0xffffff;
+
+       wl1271_set_partition(wl, &wl12xx_part_table[PART_DOWN]);
+}
+
+static int wl12xx_get_hw_info(struct wl1271 *wl)
+{
+       int ret;
+       u32 die_info;
+
+       ret = wl12xx_set_power_on(wl);
+       if (ret < 0)
+               goto out;
+
+       wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
+
+       if (wl->chip.id == CHIP_ID_1283_PG20)
+               die_info = wl1271_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1);
+       else
+               die_info = wl1271_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1);
+
+       wl->hw_pg_ver = (s8) (die_info & PG_VER_MASK) >> PG_VER_OFFSET;
+
+       if (!wl12xx_mac_in_fuse(wl)) {
+               wl->fuse_oui_addr = 0;
+               wl->fuse_nic_addr = 0;
+       } else {
+               wl12xx_get_fuse_mac(wl);
+       }
+
+       wl1271_power_off(wl);
+out:
+       return ret;
+}
+
 static int wl1271_register_hw(struct wl1271 *wl)
 {
        int ret;
+       u32 oui_addr = 0, nic_addr = 0;
 
        if (wl->mac80211_registered)
                return 0;
 
+       ret = wl12xx_get_hw_info(wl);
+       if (ret < 0) {
+               wl1271_error("couldn't get hw info");
+               goto out;
+       }
+
        ret = wl1271_fetch_nvs(wl);
        if (ret == 0) {
                /* NOTE: The wl->nvs->nvs element must be first, in
@@ -4843,39 +5149,42 @@ static int wl1271_register_hw(struct wl1271 *wl)
                 */
                u8 *nvs_ptr = (u8 *)wl->nvs;
 
-               wl->mac_addr[0] = nvs_ptr[11];
-               wl->mac_addr[1] = nvs_ptr[10];
-               wl->mac_addr[2] = nvs_ptr[6];
-               wl->mac_addr[3] = nvs_ptr[5];
-               wl->mac_addr[4] = nvs_ptr[4];
-               wl->mac_addr[5] = nvs_ptr[3];
+               oui_addr =
+                       (nvs_ptr[11] << 16) + (nvs_ptr[10] << 8) + nvs_ptr[6];
+               nic_addr =
+                       (nvs_ptr[5] << 16) + (nvs_ptr[4] << 8) + nvs_ptr[3];
        }
 
-       SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
+       /* if the MAC address is zeroed in the NVS derive from fuse */
+       if (oui_addr == 0 && nic_addr == 0) {
+               oui_addr = wl->fuse_oui_addr;
+               /* fuse has the BD_ADDR, the WLAN addresses are the next two */
+               nic_addr = wl->fuse_nic_addr + 1;
+       }
+
+       wl12xx_derive_mac_addresses(wl, oui_addr, nic_addr, 2);
 
        ret = ieee80211_register_hw(wl->hw);
        if (ret < 0) {
                wl1271_error("unable to register mac80211 hw: %d", ret);
-               return ret;
+               goto out;
        }
 
        wl->mac80211_registered = true;
 
        wl1271_debugfs_init(wl);
 
-       register_netdevice_notifier(&wl1271_dev_notifier);
-
        wl1271_notice("loaded");
 
-       return 0;
+out:
+       return ret;
 }
 
 static void wl1271_unregister_hw(struct wl1271 *wl)
 {
-       if (wl->state == WL1271_STATE_PLT)
-               __wl1271_plt_stop(wl);
+       if (wl->plt)
+               wl1271_plt_stop(wl);
 
-       unregister_netdevice_notifier(&wl1271_dev_notifier);
        ieee80211_unregister_hw(wl->hw);
        wl->mac80211_registered = false;
 
@@ -4892,7 +5201,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
        };
 
        /* The tx descriptor buffer and the TKIP space. */
-       wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
+       wl->hw->extra_tx_headroom = WL1271_EXTRA_SPACE_TKIP +
                sizeof(struct wl1271_tx_hw_descr);
 
        /* unit us */
@@ -4902,6 +5211,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
 
        wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
                IEEE80211_HW_SUPPORTS_PS |
+               IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
                IEEE80211_HW_SUPPORTS_UAPSD |
                IEEE80211_HW_HAS_RATE_CONTROL |
                IEEE80211_HW_CONNECTION_MONITOR |
@@ -4909,7 +5219,8 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
                IEEE80211_HW_SPECTRUM_MGMT |
                IEEE80211_HW_AP_LINK_PS |
                IEEE80211_HW_AMPDU_AGGREGATION |
-               IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
+               IEEE80211_HW_TX_AMPDU_SETUP_IN_HW |
+               IEEE80211_HW_SCAN_WHILE_IDLE;
 
        wl->hw->wiphy->cipher_suites = cipher_suites;
        wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
@@ -4925,10 +5236,10 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
         * should be the maximum length possible for a template, without
         * the IEEE80211 header of the template
         */
-       wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
+       wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
                        sizeof(struct ieee80211_header);
 
-       wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
+       wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
                sizeof(struct ieee80211_header);
 
        wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
@@ -4994,7 +5305,6 @@ static struct ieee80211_hw *wl1271_alloc_hw(void)
        wl = hw->priv;
        memset(wl, 0, sizeof(*wl));
 
-       INIT_LIST_HEAD(&wl->list);
        INIT_LIST_HEAD(&wl->wlvif_list);
 
        wl->hw = hw;
@@ -5011,6 +5321,7 @@ static struct ieee80211_hw *wl1271_alloc_hw(void)
        INIT_WORK(&wl->tx_work, wl1271_tx_work);
        INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
        INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
+       INIT_DELAYED_WORK(&wl->tx_watchdog_work, wl12xx_tx_watchdog_work);
 
        wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
        if (!wl->freezable_wq) {
@@ -5022,7 +5333,6 @@ static struct ieee80211_hw *wl1271_alloc_hw(void)
        wl->rx_counter = 0;
        wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
        wl->band = IEEE80211_BAND_2GHZ;
-       wl->vif = NULL;
        wl->flags = 0;
        wl->sg_enabled = true;
        wl->hw_pg_ver = -1;
@@ -5047,6 +5357,7 @@ static struct ieee80211_hw *wl1271_alloc_hw(void)
        spin_lock_init(&wl->wl_lock);
 
        wl->state = WL1271_STATE_OFF;
+       wl->fw_type = WL12XX_FW_TYPE_NONE;
        mutex_init(&wl->mutex);
 
        /* Apply default driver configuration. */
@@ -5114,6 +5425,7 @@ static int wl1271_free_hw(struct wl1271 *wl)
 
        vfree(wl->fw);
        wl->fw = NULL;
+       wl->fw_type = WL12XX_FW_TYPE_NONE;
        kfree(wl->nvs);
        wl->nvs = NULL;
 
@@ -5300,7 +5612,7 @@ module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
 MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
 
 module_param_named(fwlog, fwlog_param, charp, 0);
-MODULE_PARM_DESC(keymap,
+MODULE_PARM_DESC(fwlog,
                 "FW logger options: continuous, ondemand, dbgpins or disable");
 
 module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
index a2bdacdd7e1dd742ae9398ef70c1d2eb1c8037d2..78f598b4f97b977cbc747a0bd93b0877bc900ff0 100644 (file)
@@ -56,7 +56,7 @@ void wl1271_elp_work(struct work_struct *work)
                if (wlvif->bss_type == BSS_TYPE_AP_BSS)
                        goto out;
 
-               if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags) &&
+               if (!test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags) &&
                    test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags))
                        goto out;
        }
@@ -69,8 +69,6 @@ out:
        mutex_unlock(&wl->mutex);
 }
 
-#define ELP_ENTRY_DELAY  5
-
 /* Routines to toggle sleep mode while in ELP */
 void wl1271_ps_elp_sleep(struct wl1271 *wl)
 {
@@ -84,13 +82,13 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl)
                if (wlvif->bss_type == BSS_TYPE_AP_BSS)
                        return;
 
-               if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags) &&
+               if (!test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags) &&
                    test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags))
                        return;
        }
 
        ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
-                                    msecs_to_jiffies(ELP_ENTRY_DELAY));
+               msecs_to_jiffies(wl->conf.conn.dynamic_ps_timeout));
 }
 
 int wl1271_ps_elp_wakeup(struct wl1271 *wl)
@@ -160,28 +158,39 @@ out:
 }
 
 int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
-                      enum wl1271_cmd_ps_mode mode, u32 rates, bool send)
+                      enum wl1271_cmd_ps_mode mode)
 {
        int ret;
+       u16 timeout = wl->conf.conn.dynamic_ps_timeout;
 
        switch (mode) {
+       case STATION_AUTO_PS_MODE:
        case STATION_POWER_SAVE_MODE:
-               wl1271_debug(DEBUG_PSM, "entering psm");
+               wl1271_debug(DEBUG_PSM, "entering psm (mode=%d,timeout=%u)",
+                            mode, timeout);
 
-               ret = wl1271_acx_wake_up_conditions(wl, wlvif);
+               ret = wl1271_acx_wake_up_conditions(wl, wlvif,
+                                           wl->conf.conn.wake_up_event,
+                                           wl->conf.conn.listen_interval);
                if (ret < 0) {
                        wl1271_error("couldn't set wake up conditions");
                        return ret;
                }
 
-               ret = wl1271_cmd_ps_mode(wl, wlvif, STATION_POWER_SAVE_MODE);
+               ret = wl1271_cmd_ps_mode(wl, wlvif, mode, timeout);
                if (ret < 0)
                        return ret;
 
-               set_bit(WLVIF_FLAG_PSM, &wlvif->flags);
+               set_bit(WLVIF_FLAG_IN_PS, &wlvif->flags);
+
+               /* enable beacon early termination. Not relevant for 5GHz */
+               if (wlvif->band == IEEE80211_BAND_2GHZ) {
+                       ret = wl1271_acx_bet_enable(wl, wlvif, true);
+                       if (ret < 0)
+                               return ret;
+               }
                break;
        case STATION_ACTIVE_MODE:
-       default:
                wl1271_debug(DEBUG_PSM, "leaving psm");
 
                /* disable beacon early termination */
@@ -191,12 +200,15 @@ int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
                                return ret;
                }
 
-               ret = wl1271_cmd_ps_mode(wl, wlvif, STATION_ACTIVE_MODE);
+               ret = wl1271_cmd_ps_mode(wl, wlvif, mode, 0);
                if (ret < 0)
                        return ret;
 
-               clear_bit(WLVIF_FLAG_PSM, &wlvif->flags);
+               clear_bit(WLVIF_FLAG_IN_PS, &wlvif->flags);
                break;
+       default:
+               wl1271_warning("trying to set ps to unsupported mode %d", mode);
+               ret = -EINVAL;
        }
 
        return ret;
index a12052f02026fba0a943258913cb7ad099254f75..5f19d4fbbf27e88345dd7d4fb406d1ad37e2bf0b 100644 (file)
@@ -28,7 +28,7 @@
 #include "acx.h"
 
 int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
-                      enum wl1271_cmd_ps_mode mode, u32 rates, bool send);
+                      enum wl1271_cmd_ps_mode mode);
 void wl1271_ps_elp_sleep(struct wl1271 *wl);
 int wl1271_ps_elp_wakeup(struct wl1271 *wl);
 void wl1271_elp_work(struct work_struct *work);
index df34d5977b98581a2e4b321665a9d0de0dc00398..340db324bc26016933b68afe8abb031d2302513d 100644 (file)
@@ -525,4 +525,31 @@ b12-b0 - Supported Rate indicator bits as defined below.
  */
 #define INTR_TRIG_TX_PROC1 BIT(18)
 
+#define WL127X_REG_FUSE_DATA_2_1       0x050a
+#define WL128X_REG_FUSE_DATA_2_1       0x2152
+#define PG_VER_MASK                    0x3c
+#define PG_VER_OFFSET                  2
+
+#define WL127X_PG_MAJOR_VER_MASK       0x3
+#define WL127X_PG_MAJOR_VER_OFFSET     0x0
+#define WL127X_PG_MINOR_VER_MASK       0xc
+#define WL127X_PG_MINOR_VER_OFFSET     0x2
+
+#define WL128X_PG_MAJOR_VER_MASK       0xc
+#define WL128X_PG_MAJOR_VER_OFFSET     0x2
+#define WL128X_PG_MINOR_VER_MASK       0x3
+#define WL128X_PG_MINOR_VER_OFFSET     0x0
+
+#define WL127X_PG_GET_MAJOR(pg_ver) ((pg_ver & WL127X_PG_MAJOR_VER_MASK) >> \
+                                    WL127X_PG_MAJOR_VER_OFFSET)
+#define WL127X_PG_GET_MINOR(pg_ver) ((pg_ver & WL127X_PG_MINOR_VER_MASK) >> \
+                                    WL127X_PG_MINOR_VER_OFFSET)
+#define WL128X_PG_GET_MAJOR(pg_ver) ((pg_ver & WL128X_PG_MAJOR_VER_MASK) >> \
+                                    WL128X_PG_MAJOR_VER_OFFSET)
+#define WL128X_PG_GET_MINOR(pg_ver) ((pg_ver & WL128X_PG_MINOR_VER_MASK) >> \
+                                    WL128X_PG_MINOR_VER_OFFSET)
+
+#define WL12XX_REG_FUSE_BD_ADDR_1      0x00310eb4
+#define WL12XX_REG_FUSE_BD_ADDR_2      0x00310eb8
+
 #endif
index 4fbd2a722ffabf28eb4f3c383490b2060c1535dc..cfa6071704c591d3be1100b469a140302da95489 100644 (file)
@@ -113,7 +113,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
         * In PLT mode we seem to get frames and mac80211 warns about them,
         * workaround this by not retrieving them at all.
         */
-       if (unlikely(wl->state == WL1271_STATE_PLT))
+       if (unlikely(wl->plt))
                return -EINVAL;
 
        /* the data read starts with the descriptor */
index e24111ececc5c64ba40cf87133b1193b93b0aaa5..fcba055ef196a050023796152d66cafb550c68e2 100644 (file)
@@ -38,7 +38,6 @@ void wl1271_scan_complete_work(struct work_struct *work)
        struct ieee80211_vif *vif;
        struct wl12xx_vif *wlvif;
        int ret;
-       bool is_sta, is_ibss;
 
        dwork = container_of(work, struct delayed_work, work);
        wl = container_of(dwork, struct wl1271, scan_complete_work);
@@ -56,6 +55,12 @@ void wl1271_scan_complete_work(struct work_struct *work)
        vif = wl->scan_vif;
        wlvif = wl12xx_vif_to_data(vif);
 
+       /*
+        * Rearm the tx watchdog just before idling scan. This
+        * prevents just-finished scans from triggering the watchdog
+        */
+       wl12xx_rearm_tx_watchdog_locked(wl);
+
        wl->scan.state = WL1271_SCAN_STATE_IDLE;
        memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
        wl->scan.req = NULL;
@@ -70,15 +75,6 @@ void wl1271_scan_complete_work(struct work_struct *work)
                wl1271_cmd_build_ap_probe_req(wl, wlvif, wlvif->probereq);
        }
 
-       /* return to ROC if needed */
-       is_sta = (wlvif->bss_type == BSS_TYPE_STA_BSS);
-       is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
-       if (((is_sta && !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) ||
-            (is_ibss && !test_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags))) &&
-           !test_bit(wlvif->dev_role_id, wl->roc_map)) {
-               /* restore remain on channel */
-               wl12xx_start_dev(wl, wlvif);
-       }
        wl1271_ps_elp_sleep(wl);
 
        if (wl->scan.failed) {
@@ -182,14 +178,23 @@ static int wl1271_scan_send(struct wl1271 *wl, struct ieee80211_vif *vif,
                goto out;
        }
 
+       if (wl->conf.scan.split_scan_timeout)
+               scan_options |= WL1271_SCAN_OPT_SPLIT_SCAN;
+
        if (passive)
                scan_options |= WL1271_SCAN_OPT_PASSIVE;
 
-       if (WARN_ON(wlvif->role_id == WL12XX_INVALID_ROLE_ID)) {
+       if (wlvif->bss_type == BSS_TYPE_AP_BSS ||
+           test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
+               cmd->params.role_id = wlvif->role_id;
+       else
+               cmd->params.role_id = wlvif->dev_role_id;
+
+       if (WARN_ON(cmd->params.role_id == WL12XX_INVALID_ROLE_ID)) {
                ret = -EINVAL;
                goto out;
        }
-       cmd->params.role_id = wlvif->role_id;
+
        cmd->params.scan_options = cpu_to_le16(scan_options);
 
        cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req,
@@ -202,7 +207,7 @@ static int wl1271_scan_send(struct wl1271 *wl, struct ieee80211_vif *vif,
 
        cmd->params.tx_rate = cpu_to_le32(basic_rate);
        cmd->params.n_probe_reqs = wl->conf.scan.num_probe_reqs;
-       cmd->params.tid_trigger = 0;
+       cmd->params.tid_trigger = CONF_TX_AC_ANY_TID;
        cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;
 
        if (band == IEEE80211_BAND_2GHZ)
@@ -217,16 +222,17 @@ static int wl1271_scan_send(struct wl1271 *wl, struct ieee80211_vif *vif,
 
        memcpy(cmd->addr, vif->addr, ETH_ALEN);
 
-       ret = wl1271_cmd_build_probe_req(wl, wlvif, wl->scan.ssid,
-                                        wl->scan.ssid_len, wl->scan.req->ie,
-                                        wl->scan.req->ie_len, band);
+       ret = wl12xx_cmd_build_probe_req(wl, wlvif,
+                                        cmd->params.role_id, band,
+                                        wl->scan.ssid, wl->scan.ssid_len,
+                                        wl->scan.req->ie,
+                                        wl->scan.req->ie_len);
        if (ret < 0) {
                wl1271_error("PROBE request template failed");
                goto out;
        }
 
-       /* disable the timeout */
-       trigger->timeout = 0;
+       trigger->timeout = cpu_to_le32(wl->conf.scan.split_scan_timeout);
        ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger,
                              sizeof(*trigger), 0);
        if (ret < 0) {
@@ -658,11 +664,13 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
        }
 
        if (!force_passive && cfg->active[0]) {
-               ret = wl1271_cmd_build_probe_req(wl, wlvif, req->ssids[0].ssid,
+               u8 band = IEEE80211_BAND_2GHZ;
+               ret = wl12xx_cmd_build_probe_req(wl, wlvif,
+                                                wlvif->dev_role_id, band,
+                                                req->ssids[0].ssid,
                                                 req->ssids[0].ssid_len,
-                                                ies->ie[IEEE80211_BAND_2GHZ],
-                                                ies->len[IEEE80211_BAND_2GHZ],
-                                                IEEE80211_BAND_2GHZ);
+                                                ies->ie[band],
+                                                ies->len[band]);
                if (ret < 0) {
                        wl1271_error("2.4GHz PROBE request template failed");
                        goto out;
@@ -670,11 +678,13 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
        }
 
        if (!force_passive && cfg->active[1]) {
-               ret = wl1271_cmd_build_probe_req(wl, wlvif, req->ssids[0].ssid,
+               u8 band = IEEE80211_BAND_5GHZ;
+               ret = wl12xx_cmd_build_probe_req(wl, wlvif,
+                                                wlvif->dev_role_id, band,
+                                                req->ssids[0].ssid,
                                                 req->ssids[0].ssid_len,
-                                                ies->ie[IEEE80211_BAND_5GHZ],
-                                                ies->len[IEEE80211_BAND_5GHZ],
-                                                IEEE80211_BAND_5GHZ);
+                                                ies->ie[band],
+                                                ies->len[band]);
                if (ret < 0) {
                        wl1271_error("5GHz PROBE request template failed");
                        goto out;
index a7ed43dc08c9e89217bc4430ca8b5b2b3ce2607a..96ff457a3a0bee224996788195d9fcdb49bdb31b 100644 (file)
@@ -48,7 +48,7 @@ void wl1271_scan_sched_scan_results(struct wl1271 *wl);
 #define WL1271_SCAN_CURRENT_TX_PWR     0
 #define WL1271_SCAN_OPT_ACTIVE         0
 #define WL1271_SCAN_OPT_PASSIVE               1
-#define WL1271_SCAN_OPT_TRIGGERED_SCAN 2
+#define WL1271_SCAN_OPT_SPLIT_SCAN     2
 #define WL1271_SCAN_OPT_PRIORITY_HIGH  4
 /* scan even if we fail to enter psm */
 #define WL1271_SCAN_OPT_FORCE          8
index 468a50553fac8f345e689432f82cd075d9413828..4b3c32774baee1978a45bb5ee95d62f0840a041c 100644 (file)
@@ -74,6 +74,8 @@ static void wl12xx_sdio_raw_read(struct device *child, int addr, void *buf,
        struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent);
        struct sdio_func *func = dev_to_sdio_func(glue->dev);
 
+       sdio_claim_host(func);
+
        if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) {
                ((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret);
                dev_dbg(child->parent, "sdio read 52 addr 0x%x, byte 0x%02x\n",
@@ -88,6 +90,8 @@ static void wl12xx_sdio_raw_read(struct device *child, int addr, void *buf,
                        addr, len);
        }
 
+       sdio_release_host(func);
+
        if (ret)
                dev_err(child->parent, "sdio read failed (%d)\n", ret);
 }
@@ -99,6 +103,8 @@ static void wl12xx_sdio_raw_write(struct device *child, int addr, void *buf,
        struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent);
        struct sdio_func *func = dev_to_sdio_func(glue->dev);
 
+       sdio_claim_host(func);
+
        if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) {
                sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret);
                dev_dbg(child->parent, "sdio write 52 addr 0x%x, byte 0x%02x\n",
@@ -113,6 +119,8 @@ static void wl12xx_sdio_raw_write(struct device *child, int addr, void *buf,
                        ret = sdio_memcpy_toio(func, addr, buf, len);
        }
 
+       sdio_release_host(func);
+
        if (ret)
                dev_err(child->parent, "sdio write failed (%d)\n", ret);
 }
@@ -136,6 +144,7 @@ static int wl12xx_sdio_power_on(struct wl12xx_sdio_glue *glue)
 
        sdio_claim_host(func);
        sdio_enable_func(func);
+       sdio_release_host(func);
 
 out:
        return ret;
@@ -146,6 +155,7 @@ static int wl12xx_sdio_power_off(struct wl12xx_sdio_glue *glue)
        int ret;
        struct sdio_func *func = dev_to_sdio_func(glue->dev);
 
+       sdio_claim_host(func);
        sdio_disable_func(func);
        sdio_release_host(func);
 
@@ -314,9 +324,6 @@ static int wl1271_suspend(struct device *dev)
                        dev_err(dev, "error while trying to keep power\n");
                        goto out;
                }
-
-               /* release host */
-               sdio_release_host(func);
        }
 out:
        return ret;
@@ -324,15 +331,7 @@ out:
 
 static int wl1271_resume(struct device *dev)
 {
-       struct sdio_func *func = dev_to_sdio_func(dev);
-       struct wl12xx_sdio_glue *glue = sdio_get_drvdata(func);
-       struct wl1271 *wl = platform_get_drvdata(glue->core);
-
        dev_dbg(dev, "wl1271 resume\n");
-       if (wl->wow_enabled) {
-               /* claim back host */
-               sdio_claim_host(func);
-       }
 
        return 0;
 }
@@ -371,5 +370,9 @@ module_exit(wl1271_exit);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
 MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
-MODULE_FIRMWARE(WL127X_FW_NAME);
-MODULE_FIRMWARE(WL128X_FW_NAME);
+MODULE_FIRMWARE(WL127X_FW_NAME_SINGLE);
+MODULE_FIRMWARE(WL127X_FW_NAME_MULTI);
+MODULE_FIRMWARE(WL127X_PLT_FW_NAME);
+MODULE_FIRMWARE(WL128X_FW_NAME_SINGLE);
+MODULE_FIRMWARE(WL128X_FW_NAME_MULTI);
+MODULE_FIRMWARE(WL128X_PLT_FW_NAME);
index 92caa7ce6053efc1c36227553b03b05e61844cbe..2fc18a8dcce8329436805a38d0582578325a8368 100644 (file)
@@ -433,6 +433,10 @@ module_exit(wl1271_exit);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
 MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
-MODULE_FIRMWARE(WL127X_FW_NAME);
-MODULE_FIRMWARE(WL128X_FW_NAME);
+MODULE_FIRMWARE(WL127X_FW_NAME_SINGLE);
+MODULE_FIRMWARE(WL127X_FW_NAME_MULTI);
+MODULE_FIRMWARE(WL127X_PLT_FW_NAME);
+MODULE_FIRMWARE(WL128X_FW_NAME_SINGLE);
+MODULE_FIRMWARE(WL128X_FW_NAME_MULTI);
+MODULE_FIRMWARE(WL128X_PLT_FW_NAME);
 MODULE_ALIAS("spi:wl1271");
index 25093c0cb0edf654ad04f603e3c1b7eb47603a1b..1e93bb9c0246cfa02e44f6160851909b422b14ec 100644 (file)
@@ -30,6 +30,7 @@
 #include "acx.h"
 #include "reg.h"
 #include "ps.h"
+#include "io.h"
 
 #define WL1271_TM_MAX_DATA_LENGTH 1024
 
@@ -41,6 +42,7 @@ enum wl1271_tm_commands {
        WL1271_TM_CMD_NVS_PUSH,         /* Not in use. Keep to not break ABI */
        WL1271_TM_CMD_SET_PLT_MODE,
        WL1271_TM_CMD_RECOVER,
+       WL1271_TM_CMD_GET_MAC,
 
        __WL1271_TM_CMD_AFTER_LAST
 };
@@ -264,6 +266,52 @@ static int wl1271_tm_cmd_recover(struct wl1271 *wl, struct nlattr *tb[])
        return 0;
 }
 
+static int wl12xx_tm_cmd_get_mac(struct wl1271 *wl, struct nlattr *tb[])
+{
+       struct sk_buff *skb;
+       u8 mac_addr[ETH_ALEN];
+       int ret = 0;
+
+       mutex_lock(&wl->mutex);
+
+       if (!wl->plt) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (wl->fuse_oui_addr == 0 && wl->fuse_nic_addr == 0) {
+               ret = -EOPNOTSUPP;
+               goto out;
+       }
+
+       mac_addr[0] = (u8)(wl->fuse_oui_addr >> 16);
+       mac_addr[1] = (u8)(wl->fuse_oui_addr >> 8);
+       mac_addr[2] = (u8) wl->fuse_oui_addr;
+       mac_addr[3] = (u8)(wl->fuse_nic_addr >> 16);
+       mac_addr[4] = (u8)(wl->fuse_nic_addr >> 8);
+       mac_addr[5] = (u8) wl->fuse_nic_addr;
+
+       skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, ETH_ALEN);
+       if (!skb) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       NLA_PUT(skb, WL1271_TM_ATTR_DATA, ETH_ALEN, mac_addr);
+       ret = cfg80211_testmode_reply(skb);
+       if (ret < 0)
+               goto out;
+
+out:
+       mutex_unlock(&wl->mutex);
+       return ret;
+
+nla_put_failure:
+       kfree_skb(skb);
+       ret = -EMSGSIZE;
+       goto out;
+}
+
 int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len)
 {
        struct wl1271 *wl = hw->priv;
@@ -288,6 +336,8 @@ int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len)
                return wl1271_tm_cmd_set_plt_mode(wl, tb);
        case WL1271_TM_CMD_RECOVER:
                return wl1271_tm_cmd_recover(wl, tb);
+       case WL1271_TM_CMD_GET_MAC:
+               return wl12xx_tm_cmd_get_mac(wl, tb);
        default:
                return -EOPNOTSUPP;
        }
index 4508ccd78328017b173215fbfec69ea3a6c5c413..43ae49143d68bf47a4fa98c25f15b5d3b20cd3a9 100644 (file)
@@ -77,35 +77,6 @@ static void wl1271_free_tx_id(struct wl1271 *wl, int id)
        }
 }
 
-static int wl1271_tx_update_filters(struct wl1271 *wl,
-                                   struct wl12xx_vif *wlvif,
-                                   struct sk_buff *skb)
-{
-       struct ieee80211_hdr *hdr;
-       int ret;
-
-       hdr = (struct ieee80211_hdr *)skb->data;
-
-       /*
-        * stop bssid-based filtering before transmitting authentication
-        * requests. this way the hw will never drop authentication
-        * responses coming from BSSIDs it isn't familiar with (e.g. on
-        * roaming)
-        */
-       if (!ieee80211_is_auth(hdr->frame_control))
-               return 0;
-
-       if (wlvif->dev_hlid != WL12XX_INVALID_LINK_ID)
-               goto out;
-
-       wl1271_debug(DEBUG_CMD, "starting device role for roaming");
-       ret = wl12xx_start_dev(wl, wlvif);
-       if (ret < 0)
-               goto out;
-out:
-       return 0;
-}
-
 static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl,
                                                 struct sk_buff *skb)
 {
@@ -187,8 +158,6 @@ u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif,
        if (wlvif->bss_type == BSS_TYPE_AP_BSS)
                return wl12xx_tx_get_hlid_ap(wl, wlvif, skb);
 
-       wl1271_tx_update_filters(wl, wlvif, skb);
-
        if ((test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
             test_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags)) &&
            !ieee80211_is_auth(hdr->frame_control) &&
@@ -257,6 +226,10 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
                wl->tx_blocks_available -= total_blocks;
                wl->tx_allocated_blocks += total_blocks;
 
+               /* If the FW was empty before, arm the Tx watchdog */
+               if (wl->tx_allocated_blocks == total_blocks)
+                       wl12xx_rearm_tx_watchdog_locked(wl);
+
                ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
                wl->tx_allocated_pkts[ac]++;
 
@@ -286,16 +259,20 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif,
        int aligned_len, ac, rate_idx;
        s64 hosttime;
        u16 tx_attr = 0;
+       __le16 frame_control;
+       struct ieee80211_hdr *hdr;
+       u8 *frame_start;
        bool is_dummy;
 
        desc = (struct wl1271_tx_hw_descr *) skb->data;
+       frame_start = (u8 *)(desc + 1);
+       hdr = (struct ieee80211_hdr *)(frame_start + extra);
+       frame_control = hdr->frame_control;
 
        /* relocate space for security header */
        if (extra) {
-               void *framestart = skb->data + sizeof(*desc);
-               u16 fc = *(u16 *)(framestart + extra);
-               int hdrlen = ieee80211_hdrlen(cpu_to_le16(fc));
-               memmove(framestart, framestart + extra, hdrlen);
+               int hdrlen = ieee80211_hdrlen(frame_control);
+               memmove(frame_start, hdr, hdrlen);
        }
 
        /* configure packet life time */
@@ -384,6 +361,11 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif,
                             desc->wl127x_mem.total_mem_blocks);
        }
 
+       /* for WEP shared auth - no fw encryption is needed */
+       if (ieee80211_is_auth(frame_control) &&
+           ieee80211_has_protected(frame_control))
+               tx_attr |= TX_HW_ATTR_HOST_ENCRYPT;
+
        desc->tx_attr = cpu_to_le16(tx_attr);
 }
 
@@ -408,7 +390,7 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 
        if (info->control.hw_key &&
            info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP)
-               extra = WL1271_TKIP_IV_SPACE;
+               extra = WL1271_EXTRA_SPACE_TKIP;
 
        if (info->control.hw_key) {
                bool is_wep;
@@ -549,6 +531,7 @@ static struct sk_buff *wl12xx_lnk_skb_dequeue(struct wl1271 *wl,
        if (skb) {
                int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
                spin_lock_irqsave(&wl->wl_lock, flags);
+               WARN_ON_ONCE(wl->tx_queue_count[q] <= 0);
                wl->tx_queue_count[q]--;
                spin_unlock_irqrestore(&wl->wl_lock, flags);
        }
@@ -593,6 +576,7 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl)
        struct wl12xx_vif *wlvif = wl->last_wlvif;
        struct sk_buff *skb = NULL;
 
+       /* continue from last wlvif (round robin) */
        if (wlvif) {
                wl12xx_for_each_wlvif_continue(wl, wlvif) {
                        skb = wl12xx_vif_skb_dequeue(wl, wlvif);
@@ -603,7 +587,11 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl)
                }
        }
 
-       /* do another pass */
+       /* dequeue from the system HLID before the restarting wlvif list */
+       if (!skb)
+               skb = wl12xx_lnk_skb_dequeue(wl, &wl->links[wl->system_hlid]);
+
+       /* do a new pass over the wlvif list */
        if (!skb) {
                wl12xx_for_each_wlvif(wl, wlvif) {
                        skb = wl12xx_vif_skb_dequeue(wl, wlvif);
@@ -611,12 +599,16 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl)
                                wl->last_wlvif = wlvif;
                                break;
                        }
+
+                       /*
+                        * No need to continue after last_wlvif. The previous
+                        * pass should have found it.
+                        */
+                       if (wlvif == wl->last_wlvif)
+                               break;
                }
        }
 
-       if (!skb)
-               skb = wl12xx_lnk_skb_dequeue(wl, &wl->links[wl->system_hlid]);
-
        if (!skb &&
            test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) {
                int q;
@@ -624,6 +616,7 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl)
                skb = wl->dummy_packet;
                q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
                spin_lock_irqsave(&wl->wl_lock, flags);
+               WARN_ON_ONCE(wl->tx_queue_count[q] <= 0);
                wl->tx_queue_count[q]--;
                spin_unlock_irqrestore(&wl->wl_lock, flags);
        }
@@ -795,6 +788,18 @@ out:
        mutex_unlock(&wl->mutex);
 }
 
+static u8 wl1271_tx_get_rate_flags(u8 rate_class_index)
+{
+       u8 flags = 0;
+
+       if (rate_class_index >= CONF_HW_RXTX_RATE_MCS_MIN &&
+           rate_class_index <= CONF_HW_RXTX_RATE_MCS_MAX)
+               flags |= IEEE80211_TX_RC_MCS;
+       if (rate_class_index == CONF_HW_RXTX_RATE_MCS7_SGI)
+               flags |= IEEE80211_TX_RC_SHORT_GI;
+       return flags;
+}
+
 static void wl1271_tx_complete_packet(struct wl1271 *wl,
                                      struct wl1271_tx_hw_res_descr *result)
 {
@@ -804,6 +809,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
        struct sk_buff *skb;
        int id = result->id;
        int rate = -1;
+       u8 rate_flags = 0;
        u8 retries = 0;
 
        /* check for id legality */
@@ -830,6 +836,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
                        info->flags |= IEEE80211_TX_STAT_ACK;
                rate = wl1271_rate_to_idx(result->rate_class_index,
                                          wlvif->band);
+               rate_flags = wl1271_tx_get_rate_flags(result->rate_class_index);
                retries = result->ack_failures;
        } else if (result->status == TX_RETRY_EXCEEDED) {
                wl->stats.excessive_retries++;
@@ -838,7 +845,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
 
        info->status.rates[0].idx = rate;
        info->status.rates[0].count = retries;
-       info->status.rates[0].flags = 0;
+       info->status.rates[0].flags = rate_flags;
        info->status.ack_signal = -1;
 
        wl->stats.retry_count += result->ack_failures;
@@ -869,8 +876,9 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
        if (info->control.hw_key &&
            info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
                int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
-               memmove(skb->data + WL1271_TKIP_IV_SPACE, skb->data, hdrlen);
-               skb_pull(skb, WL1271_TKIP_IV_SPACE);
+               memmove(skb->data + WL1271_EXTRA_SPACE_TKIP, skb->data,
+                       hdrlen);
+               skb_pull(skb, WL1271_EXTRA_SPACE_TKIP);
        }
 
        wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x"
@@ -966,7 +974,6 @@ void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif)
                else
                        wlvif->sta.ba_rx_bitmap = 0;
 
-               wl1271_tx_reset_link_queues(wl, i);
                wl->links[i].allocated_pkts = 0;
                wl->links[i].prev_freed_pkts = 0;
        }
@@ -980,8 +987,14 @@ void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
        struct sk_buff *skb;
        struct ieee80211_tx_info *info;
 
-       for (i = 0; i < NUM_TX_QUEUES; i++)
-               wl->tx_queue_count[i] = 0;
+       /* only reset the queues if something bad happened */
+       if (WARN_ON_ONCE(wl1271_tx_total_queue_count(wl) != 0)) {
+               for (i = 0; i < WL12XX_MAX_LINKS; i++)
+                       wl1271_tx_reset_link_queues(wl, i);
+
+               for (i = 0; i < NUM_TX_QUEUES; i++)
+                       wl->tx_queue_count[i] = 0;
+       }
 
        wl->stopped_queues_map = 0;
 
@@ -1012,9 +1025,9 @@ void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
                            info->control.hw_key->cipher ==
                            WLAN_CIPHER_SUITE_TKIP) {
                                int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
-                               memmove(skb->data + WL1271_TKIP_IV_SPACE,
+                               memmove(skb->data + WL1271_EXTRA_SPACE_TKIP,
                                        skb->data, hdrlen);
-                               skb_pull(skb, WL1271_TKIP_IV_SPACE);
+                               skb_pull(skb, WL1271_EXTRA_SPACE_TKIP);
                        }
 
                        info->status.rates[0].idx = -1;
@@ -1031,6 +1044,7 @@ void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
 void wl1271_tx_flush(struct wl1271 *wl)
 {
        unsigned long timeout;
+       int i;
        timeout = jiffies + usecs_to_jiffies(WL1271_TX_FLUSH_TIMEOUT);
 
        while (!time_after(jiffies, timeout)) {
@@ -1048,6 +1062,12 @@ void wl1271_tx_flush(struct wl1271 *wl)
        }
 
        wl1271_warning("Unable to flush all TX buffers, timed out.");
+
+       /* forcibly flush all Tx buffers on our queues */
+       mutex_lock(&wl->mutex);
+       for (i = 0; i < WL12XX_MAX_LINKS; i++)
+               wl1271_tx_reset_link_queues(wl, i);
+       mutex_unlock(&wl->mutex);
 }
 
 u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set)
index 2dbb24e6d541a8c9dbff30efd9144f922217fb92..5cf8c32d40d14e1915a6e65eaa2e980b35ecaef3 100644 (file)
@@ -39,6 +39,7 @@
 #define TX_HW_ATTR_LAST_WORD_PAD         (BIT(10) | BIT(11))
 #define TX_HW_ATTR_TX_CMPLT_REQ          BIT(12)
 #define TX_HW_ATTR_TX_DUMMY_REQ          BIT(13)
+#define TX_HW_ATTR_HOST_ENCRYPT          BIT(14)
 
 #define TX_HW_ATTR_OFST_SAVE_RETRIES     0
 #define TX_HW_ATTR_OFST_HEADER_PAD       1
@@ -51,7 +52,9 @@
 #define TX_HW_RESULT_QUEUE_LEN_MASK      0xf
 
 #define WL1271_TX_ALIGN_TO 4
-#define WL1271_TKIP_IV_SPACE 4
+#define WL1271_EXTRA_SPACE_TKIP 4
+#define WL1271_EXTRA_SPACE_AES  8
+#define WL1271_EXTRA_SPACE_MAX  8
 
 /* Used for management frames and dummy packets */
 #define WL1271_TID_MGMT 7
@@ -224,5 +227,6 @@ void wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids);
 
 /* from main.c */
 void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid);
+void wl12xx_rearm_tx_watchdog_locked(struct wl1271 *wl);
 
 #endif
index b2b09cd0202256c4a623c65f6870160f5fa106b9..749a15a75d384c763b5bf68a06b038a3961e2af0 100644 (file)
 #include "conf.h"
 #include "ini.h"
 
-#define WL127X_FW_NAME "ti-connectivity/wl127x-fw-3.bin"
-#define WL128X_FW_NAME "ti-connectivity/wl128x-fw-3.bin"
+#define WL127X_FW_NAME_MULTI "ti-connectivity/wl127x-fw-4-mr.bin"
+#define WL127X_FW_NAME_SINGLE "ti-connectivity/wl127x-fw-4-sr.bin"
+
+#define WL128X_FW_NAME_MULTI "ti-connectivity/wl128x-fw-4-mr.bin"
+#define WL128X_FW_NAME_SINGLE "ti-connectivity/wl128x-fw-4-sr.bin"
+
+#define WL127X_PLT_FW_NAME "ti-connectivity/wl127x-fw-4-plt.bin"
+#define WL128X_PLT_FW_NAME "ti-connectivity/wl128x-fw-4-plt.bin"
 
 /*
  * wl127x and wl128x are using the same NVS file name. However, the
 enum wl1271_state {
        WL1271_STATE_OFF,
        WL1271_STATE_ON,
-       WL1271_STATE_PLT,
+};
+
+enum wl12xx_fw_type {
+       WL12XX_FW_TYPE_NONE,
+       WL12XX_FW_TYPE_NORMAL,
+       WL12XX_FW_TYPE_MULTI,
+       WL12XX_FW_TYPE_PLT,
 };
 
 enum wl1271_partition_type {
@@ -247,15 +259,17 @@ enum wl12xx_flags {
        WL1271_FLAG_PENDING_WORK,
        WL1271_FLAG_SOFT_GEMINI,
        WL1271_FLAG_RECOVERY_IN_PROGRESS,
+       WL1271_FLAG_VIF_CHANGE_IN_PROGRESS,
+       WL1271_FLAG_INTENDED_FW_RECOVERY,
 };
 
 enum wl12xx_vif_flags {
        WLVIF_FLAG_INITIALIZED,
        WLVIF_FLAG_STA_ASSOCIATED,
+       WLVIF_FLAG_STA_AUTHORIZED,
        WLVIF_FLAG_IBSS_JOINED,
        WLVIF_FLAG_AP_STARTED,
-       WLVIF_FLAG_PSM,
-       WLVIF_FLAG_PSM_REQUESTED,
+       WLVIF_FLAG_IN_PS,
        WLVIF_FLAG_STA_STATE_SENT,
        WLVIF_FLAG_RX_STREAMING_STARTED,
        WLVIF_FLAG_PSPOLL_FAILURE,
@@ -295,6 +309,9 @@ struct wl1271 {
        spinlock_t wl_lock;
 
        enum wl1271_state state;
+       enum wl12xx_fw_type fw_type;
+       bool plt;
+       u8 last_vif_count;
        struct mutex mutex;
 
        unsigned long flags;
@@ -313,7 +330,12 @@ struct wl1271 {
 
        s8 hw_pg_ver;
 
-       u8 mac_addr[ETH_ALEN];
+       /* address read from the fuse ROM */
+       u32 fuse_oui_addr;
+       u32 fuse_nic_addr;
+
+       /* we have up to 2 MAC addresses */
+       struct mac_address addresses[2];
        int channel;
        u8 system_hlid;
 
@@ -425,8 +447,6 @@ struct wl1271 {
        struct wl12xx_fw_status *fw_status;
        struct wl1271_tx_hw_res_if *tx_res_if;
 
-       struct ieee80211_vif *vif;
-
        /* Current chipset configuration */
        struct conf_drv_settings conf;
 
@@ -434,8 +454,6 @@ struct wl1271 {
 
        bool enable_11a;
 
-       struct list_head list;
-
        /* Most recently reported noise in dBm */
        s8 noise;
 
@@ -477,6 +495,9 @@ struct wl1271 {
 
        /* last wlvif we transmitted from */
        struct wl12xx_vif *last_wlvif;
+
+       /* work to fire when Tx is stuck */
+       struct delayed_work tx_watchdog_work;
 };
 
 struct wl1271_station {
@@ -503,6 +524,8 @@ struct wl12xx_vif {
                        u8 basic_rate_idx;
                        u8 ap_rate_idx;
                        u8 p2p_rate_idx;
+
+                       bool qos;
                } sta;
                struct {
                        u8 global_hlid;
@@ -560,12 +583,6 @@ struct wl12xx_vif {
        /* Session counter for the chipset */
        int session_counter;
 
-       struct completion *ps_compl;
-       struct delayed_work pspoll_work;
-
-       /* counter for ps-poll delivery failures */
-       int ps_poll_failures;
-
        /* retry counter for PSM entries */
        u8 psm_entry_retry;
 
@@ -575,6 +592,10 @@ struct wl12xx_vif {
        int rssi_thold;
        int last_rssi_event;
 
+       /* save the current encryption type for auto-arp config */
+       u8 encryption_type;
+       __be32 ip_addr;
+
        /* RX BA constraint value */
        bool ba_support;
        bool ba_allowed;
index 8f0ffaf62309f8208a1bd6299cf3fd1c66c29e45..22b0bc98d7b5baeb05aec26a180dc060f9712a6d 100644 (file)
@@ -117,7 +117,7 @@ struct wl12xx_ps_poll_template {
 } __packed;
 
 struct wl12xx_arp_rsp_template {
-       struct ieee80211_hdr_3addr hdr;
+       /* not including ieee80211 header */
 
        u8 llc_hdr[sizeof(rfc1042_header)];
        __be16 llc_type;
index 98a574a4a465004728792a293551ae867f450d6c..9fcde36d5013d9435d0070e2eadd4c36f5dc21aa 100644 (file)
@@ -306,9 +306,19 @@ int zd_op_start(struct ieee80211_hw *hw)
        r = set_mc_hash(mac);
        if (r)
                goto disable_int;
+
+       /* Wait after setting the multicast hash table and powering on
+        * the radio otherwise interface bring up will fail. This matches
+        * what the vendor driver did.
+        */
+       msleep(10);
+
        r = zd_chip_switch_radio_on(chip);
-       if (r < 0)
+       if (r < 0) {
+               dev_err(zd_chip_dev(chip),
+                       "%s: failed to set radio on\n", __func__);
                goto disable_int;
+       }
        r = zd_chip_enable_rxtx(chip);
        if (r < 0)
                goto disable_radio;
index 1a1500bc845233dc1537ea2b05c35379c33907e5..cb6204f783002dc3ddcc79adebcc79fa61cc4392 100644 (file)
@@ -736,6 +736,8 @@ static int pn533_target_found_type_a(struct nfc_target *nfc_tgt, u8 *tgt_data,
 
        nfc_tgt->sens_res = be16_to_cpu(tgt_type_a->sens_res);
        nfc_tgt->sel_res = tgt_type_a->sel_res;
+       nfc_tgt->nfcid1_len = tgt_type_a->nfcid_len;
+       memcpy(nfc_tgt->nfcid1, tgt_type_a->nfcid_data, nfc_tgt->nfcid1_len);
 
        return 0;
 }
@@ -781,6 +783,9 @@ static int pn533_target_found_felica(struct nfc_target *nfc_tgt, u8 *tgt_data,
        else
                nfc_tgt->supported_protocols = NFC_PROTO_FELICA_MASK;
 
+       memcpy(nfc_tgt->sensf_res, &tgt_felica->opcode, 9);
+       nfc_tgt->sensf_res_len = 9;
+
        return 0;
 }
 
@@ -823,6 +828,8 @@ static int pn533_target_found_jewel(struct nfc_target *nfc_tgt, u8 *tgt_data,
 
        nfc_tgt->supported_protocols = NFC_PROTO_JEWEL_MASK;
        nfc_tgt->sens_res = be16_to_cpu(tgt_jewel->sens_res);
+       nfc_tgt->nfcid1_len = 4;
+       memcpy(nfc_tgt->nfcid1, tgt_jewel->jewelid, nfc_tgt->nfcid1_len);
 
        return 0;
 }
@@ -902,6 +909,8 @@ static int pn533_target_found(struct pn533 *dev,
        if (resp->tg != 1)
                return -EPROTO;
 
+       memset(&nfc_tgt, 0, sizeof(struct nfc_target));
+
        target_data_len = resp_len - sizeof(struct pn533_poll_response);
 
        switch (dev->poll_mod_curr) {
@@ -1307,6 +1316,8 @@ static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg,
                nfc_dev_dbg(&dev->interface->dev, "Creating new target");
 
                nfc_target.supported_protocols = NFC_PROTO_NFC_DEP_MASK;
+               nfc_target.nfcid1_len = 10;
+               memcpy(nfc_target.nfcid1, resp->nfcid3t, nfc_target.nfcid1_len);
                rc = nfc_targets_found(dev->nfc_dev, &nfc_target, 1);
                if (rc)
                        return 0;
@@ -1329,21 +1340,15 @@ static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg,
 }
 
 static int pn533_dep_link_up(struct nfc_dev *nfc_dev, int target_idx,
-                                               u8 comm_mode, u8 rf_mode)
+                            u8 comm_mode, u8* gb, size_t gb_len)
 {
        struct pn533 *dev = nfc_get_drvdata(nfc_dev);
        struct pn533_cmd_jump_dep *cmd;
-       u8 cmd_len, local_gt_len, *local_gt;
+       u8 cmd_len;
        int rc;
 
        nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
-       if (rf_mode == NFC_RF_TARGET) {
-               nfc_dev_err(&dev->interface->dev, "Target mode not supported");
-               return -EOPNOTSUPP;
-       }
-
-
        if (dev->poll_mod_count) {
                nfc_dev_err(&dev->interface->dev,
                                "Cannot bring the DEP link up while polling");
@@ -1356,11 +1361,7 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, int target_idx,
                return -EBUSY;
        }
 
-       local_gt = nfc_get_local_general_bytes(dev->nfc_dev, &local_gt_len);
-       if (local_gt_len > NFC_MAX_GT_LEN)
-               return -EINVAL;
-
-       cmd_len = sizeof(struct pn533_cmd_jump_dep) + local_gt_len;
+       cmd_len = sizeof(struct pn533_cmd_jump_dep) + gb_len;
        cmd = kzalloc(cmd_len, GFP_KERNEL);
        if (cmd == NULL)
                return -ENOMEM;
@@ -1369,9 +1370,9 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, int target_idx,
 
        cmd->active = !comm_mode;
        cmd->baud = 0;
-       if (local_gt != NULL) {
+       if (gb != NULL && gb_len > 0) {
                cmd->next = 4; /* We have some Gi */
-               memcpy(cmd->gt, local_gt, local_gt_len);
+               memcpy(cmd->gt, gb, gb_len);
        } else {
                cmd->next = 0;
        }
index ea2bd1be26404092585dcb4d20b0ab113a808ab7..91a375fb6ae622181231fce19b1a5907e94c9f40 100644 (file)
@@ -23,7 +23,6 @@
 #include <asm/machdep.h>
 #endif /* CONFIG_PPC */
 
-#include <asm/setup.h>
 #include <asm/page.h>
 
 char *of_fdt_get_string(struct boot_param_header *blob, u32 offset)
index 980c079e444393cc17577e29204b5e28da299938..483c0adcad87d4701b866d6934137e34a5c38ed9 100644 (file)
@@ -182,7 +182,7 @@ struct phy_device *of_phy_connect_fixed_link(struct net_device *dev,
        if (!phy_id || sz < sizeof(*phy_id))
                return NULL;
 
-       sprintf(bus_id, PHY_ID_FMT, "0", be32_to_cpu(phy_id[0]));
+       sprintf(bus_id, PHY_ID_FMT, "fixed-0", be32_to_cpu(phy_id[0]));
 
        phy = phy_connect(dev, bus_id, hndlr, 0, iface);
        return IS_ERR(phy) ? NULL : phy;
index a9c46cc2db3701157485b8194af83a6c03c7b189..8c33491b21fe75b7b38fddcab4022676d274db43 100644 (file)
@@ -1,3 +1,5 @@
+#include <linux/prefetch.h>
+
 /**
  * iommu_fill_pdir - Insert coalesced scatter/gather chunks into the I/O Pdir.
  * @ioc: The I/O Controller.
index a87e2728b2c3a19cd50df8b6ae19de643296cceb..64d433ec4fc6f78fb7350fe333831e4e8e35371a 100644 (file)
@@ -328,21 +328,15 @@ static int pxa2xx_drv_pcmcia_probe(struct platform_device *dev)
                        goto err1;
        }
 
-       if (ret) {
-               while (--i >= 0)
-                       soc_pcmcia_remove_one(&sinfo->skt[i]);
-               kfree(sinfo);
-               clk_put(clk);
-       } else {
-               pxa2xx_configure_sockets(&dev->dev);
-               dev_set_drvdata(&dev->dev, sinfo);
-       }
+       pxa2xx_configure_sockets(&dev->dev);
+       dev_set_drvdata(&dev->dev, sinfo);
 
        return 0;
 
 err1:
        while (--i >= 0)
                soc_pcmcia_remove_one(&sinfo->skt[i]);
+       clk_put(clk);
        kfree(sinfo);
 err0:
        return ret;
index 2baadd21b7a664dea71cce5a237d66b0b8e36a25..98fbe62694d4eddbead50fde0de22fe834ce67a4 100644 (file)
@@ -369,9 +369,9 @@ static int __init pps_init(void)
        int err;
 
        pps_class = class_create(THIS_MODULE, "pps");
-       if (!pps_class) {
+       if (IS_ERR(pps_class)) {
                pr_err("failed to allocate class\n");
-               return -ENOMEM;
+               return PTR_ERR(pps_class);
        }
        pps_class->dev_attrs = pps_attrs;
 
index 68d720102296d6db01ff5d98dac0944b64a9c926..cd9bc3b129bc7fde6e07066ad28925fec4c6304b 100644 (file)
@@ -72,4 +72,17 @@ config DP83640_PHY
          In order for this to work, your MAC driver must also
          implement the skb_tx_timetamp() function.
 
+config PTP_1588_CLOCK_PCH
+       tristate "Intel PCH EG20T as PTP clock"
+       depends on PTP_1588_CLOCK
+       depends on PCH_GBE
+       help
+         This driver adds support for using the PCH EG20T as a PTP
+         clock. This clock is only useful if your PTP programs are
+         getting hardware time stamps on the PTP Ethernet packets
+         using the SO_TIMESTAMPING API.
+
+         To compile this driver as a module, choose M here: the module
+         will be called ptp_pch.
+
 endmenu
index f6933e83de724679d2c62948a7452ddead1a3683..8b58597298de392fa2ded9c8f5d3401e2932182d 100644 (file)
@@ -5,3 +5,4 @@
 ptp-y                                  := ptp_clock.o ptp_chardev.o ptp_sysfs.o
 obj-$(CONFIG_PTP_1588_CLOCK)           += ptp.o
 obj-$(CONFIG_PTP_1588_CLOCK_IXP46X)    += ptp_ixp46x.o
+obj-$(CONFIG_PTP_1588_CLOCK_PCH)       += ptp_pch.o
diff --git a/drivers/ptp/ptp_pch.c b/drivers/ptp/ptp_pch.c
new file mode 100644 (file)
index 0000000..375eb04
--- /dev/null
@@ -0,0 +1,730 @@
+/*
+ * PTP 1588 clock using the EG20T PCH
+ *
+ * Copyright (C) 2010 OMICRON electronics GmbH
+ * Copyright (C) 2011-2012 LAPIS SEMICONDUCTOR Co., LTD.
+ *
+ * This code was derived from the IXP46X driver.
+ *
+ * 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/ptp_clock_kernel.h>
+
+#define STATION_ADDR_LEN       20
+#define PCI_DEVICE_ID_PCH_1588 0x8819
+#define IO_MEM_BAR 1
+
+#define DEFAULT_ADDEND 0xA0000000
+#define TICKS_NS_SHIFT  5
+#define N_EXT_TS       2
+
+enum pch_status {
+       PCH_SUCCESS,
+       PCH_INVALIDPARAM,
+       PCH_NOTIMESTAMP,
+       PCH_INTERRUPTMODEINUSE,
+       PCH_FAILED,
+       PCH_UNSUPPORTED,
+};
+/**
+ * struct pch_ts_regs - IEEE 1588 registers
+ */
+struct pch_ts_regs {
+       u32 control;
+       u32 event;
+       u32 addend;
+       u32 accum;
+       u32 test;
+       u32 ts_compare;
+       u32 rsystime_lo;
+       u32 rsystime_hi;
+       u32 systime_lo;
+       u32 systime_hi;
+       u32 trgt_lo;
+       u32 trgt_hi;
+       u32 asms_lo;
+       u32 asms_hi;
+       u32 amms_lo;
+       u32 amms_hi;
+       u32 ch_control;
+       u32 ch_event;
+       u32 tx_snap_lo;
+       u32 tx_snap_hi;
+       u32 rx_snap_lo;
+       u32 rx_snap_hi;
+       u32 src_uuid_lo;
+       u32 src_uuid_hi;
+       u32 can_status;
+       u32 can_snap_lo;
+       u32 can_snap_hi;
+       u32 ts_sel;
+       u32 ts_st[6];
+       u32 reserve1[14];
+       u32 stl_max_set_en;
+       u32 stl_max_set;
+       u32 reserve2[13];
+       u32 srst;
+};
+
+#define PCH_TSC_RESET          (1 << 0)
+#define PCH_TSC_TTM_MASK       (1 << 1)
+#define PCH_TSC_ASMS_MASK      (1 << 2)
+#define PCH_TSC_AMMS_MASK      (1 << 3)
+#define PCH_TSC_PPSM_MASK      (1 << 4)
+#define PCH_TSE_TTIPEND                (1 << 1)
+#define PCH_TSE_SNS            (1 << 2)
+#define PCH_TSE_SNM            (1 << 3)
+#define PCH_TSE_PPS            (1 << 4)
+#define PCH_CC_MM              (1 << 0)
+#define PCH_CC_TA              (1 << 1)
+
+#define PCH_CC_MODE_SHIFT      16
+#define PCH_CC_MODE_MASK       0x001F0000
+#define PCH_CC_VERSION         (1 << 31)
+#define PCH_CE_TXS             (1 << 0)
+#define PCH_CE_RXS             (1 << 1)
+#define PCH_CE_OVR             (1 << 0)
+#define PCH_CE_VAL             (1 << 1)
+#define PCH_ECS_ETH            (1 << 0)
+
+#define PCH_ECS_CAN            (1 << 1)
+#define PCH_STATION_BYTES      6
+
+#define PCH_IEEE1588_ETH       (1 << 0)
+#define PCH_IEEE1588_CAN       (1 << 1)
+/**
+ * struct pch_dev - Driver private data
+ */
+struct pch_dev {
+       struct pch_ts_regs *regs;
+       struct ptp_clock *ptp_clock;
+       struct ptp_clock_info caps;
+       int exts0_enabled;
+       int exts1_enabled;
+
+       u32 mem_base;
+       u32 mem_size;
+       u32 irq;
+       struct pci_dev *pdev;
+       spinlock_t register_lock;
+};
+
+/**
+ * struct pch_params - 1588 module parameter
+ */
+struct pch_params {
+       u8 station[STATION_ADDR_LEN];
+};
+
+/* structure to hold the module parameters */
+static struct pch_params pch_param = {
+       "00:00:00:00:00:00"
+};
+
+/*
+ * Register access functions
+ */
+static inline void pch_eth_enable_set(struct pch_dev *chip)
+{
+       u32 val;
+       /* SET the eth_enable bit */
+       val = ioread32(&chip->regs->ts_sel) | (PCH_ECS_ETH);
+       iowrite32(val, (&chip->regs->ts_sel));
+}
+
+static u64 pch_systime_read(struct pch_ts_regs *regs)
+{
+       u64 ns;
+       u32 lo, hi;
+
+       lo = ioread32(&regs->systime_lo);
+       hi = ioread32(&regs->systime_hi);
+
+       ns = ((u64) hi) << 32;
+       ns |= lo;
+       ns <<= TICKS_NS_SHIFT;
+
+       return ns;
+}
+
+static void pch_systime_write(struct pch_ts_regs *regs, u64 ns)
+{
+       u32 hi, lo;
+
+       ns >>= TICKS_NS_SHIFT;
+       hi = ns >> 32;
+       lo = ns & 0xffffffff;
+
+       iowrite32(lo, &regs->systime_lo);
+       iowrite32(hi, &regs->systime_hi);
+}
+
+static inline void pch_block_reset(struct pch_dev *chip)
+{
+       u32 val;
+       /* Reset Hardware Assist block */
+       val = ioread32(&chip->regs->control) | PCH_TSC_RESET;
+       iowrite32(val, (&chip->regs->control));
+       val = val & ~PCH_TSC_RESET;
+       iowrite32(val, (&chip->regs->control));
+}
+
+u32 pch_ch_control_read(struct pci_dev *pdev)
+{
+       struct pch_dev *chip = pci_get_drvdata(pdev);
+       u32 val;
+
+       val = ioread32(&chip->regs->ch_control);
+
+       return val;
+}
+EXPORT_SYMBOL(pch_ch_control_read);
+
+void pch_ch_control_write(struct pci_dev *pdev, u32 val)
+{
+       struct pch_dev *chip = pci_get_drvdata(pdev);
+
+       iowrite32(val, (&chip->regs->ch_control));
+}
+EXPORT_SYMBOL(pch_ch_control_write);
+
+u32 pch_ch_event_read(struct pci_dev *pdev)
+{
+       struct pch_dev *chip = pci_get_drvdata(pdev);
+       u32 val;
+
+       val = ioread32(&chip->regs->ch_event);
+
+       return val;
+}
+EXPORT_SYMBOL(pch_ch_event_read);
+
+void pch_ch_event_write(struct pci_dev *pdev, u32 val)
+{
+       struct pch_dev *chip = pci_get_drvdata(pdev);
+
+       iowrite32(val, (&chip->regs->ch_event));
+}
+EXPORT_SYMBOL(pch_ch_event_write);
+
+u32 pch_src_uuid_lo_read(struct pci_dev *pdev)
+{
+       struct pch_dev *chip = pci_get_drvdata(pdev);
+       u32 val;
+
+       val = ioread32(&chip->regs->src_uuid_lo);
+
+       return val;
+}
+EXPORT_SYMBOL(pch_src_uuid_lo_read);
+
+u32 pch_src_uuid_hi_read(struct pci_dev *pdev)
+{
+       struct pch_dev *chip = pci_get_drvdata(pdev);
+       u32 val;
+
+       val = ioread32(&chip->regs->src_uuid_hi);
+
+       return val;
+}
+EXPORT_SYMBOL(pch_src_uuid_hi_read);
+
+u64 pch_rx_snap_read(struct pci_dev *pdev)
+{
+       struct pch_dev *chip = pci_get_drvdata(pdev);
+       u64 ns;
+       u32 lo, hi;
+
+       lo = ioread32(&chip->regs->rx_snap_lo);
+       hi = ioread32(&chip->regs->rx_snap_hi);
+
+       ns = ((u64) hi) << 32;
+       ns |= lo;
+
+       return ns;
+}
+EXPORT_SYMBOL(pch_rx_snap_read);
+
+u64 pch_tx_snap_read(struct pci_dev *pdev)
+{
+       struct pch_dev *chip = pci_get_drvdata(pdev);
+       u64 ns;
+       u32 lo, hi;
+
+       lo = ioread32(&chip->regs->tx_snap_lo);
+       hi = ioread32(&chip->regs->tx_snap_hi);
+
+       ns = ((u64) hi) << 32;
+       ns |= lo;
+
+       return ns;
+}
+EXPORT_SYMBOL(pch_tx_snap_read);
+
+/* This function enables all 64 bits in system time registers [high & low].
+This is a work-around for non continuous value in the SystemTime Register*/
+static void pch_set_system_time_count(struct pch_dev *chip)
+{
+       iowrite32(0x01, &chip->regs->stl_max_set_en);
+       iowrite32(0xFFFFFFFF, &chip->regs->stl_max_set);
+       iowrite32(0x00, &chip->regs->stl_max_set_en);
+}
+
+static void pch_reset(struct pch_dev *chip)
+{
+       /* Reset Hardware Assist */
+       pch_block_reset(chip);
+
+       /* enable all 32 bits in system time registers */
+       pch_set_system_time_count(chip);
+}
+
+/**
+ * pch_set_station_address() - This API sets the station address used by
+ *                                 IEEE 1588 hardware when looking at PTP
+ *                                 traffic on the  ethernet interface
+ * @addr:      dress which contain the column separated address to be used.
+ */
+static int pch_set_station_address(u8 *addr, struct pci_dev *pdev)
+{
+       s32 i;
+       struct pch_dev *chip = pci_get_drvdata(pdev);
+
+       /* Verify the parameter */
+       if ((chip->regs == 0) || addr == (u8 *)NULL) {
+               dev_err(&pdev->dev,
+                       "invalid params returning PCH_INVALIDPARAM\n");
+               return PCH_INVALIDPARAM;
+       }
+       /* For all station address bytes */
+       for (i = 0; i < PCH_STATION_BYTES; i++) {
+               u32 val;
+               s32 tmp;
+
+               tmp = hex_to_bin(addr[i * 3]);
+               if (tmp < 0) {
+                       dev_err(&pdev->dev,
+                               "invalid params returning PCH_INVALIDPARAM\n");
+                       return PCH_INVALIDPARAM;
+               }
+               val = tmp * 16;
+               tmp = hex_to_bin(addr[(i * 3) + 1]);
+               if (tmp < 0) {
+                       dev_err(&pdev->dev,
+                               "invalid params returning PCH_INVALIDPARAM\n");
+                       return PCH_INVALIDPARAM;
+               }
+               val += tmp;
+               /* Expects ':' separated addresses */
+               if ((i < 5) && (addr[(i * 3) + 2] != ':')) {
+                       dev_err(&pdev->dev,
+                               "invalid params returning PCH_INVALIDPARAM\n");
+                       return PCH_INVALIDPARAM;
+               }
+
+               /* Ideally we should set the address only after validating
+                                                        entire string */
+               dev_dbg(&pdev->dev, "invoking pch_station_set\n");
+               iowrite32(val, &chip->regs->ts_st[i]);
+       }
+       return 0;
+}
+
+/*
+ * Interrupt service routine
+ */
+static irqreturn_t isr(int irq, void *priv)
+{
+       struct pch_dev *pch_dev = priv;
+       struct pch_ts_regs *regs = pch_dev->regs;
+       struct ptp_clock_event event;
+       u32 ack = 0, lo, hi, val;
+
+       val = ioread32(&regs->event);
+
+       if (val & PCH_TSE_SNS) {
+               ack |= PCH_TSE_SNS;
+               if (pch_dev->exts0_enabled) {
+                       hi = ioread32(&regs->asms_hi);
+                       lo = ioread32(&regs->asms_lo);
+                       event.type = PTP_CLOCK_EXTTS;
+                       event.index = 0;
+                       event.timestamp = ((u64) hi) << 32;
+                       event.timestamp |= lo;
+                       event.timestamp <<= TICKS_NS_SHIFT;
+                       ptp_clock_event(pch_dev->ptp_clock, &event);
+               }
+       }
+
+       if (val & PCH_TSE_SNM) {
+               ack |= PCH_TSE_SNM;
+               if (pch_dev->exts1_enabled) {
+                       hi = ioread32(&regs->amms_hi);
+                       lo = ioread32(&regs->amms_lo);
+                       event.type = PTP_CLOCK_EXTTS;
+                       event.index = 1;
+                       event.timestamp = ((u64) hi) << 32;
+                       event.timestamp |= lo;
+                       event.timestamp <<= TICKS_NS_SHIFT;
+                       ptp_clock_event(pch_dev->ptp_clock, &event);
+               }
+       }
+
+       if (val & PCH_TSE_TTIPEND)
+               ack |= PCH_TSE_TTIPEND; /* this bit seems to be always set */
+
+       if (ack) {
+               iowrite32(ack, &regs->event);
+               return IRQ_HANDLED;
+       } else
+               return IRQ_NONE;
+}
+
+/*
+ * PTP clock operations
+ */
+
+static int ptp_pch_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
+{
+       u64 adj;
+       u32 diff, addend;
+       int neg_adj = 0;
+       struct pch_dev *pch_dev = container_of(ptp, struct pch_dev, caps);
+       struct pch_ts_regs *regs = pch_dev->regs;
+
+       if (ppb < 0) {
+               neg_adj = 1;
+               ppb = -ppb;
+       }
+       addend = DEFAULT_ADDEND;
+       adj = addend;
+       adj *= ppb;
+       diff = div_u64(adj, 1000000000ULL);
+
+       addend = neg_adj ? addend - diff : addend + diff;
+
+       iowrite32(addend, &regs->addend);
+
+       return 0;
+}
+
+static int ptp_pch_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+       s64 now;
+       unsigned long flags;
+       struct pch_dev *pch_dev = container_of(ptp, struct pch_dev, caps);
+       struct pch_ts_regs *regs = pch_dev->regs;
+
+       spin_lock_irqsave(&pch_dev->register_lock, flags);
+       now = pch_systime_read(regs);
+       now += delta;
+       pch_systime_write(regs, now);
+       spin_unlock_irqrestore(&pch_dev->register_lock, flags);
+
+       return 0;
+}
+
+static int ptp_pch_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
+{
+       u64 ns;
+       u32 remainder;
+       unsigned long flags;
+       struct pch_dev *pch_dev = container_of(ptp, struct pch_dev, caps);
+       struct pch_ts_regs *regs = pch_dev->regs;
+
+       spin_lock_irqsave(&pch_dev->register_lock, flags);
+       ns = pch_systime_read(regs);
+       spin_unlock_irqrestore(&pch_dev->register_lock, flags);
+
+       ts->tv_sec = div_u64_rem(ns, 1000000000, &remainder);
+       ts->tv_nsec = remainder;
+       return 0;
+}
+
+static int ptp_pch_settime(struct ptp_clock_info *ptp,
+                          const struct timespec *ts)
+{
+       u64 ns;
+       unsigned long flags;
+       struct pch_dev *pch_dev = container_of(ptp, struct pch_dev, caps);
+       struct pch_ts_regs *regs = pch_dev->regs;
+
+       ns = ts->tv_sec * 1000000000ULL;
+       ns += ts->tv_nsec;
+
+       spin_lock_irqsave(&pch_dev->register_lock, flags);
+       pch_systime_write(regs, ns);
+       spin_unlock_irqrestore(&pch_dev->register_lock, flags);
+
+       return 0;
+}
+
+static int ptp_pch_enable(struct ptp_clock_info *ptp,
+                         struct ptp_clock_request *rq, int on)
+{
+       struct pch_dev *pch_dev = container_of(ptp, struct pch_dev, caps);
+
+       switch (rq->type) {
+       case PTP_CLK_REQ_EXTTS:
+               switch (rq->extts.index) {
+               case 0:
+                       pch_dev->exts0_enabled = on ? 1 : 0;
+                       break;
+               case 1:
+                       pch_dev->exts1_enabled = on ? 1 : 0;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               return 0;
+       default:
+               break;
+       }
+
+       return -EOPNOTSUPP;
+}
+
+static struct ptp_clock_info ptp_pch_caps = {
+       .owner          = THIS_MODULE,
+       .name           = "PCH timer",
+       .max_adj        = 50000000,
+       .n_ext_ts       = N_EXT_TS,
+       .pps            = 0,
+       .adjfreq        = ptp_pch_adjfreq,
+       .adjtime        = ptp_pch_adjtime,
+       .gettime        = ptp_pch_gettime,
+       .settime        = ptp_pch_settime,
+       .enable         = ptp_pch_enable,
+};
+
+
+#ifdef CONFIG_PM
+static s32 pch_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       pci_disable_device(pdev);
+       pci_enable_wake(pdev, PCI_D3hot, 0);
+
+       if (pci_save_state(pdev) != 0) {
+               dev_err(&pdev->dev, "could not save PCI config state\n");
+               return -ENOMEM;
+       }
+       pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+       return 0;
+}
+
+static s32 pch_resume(struct pci_dev *pdev)
+{
+       s32 ret;
+
+       pci_set_power_state(pdev, PCI_D0);
+       pci_restore_state(pdev);
+       ret = pci_enable_device(pdev);
+       if (ret) {
+               dev_err(&pdev->dev, "pci_enable_device failed\n");
+               return ret;
+       }
+       pci_enable_wake(pdev, PCI_D3hot, 0);
+       return 0;
+}
+#else
+#define pch_suspend NULL
+#define pch_resume NULL
+#endif
+
+static void __devexit pch_remove(struct pci_dev *pdev)
+{
+       struct pch_dev *chip = pci_get_drvdata(pdev);
+
+       ptp_clock_unregister(chip->ptp_clock);
+       /* free the interrupt */
+       if (pdev->irq != 0)
+               free_irq(pdev->irq, chip);
+
+       /* unmap the virtual IO memory space */
+       if (chip->regs != 0) {
+               iounmap(chip->regs);
+               chip->regs = 0;
+       }
+       /* release the reserved IO memory space */
+       if (chip->mem_base != 0) {
+               release_mem_region(chip->mem_base, chip->mem_size);
+               chip->mem_base = 0;
+       }
+       pci_disable_device(pdev);
+       kfree(chip);
+       dev_info(&pdev->dev, "complete\n");
+}
+
+static s32 __devinit
+pch_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+       s32 ret;
+       unsigned long flags;
+       struct pch_dev *chip;
+
+       chip = kzalloc(sizeof(struct pch_dev), GFP_KERNEL);
+       if (chip == NULL)
+               return -ENOMEM;
+
+       /* enable the 1588 pci device */
+       ret = pci_enable_device(pdev);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "could not enable the pci device\n");
+               goto err_pci_en;
+       }
+
+       chip->mem_base = pci_resource_start(pdev, IO_MEM_BAR);
+       if (!chip->mem_base) {
+               dev_err(&pdev->dev, "could not locate IO memory address\n");
+               ret = -ENODEV;
+               goto err_pci_start;
+       }
+
+       /* retrieve the available length of the IO memory space */
+       chip->mem_size = pci_resource_len(pdev, IO_MEM_BAR);
+
+       /* allocate the memory for the device registers */
+       if (!request_mem_region(chip->mem_base, chip->mem_size, "1588_regs")) {
+               dev_err(&pdev->dev,
+                       "could not allocate register memory space\n");
+               ret = -EBUSY;
+               goto err_req_mem_region;
+       }
+
+       /* get the virtual address to the 1588 registers */
+       chip->regs = ioremap(chip->mem_base, chip->mem_size);
+
+       if (!chip->regs) {
+               dev_err(&pdev->dev, "Could not get virtual address\n");
+               ret = -ENOMEM;
+               goto err_ioremap;
+       }
+
+       chip->caps = ptp_pch_caps;
+       chip->ptp_clock = ptp_clock_register(&chip->caps);
+
+       if (IS_ERR(chip->ptp_clock))
+               return PTR_ERR(chip->ptp_clock);
+
+       spin_lock_init(&chip->register_lock);
+
+       ret = request_irq(pdev->irq, &isr, IRQF_SHARED, KBUILD_MODNAME, chip);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "failed to get irq %d\n", pdev->irq);
+               goto err_req_irq;
+       }
+
+       /* indicate success */
+       chip->irq = pdev->irq;
+       chip->pdev = pdev;
+       pci_set_drvdata(pdev, chip);
+
+       spin_lock_irqsave(&chip->register_lock, flags);
+       /* reset the ieee1588 h/w */
+       pch_reset(chip);
+
+       iowrite32(DEFAULT_ADDEND, &chip->regs->addend);
+       iowrite32(1, &chip->regs->trgt_lo);
+       iowrite32(0, &chip->regs->trgt_hi);
+       iowrite32(PCH_TSE_TTIPEND, &chip->regs->event);
+       /* Version: IEEE1588 v1 and IEEE1588-2008,  Mode: All Evwnt, Locked  */
+       iowrite32(0x80020000, &chip->regs->ch_control);
+
+       pch_eth_enable_set(chip);
+
+       if (strcmp(pch_param.station, "00:00:00:00:00:00") != 0) {
+               if (pch_set_station_address(pch_param.station, pdev) != 0) {
+                       dev_err(&pdev->dev,
+                       "Invalid station address parameter\n"
+                       "Module loaded but station address not set correctly\n"
+                       );
+               }
+       }
+       spin_unlock_irqrestore(&chip->register_lock, flags);
+       return 0;
+
+err_req_irq:
+       ptp_clock_unregister(chip->ptp_clock);
+       iounmap(chip->regs);
+       chip->regs = 0;
+
+err_ioremap:
+       release_mem_region(chip->mem_base, chip->mem_size);
+
+err_req_mem_region:
+       chip->mem_base = 0;
+
+err_pci_start:
+       pci_disable_device(pdev);
+
+err_pci_en:
+       kfree(chip);
+       dev_err(&pdev->dev, "probe failed(ret=0x%x)\n", ret);
+
+       return ret;
+}
+
+static DEFINE_PCI_DEVICE_TABLE(pch_ieee1588_pcidev_id) = {
+       {
+         .vendor = PCI_VENDOR_ID_INTEL,
+         .device = PCI_DEVICE_ID_PCH_1588
+        },
+       {0}
+};
+
+static struct pci_driver pch_driver = {
+       .name = KBUILD_MODNAME,
+       .id_table = pch_ieee1588_pcidev_id,
+       .probe = pch_probe,
+       .remove = pch_remove,
+       .suspend = pch_suspend,
+       .resume = pch_resume,
+};
+
+static void __exit ptp_pch_exit(void)
+{
+       pci_unregister_driver(&pch_driver);
+}
+
+static s32 __init ptp_pch_init(void)
+{
+       s32 ret;
+
+       /* register the driver with the pci core */
+       ret = pci_register_driver(&pch_driver);
+
+       return ret;
+}
+
+module_init(ptp_pch_init);
+module_exit(ptp_pch_exit);
+
+module_param_string(station, pch_param.station, sizeof pch_param.station, 0444);
+MODULE_PARM_DESC(station,
+        "IEEE 1588 station address to use - column separated hex values");
+
+MODULE_AUTHOR("LAPIS SEMICONDUCTOR, <tshimizu818@gmail.com>");
+MODULE_DESCRIPTION("PTP clock using the EG20T timer");
+MODULE_LICENSE("GPL");
index 691b1ab1a3d0499d85815bd03551e9d22518e494..30d2072f480b72947c74401d5522fbb9d697d313 100644 (file)
@@ -410,13 +410,14 @@ static void tsi721_db_dpc(struct work_struct *work)
         */
        mport = priv->mport;
 
-       wr_ptr = ioread32(priv->regs + TSI721_IDQ_WP(IDB_QUEUE));
-       rd_ptr = ioread32(priv->regs + TSI721_IDQ_RP(IDB_QUEUE));
+       wr_ptr = ioread32(priv->regs + TSI721_IDQ_WP(IDB_QUEUE)) % IDB_QSIZE;
+       rd_ptr = ioread32(priv->regs + TSI721_IDQ_RP(IDB_QUEUE)) % IDB_QSIZE;
 
        while (wr_ptr != rd_ptr) {
                idb_entry = (u64 *)(priv->idb_base +
                                        (TSI721_IDB_ENTRY_SIZE * rd_ptr));
                rd_ptr++;
+               rd_ptr %= IDB_QSIZE;
                idb.msg = *idb_entry;
                *idb_entry = 0;
 
index df33530cec4a458d0cf51be33ce60d81943116c3..28b81ae4cf7f32c18e2d752dad185c4926ba62b9 100644 (file)
@@ -196,7 +196,7 @@ static const unsigned int LDO12_suspend_table[] = {
 };
 
 static const unsigned int LDO13_table[] = {
-       1300000, 1800000, 2000000, 2500000, 2800000, 3000000, 0, 0,
+       1200000, 1300000, 1800000, 2000000, 2500000, 2800000, 3000000, 0,
 };
 
 static const unsigned int LDO13_suspend_table[] = {
@@ -389,10 +389,10 @@ static struct pm8607_regulator_info pm8607_regulator_info[] = {
        PM8607_LDO( 7,         LDO7, 0, 3, SUPPLIES_EN12, 1),
        PM8607_LDO( 8,         LDO8, 0, 3, SUPPLIES_EN12, 2),
        PM8607_LDO( 9,         LDO9, 0, 3, SUPPLIES_EN12, 3),
-       PM8607_LDO(10,        LDO10, 0, 3, SUPPLIES_EN12, 4),
+       PM8607_LDO(10,        LDO10, 0, 4, SUPPLIES_EN12, 4),
        PM8607_LDO(12,        LDO12, 0, 4, SUPPLIES_EN12, 5),
        PM8607_LDO(13, VIBRATOR_SET, 1, 3,  VIBRATOR_SET, 0),
-       PM8607_LDO(14,        LDO14, 0, 4, SUPPLIES_EN12, 6),
+       PM8607_LDO(14,        LDO14, 0, 3, SUPPLIES_EN12, 6),
 };
 
 static int __devinit pm8607_regulator_probe(struct platform_device *pdev)
index 3767364452fdd890785da5276f1f9b648be89aea..ea4d8f575ac6524676550789e93beb143cdb7cff 100644 (file)
@@ -260,8 +260,8 @@ static int da9052_set_ldo5_6_voltage(struct regulator_dev *rdev,
         * the LDO activate bit to implment the changes on the
         * LDO output.
        */
-       return da9052_reg_update(regulator->da9052, DA9052_SUPPLY_REG, 0,
-                                info->activate_bit);
+       return da9052_reg_update(regulator->da9052, DA9052_SUPPLY_REG,
+                                info->activate_bit, info->activate_bit);
 }
 
 static int da9052_set_dcdc_voltage(struct regulator_dev *rdev,
@@ -280,8 +280,8 @@ static int da9052_set_dcdc_voltage(struct regulator_dev *rdev,
         * the DCDC activate bit to implment the changes on the
         * DCDC output.
        */
-       return da9052_reg_update(regulator->da9052, DA9052_SUPPLY_REG, 0,
-                                info->activate_bit);
+       return da9052_reg_update(regulator->da9052, DA9052_SUPPLY_REG,
+                                info->activate_bit, info->activate_bit);
 }
 
 static int da9052_get_regulator_voltage_sel(struct regulator_dev *rdev)
index 5c15ba01e9c729bb6139b9d14fb52cb38f5337e8..40ecf5165899acac085ce7a650be780aead60fda 100644 (file)
@@ -662,7 +662,7 @@ static int tps65910_set_voltage_dcdc(struct regulator_dev *dev,
                tps65910_reg_write(pmic, TPS65910_VDD2_OP, vsel);
                break;
        case TPS65911_REG_VDDCTRL:
-               vsel = selector;
+               vsel = selector + 3;
                tps65910_reg_write(pmic, TPS65911_VDDCTRL_OP, vsel);
        }
 
index 9beba49c3c5b48c2abcca65c916eabc0d782a49a..2853c2a6f10f4a055d2aadb8d3fac0380bff7f97 100644 (file)
@@ -125,6 +125,13 @@ static int __devinit r9701_probe(struct spi_device *spi)
        unsigned char tmp;
        int res;
 
+       tmp = R100CNT;
+       res = read_regs(&spi->dev, &tmp, 1);
+       if (res || tmp != 0x20) {
+               dev_err(&spi->dev, "cannot read RTC register\n");
+               return -ENODEV;
+       }
+
        rtc = rtc_device_register("r9701",
                                &spi->dev, &r9701_rtc_ops, THIS_MODULE);
        if (IS_ERR(rtc))
@@ -132,13 +139,6 @@ static int __devinit r9701_probe(struct spi_device *spi)
 
        dev_set_drvdata(&spi->dev, rtc);
 
-       tmp = R100CNT;
-       res = read_regs(&spi->dev, &tmp, 1);
-       if (res || tmp != 0x20) {
-               rtc_device_unregister(rtc);
-               return res;
-       }
-
        return 0;
 }
 
index 70880be260151b62dce8ff5724a47bf8a28be7ac..2617b1ed4709bffd1f68971ebe27ea2e61e8f62f 100644 (file)
 #include <linux/hdreg.h>       /* HDIO_GETGEO                      */
 #include <linux/bio.h>
 #include <linux/module.h>
+#include <linux/compat.h>
 #include <linux/init.h>
 
 #include <asm/debug.h>
 #include <asm/idals.h>
 #include <asm/ebcdic.h>
-#include <asm/compat.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <asm/cio.h>
index f1a2016829fc5654335abaea3d7682eae4d33370..792c69e78fe2ae6474635680dba3c9af436b554e 100644 (file)
@@ -13,6 +13,7 @@
 #define KMSG_COMPONENT "dasd"
 
 #include <linux/interrupt.h>
+#include <linux/compat.h>
 #include <linux/major.h>
 #include <linux/fs.h>
 #include <linux/blkpg.h>
index e71298158f9eaa83a0531269a7da5c83c0c1d14a..911704571b9c1a862f4d8819bb89ad8f0f4c000f 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/console.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/compat.h>
 #include <linux/module.h>
 #include <linux/list.h>
 #include <linux/slab.h>
index 75bde6a8b7dc9277332b40be961bbc4888d1d497..89c03e6b1c0c633d5b3bb8cd051c83ae7aa8d1e4 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/fs.h>
 #include <linux/init.h>
+#include <linux/compat.h>
 #include <linux/kernel.h>
 #include <linux/miscdevice.h>
 #include <linux/slab.h>
index 0c87b0fc7714b42f3dedec1e1adc1035c2f96877..8f9a1a384496eb396ce2b0cbcec28327ddb48d3f 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #include <linux/slab.h>
+#include <linux/compat.h>
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/uaccess.h>
index 3ef8d071c64a683316a01b6e12ecd68f3d6f1d9d..770a740a393cd57bd24de3e0e19c1b852d9cd771 100644 (file)
@@ -167,7 +167,7 @@ again:
        DBF_ERROR("%4x EQBS ERROR", SCH_NO(q));
        DBF_ERROR("%3d%3d%2d", count, tmp_count, nr);
        q->handler(q->irq_ptr->cdev, QDIO_ERROR_ACTIVATE_CHECK_CONDITION,
-                  0, -1, -1, q->irq_ptr->int_parm);
+                  q->nr, q->first_to_kick, count, q->irq_ptr->int_parm);
        return 0;
 }
 
@@ -215,7 +215,7 @@ again:
        DBF_ERROR("%4x SQBS ERROR", SCH_NO(q));
        DBF_ERROR("%3d%3d%2d", count, tmp_count, nr);
        q->handler(q->irq_ptr->cdev, QDIO_ERROR_ACTIVATE_CHECK_CONDITION,
-                  0, -1, -1, q->irq_ptr->int_parm);
+                  q->nr, q->first_to_kick, count, q->irq_ptr->int_parm);
        return 0;
 }
 
index 2d602207541b20a95ed590c4186e2705cf7c077a..a69766900a17badf80952614a89182a915aba7fa 100644 (file)
@@ -1341,6 +1341,12 @@ static void ctcmpc_chx_txdone(fsm_instance *fi, int event, void *arg)
 
        spin_unlock(&ch->collect_lock);
        clear_normalized_cda(&ch->ccw[1]);
+
+       CTCM_PR_DBGDATA("ccwcda=0x%p data=0x%p\n",
+                       (void *)(unsigned long)ch->ccw[1].cda,
+                       ch->trans_skb->data);
+       ch->ccw[1].count = ch->max_bufsize;
+
        if (set_normalized_cda(&ch->ccw[1], ch->trans_skb->data)) {
                dev_kfree_skb_any(ch->trans_skb);
                ch->trans_skb = NULL;
@@ -1350,6 +1356,11 @@ static void ctcmpc_chx_txdone(fsm_instance *fi, int event, void *arg)
                fsm_event(priv->mpcg->fsm, MPCG_EVENT_INOP, dev);
                return;
        }
+
+       CTCM_PR_DBGDATA("ccwcda=0x%p data=0x%p\n",
+                       (void *)(unsigned long)ch->ccw[1].cda,
+                       ch->trans_skb->data);
+
        ch->ccw[1].count = ch->trans_skb->len;
        fsm_addtimer(&ch->timer, CTCM_TIME_5_SEC, CTC_EVENT_TIMER, ch);
        ch->prof.send_stamp = current_kernel_time(); /* xtime */
index 5cb93a8e340326b5a23a4d6e3c3e64a75b09749b..11f3b071f30539abd07001c25b09f9213fb6effa 100644 (file)
@@ -562,6 +562,9 @@ static int ctcm_transmit_skb(struct channel *ch, struct sk_buff *skb)
                skb_queue_tail(&ch->io_queue, skb);
                ccw_idx = 3;
        }
+       if (do_debug_ccw)
+               ctcmpc_dumpit((char *)&ch->ccw[ccw_idx],
+                                       sizeof(struct ccw1) * 3);
        ch->retry = 0;
        fsm_newstate(ch->fsm, CTC_STATE_TX);
        fsm_addtimer(&ch->timer, CTCM_TIME_5_SEC, CTC_EVENT_TIMER, ch);
index da4c747335e7ca448f5c69d803ba7dd898242df1..ac7975b7a837a9a3db240787d162e57d0fe26e17 100644 (file)
@@ -53,8 +53,8 @@
 #include <linux/moduleparam.h>
 #include <asm/idals.h>
 
-#include "ctcm_mpc.h"
 #include "ctcm_main.h"
+#include "ctcm_mpc.h"
 #include "ctcm_fsms.h"
 
 static const struct xid2 init_xid = {
@@ -132,7 +132,7 @@ void ctcmpc_dumpit(char *buf, int len)
        __u32   ct, sw, rm, dup;
        char    *ptr, *rptr;
        char    tbuf[82], tdup[82];
-       #if (UTS_MACHINE == s390x)
+       #ifdef CONFIG_64BIT
        char    addr[22];
        #else
        char    addr[12];
@@ -149,8 +149,8 @@ void ctcmpc_dumpit(char *buf, int len)
 
        for (ct = 0; ct < len; ct++, ptr++, rptr++) {
                if (sw == 0) {
-                       #if (UTS_MACHINE == s390x)
-                       sprintf(addr, "%16.16lx", (__u64)rptr);
+                       #ifdef CONFIG_64BIT
+                       sprintf(addr, "%16.16llx", (__u64)rptr);
                        #else
                        sprintf(addr, "%8.8X", (__u32)rptr);
                        #endif
@@ -164,8 +164,8 @@ void ctcmpc_dumpit(char *buf, int len)
                if (sw == 8)
                        strcat(bhex, "  ");
 
-               #if (UTS_MACHINE == s390x)
-               sprintf(tbuf, "%2.2lX", (__u64)*ptr);
+               #if CONFIG_64BIT
+               sprintf(tbuf, "%2.2llX", (__u64)*ptr);
                #else
                sprintf(tbuf, "%2.2X", (__u32)*ptr);
                #endif
index 863fc2197155c36c0f956cd9d3bb7781d8b46778..687efe4d589a517274687e17ae45f0d32d9739f6 100644 (file)
@@ -2240,7 +2240,7 @@ __lcs_shutdown_device(struct ccwgroup_device *ccwgdev, int recovery_mode)
 {
        struct lcs_card *card;
        enum lcs_dev_states recover_state;
-       int ret;
+       int ret = 0, ret2 = 0, ret3 = 0;
 
        LCS_DBF_TEXT(3, setup, "shtdndev");
        card = dev_get_drvdata(&ccwgdev->dev);
@@ -2255,13 +2255,15 @@ __lcs_shutdown_device(struct ccwgroup_device *ccwgdev, int recovery_mode)
        recover_state = card->state;
 
        ret = lcs_stop_device(card->dev);
-       ret = ccw_device_set_offline(card->read.ccwdev);
-       ret = ccw_device_set_offline(card->write.ccwdev);
+       ret2 = ccw_device_set_offline(card->read.ccwdev);
+       ret3 = ccw_device_set_offline(card->write.ccwdev);
+       if (!ret)
+               ret = (ret2) ? ret2 : ret3;
+       if (ret)
+               LCS_DBF_TEXT_(3, setup, "1err:%d", ret);
        if (recover_state == DEV_STATE_UP) {
                card->state = DEV_STATE_RECOVER;
        }
-       if (ret)
-               return ret;
        return 0;
 }
 
index cbb101828dc33f478b521331c176bd3153163fc6..120955c66410faf8e4c8254baebba15895d38aa9 100644 (file)
@@ -51,6 +51,7 @@ static struct kmem_cache *qeth_qdio_outbuf_cache;
 static struct device *qeth_core_root_dev;
 static unsigned int known_devices[][6] = QETH_MODELLIST_ARRAY;
 static struct lock_class_key qdio_out_skb_queue_key;
+static struct mutex qeth_mod_mutex;
 
 static void qeth_send_control_data_cb(struct qeth_channel *,
                        struct qeth_cmd_buffer *);
@@ -2944,8 +2945,8 @@ static int qeth_query_ipassists_cb(struct qeth_card *card,
                card->options.ipa6.enabled_funcs = cmd->hdr.ipa_enabled;
        }
        QETH_DBF_TEXT(SETUP, 2, "suppenbl");
-       QETH_DBF_TEXT_(SETUP, 2, "%x", cmd->hdr.ipa_supported);
-       QETH_DBF_TEXT_(SETUP, 2, "%x", cmd->hdr.ipa_enabled);
+       QETH_DBF_TEXT_(SETUP, 2, "%08x", (__u32)cmd->hdr.ipa_supported);
+       QETH_DBF_TEXT_(SETUP, 2, "%08x", (__u32)cmd->hdr.ipa_enabled);
        return 0;
 }
 
@@ -4321,7 +4322,7 @@ static int qeth_snmp_command_cb(struct qeth_card *card,
        /* check if there is enough room in userspace */
        if ((qinfo->udata_len - qinfo->udata_offset) < data_len) {
                QETH_CARD_TEXT_(card, 4, "scer3%i", -ENOMEM);
-               cmd->hdr.return_code = -ENOMEM;
+               cmd->hdr.return_code = IPA_RC_ENOMEM;
                return 0;
        }
        QETH_CARD_TEXT_(card, 4, "snore%i",
@@ -5040,6 +5041,7 @@ int qeth_core_load_discipline(struct qeth_card *card,
                enum qeth_discipline_id discipline)
 {
        int rc = 0;
+       mutex_lock(&qeth_mod_mutex);
        switch (discipline) {
        case QETH_DISCIPLINE_LAYER3:
                card->discipline.ccwgdriver = try_then_request_module(
@@ -5057,6 +5059,7 @@ int qeth_core_load_discipline(struct qeth_card *card,
                        "support discipline %d\n", discipline);
                rc = -EINVAL;
        }
+       mutex_unlock(&qeth_mod_mutex);
        return rc;
 }
 
@@ -5540,6 +5543,7 @@ static int __init qeth_core_init(void)
        pr_info("loading core functions\n");
        INIT_LIST_HEAD(&qeth_core_card_list.list);
        rwlock_init(&qeth_core_card_list.rwlock);
+       mutex_init(&qeth_mod_mutex);
 
        rc = qeth_register_dbf_views();
        if (rc)
index ec24901c802c565231f27a9b369c3fb19950ca9b..7fab6544def66b02f9756fe67a6d0a7a529077b5 100644 (file)
@@ -207,6 +207,7 @@ static struct ipa_rc_msg qeth_ipa_rc_msg[] = {
        {IPA_RC_MC_ADDR_ALREADY_DEFINED, "Multicast address already defined"},
        {IPA_RC_LAN_OFFLINE,            "STRTLAN_LAN_DISABLED - LAN offline"},
        {IPA_RC_INVALID_IP_VERSION2,    "Invalid IP version"},
+       {IPA_RC_ENOMEM,                 "Memory problem"},
        {IPA_RC_FFFF,                   "Unknown Error"}
 };
 
index 578e19a2de6bae7f92f4f737a38d352b87986b3d..ff41e42004ac4e13c880f5e45e8cf95eb7342ad5 100644 (file)
@@ -190,6 +190,7 @@ enum qeth_ipa_return_codes {
        IPA_RC_MC_ADDR_ALREADY_DEFINED  = 0xe013,
        IPA_RC_LAN_OFFLINE              = 0xe080,
        IPA_RC_INVALID_IP_VERSION2      = 0xf001,
+       IPA_RC_ENOMEM                   = 0xfffe,
        IPA_RC_FFFF                     = 0xffff
 };
 /* for DELIP */
index e5c9cf15e5c6b6983cf2a84a081fd28e5450cc42..0e7c29d1d7efc5991904a5d54f906a56086d244c 100644 (file)
@@ -576,7 +576,6 @@ static int qeth_l2_send_setmac_cb(struct qeth_card *card,
                default:
                        break;
                }
-               cmd->hdr.return_code = -EIO;
        } else {
                card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED;
                memcpy(card->dev->dev_addr, cmd->data.setdelmac.mac,
@@ -605,7 +604,6 @@ static int qeth_l2_send_delmac_cb(struct qeth_card *card,
        cmd = (struct qeth_ipa_cmd *) data;
        if (cmd->hdr.return_code) {
                QETH_CARD_TEXT_(card, 2, "err%d", cmd->hdr.return_code);
-               cmd->hdr.return_code = -EIO;
                return 0;
        }
        card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED;
@@ -682,7 +680,7 @@ static int qeth_l2_set_mac_address(struct net_device *dev, void *p)
        rc = qeth_l2_send_delmac(card, &card->dev->dev_addr[0]);
        if (!rc)
                rc = qeth_l2_send_setmac(card, addr->sa_data);
-       return rc;
+       return rc ? -EINVAL : 0;
 }
 
 static void qeth_l2_set_multicast_list(struct net_device *dev)
index 73bf8889984b33b72e7842a7fa407ee708d5c4c4..f859216076867b805548085ee1ea86ae5d4103e8 100644 (file)
@@ -2430,7 +2430,7 @@ static int qeth_l3_arp_query_cb(struct qeth_card *card,
 
                if ((qinfo->udata_len - qinfo->udata_offset) < esize) {
                        QETH_CARD_TEXT_(card, 4, "qaer3%i", -ENOMEM);
-                       cmd->hdr.return_code = -ENOMEM;
+                       cmd->hdr.return_code = IPA_RC_ENOMEM;
                        goto out_error;
                }
 
index 303dde09d294944b7ed51ed4eac717b2cbdbc223..fab2c2592a9744e400971b73c264fd9f2c3ab7b9 100644 (file)
@@ -11,6 +11,7 @@
 #define KMSG_COMPONENT "zfcp"
 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
 
+#include <linux/compat.h>
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/miscdevice.h>
index b31a8e3841d795154672cad902ec628bafb59c6f..d4ed9eb526572e07814e167eca89f94d22a3f73a 100644 (file)
 #ifndef SCSI_OSD_MAJOR
 #  define SCSI_OSD_MAJOR 260
 #endif
-#define SCSI_OSD_MAX_MINOR 64
+#define SCSI_OSD_MAX_MINOR MINORMASK
 
 static const char osd_name[] = "osd";
-static const char *osd_version_string = "open-osd 0.2.0";
+static const char *osd_version_string = "open-osd 0.2.1";
 
 MODULE_AUTHOR("Boaz Harrosh <bharrosh@panasas.com>");
 MODULE_DESCRIPTION("open-osd Upper-Layer-Driver osd.ko");
index 0cb39ff21171b323c3df916db675285420822136..f8fb2d691c0a69e6aed9385ba1a81d2cb893967c 100644 (file)
@@ -408,7 +408,7 @@ int sd_dif_prepare(struct request *rq, sector_t hw_sector, unsigned int sector_s
                        kunmap_atomic(sdt, KM_USER0);
                }
 
-               bio->bi_flags |= BIO_MAPPED_INTEGRITY;
+               bio->bi_flags |= (1 << BIO_MAPPED_INTEGRITY);
        }
 
        return 0;
index 2f9cb43a239870b6db396b8507fb6a67893f1f37..f37ad2271ad53729ba857bb732b646ebe92333a7 100644 (file)
@@ -1083,7 +1083,7 @@ err_alloc_rx_sg:
        return -ENOMEM;
 }
 
-static int __init pl022_dma_probe(struct pl022 *pl022)
+static int __devinit pl022_dma_probe(struct pl022 *pl022)
 {
        dma_cap_mask_t mask;
 
index befa89eac6f3c9319d913744eb2ffd4b29a12ced..ed4124469a3a34493088db68b725c081620ab81d 100644 (file)
@@ -331,7 +331,6 @@ static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
 {
        int i;
        u16 v;
-       s8 gain;
        u16 loc[3];
 
        if (out->revision == 3)                 /* rev 3 moved MAC */
@@ -390,20 +389,12 @@ static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
                SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0);
 
        /* Extract the antenna gain values. */
-       gain = r123_extract_antgain(out->revision, in,
-                                   SSB_SPROM1_AGAIN_BG,
-                                   SSB_SPROM1_AGAIN_BG_SHIFT);
-       out->antenna_gain.ghz24.a0 = gain;
-       out->antenna_gain.ghz24.a1 = gain;
-       out->antenna_gain.ghz24.a2 = gain;
-       out->antenna_gain.ghz24.a3 = gain;
-       gain = r123_extract_antgain(out->revision, in,
-                                   SSB_SPROM1_AGAIN_A,
-                                   SSB_SPROM1_AGAIN_A_SHIFT);
-       out->antenna_gain.ghz5.a0 = gain;
-       out->antenna_gain.ghz5.a1 = gain;
-       out->antenna_gain.ghz5.a2 = gain;
-       out->antenna_gain.ghz5.a3 = gain;
+       out->antenna_gain.a0 = r123_extract_antgain(out->revision, in,
+                                                   SSB_SPROM1_AGAIN_BG,
+                                                   SSB_SPROM1_AGAIN_BG_SHIFT);
+       out->antenna_gain.a1 = r123_extract_antgain(out->revision, in,
+                                                   SSB_SPROM1_AGAIN_A,
+                                                   SSB_SPROM1_AGAIN_A_SHIFT);
 }
 
 /* Revs 4 5 and 8 have partially shared layout */
@@ -504,16 +495,14 @@ static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in)
        }
 
        /* Extract the antenna gain values. */
-       SPEX(antenna_gain.ghz24.a0, SSB_SPROM4_AGAIN01,
+       SPEX(antenna_gain.a0, SSB_SPROM4_AGAIN01,
             SSB_SPROM4_AGAIN0, SSB_SPROM4_AGAIN0_SHIFT);
-       SPEX(antenna_gain.ghz24.a1, SSB_SPROM4_AGAIN01,
+       SPEX(antenna_gain.a1, SSB_SPROM4_AGAIN01,
             SSB_SPROM4_AGAIN1, SSB_SPROM4_AGAIN1_SHIFT);
-       SPEX(antenna_gain.ghz24.a2, SSB_SPROM4_AGAIN23,
+       SPEX(antenna_gain.a2, SSB_SPROM4_AGAIN23,
             SSB_SPROM4_AGAIN2, SSB_SPROM4_AGAIN2_SHIFT);
-       SPEX(antenna_gain.ghz24.a3, SSB_SPROM4_AGAIN23,
+       SPEX(antenna_gain.a3, SSB_SPROM4_AGAIN23,
             SSB_SPROM4_AGAIN3, SSB_SPROM4_AGAIN3_SHIFT);
-       memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24,
-              sizeof(out->antenna_gain.ghz5));
 
        sprom_extract_r458(out, in);
 
@@ -602,16 +591,14 @@ static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in)
        SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, 0xFFFFFFFF, 0);
 
        /* Extract the antenna gain values. */
-       SPEX(antenna_gain.ghz24.a0, SSB_SPROM8_AGAIN01,
+       SPEX(antenna_gain.a0, SSB_SPROM8_AGAIN01,
             SSB_SPROM8_AGAIN0, SSB_SPROM8_AGAIN0_SHIFT);
-       SPEX(antenna_gain.ghz24.a1, SSB_SPROM8_AGAIN01,
+       SPEX(antenna_gain.a1, SSB_SPROM8_AGAIN01,
             SSB_SPROM8_AGAIN1, SSB_SPROM8_AGAIN1_SHIFT);
-       SPEX(antenna_gain.ghz24.a2, SSB_SPROM8_AGAIN23,
+       SPEX(antenna_gain.a2, SSB_SPROM8_AGAIN23,
             SSB_SPROM8_AGAIN2, SSB_SPROM8_AGAIN2_SHIFT);
-       SPEX(antenna_gain.ghz24.a3, SSB_SPROM8_AGAIN23,
+       SPEX(antenna_gain.a3, SSB_SPROM8_AGAIN23,
             SSB_SPROM8_AGAIN3, SSB_SPROM8_AGAIN3_SHIFT);
-       memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24,
-              sizeof(out->antenna_gain.ghz5));
 
        /* Extract cores power info info */
        for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) {
index c821c6b2a6a0b778da37a7994ad1ad2d57335428..fbafed5b729bdcf6ae57889c3c9d4f05ca0509c5 100644 (file)
@@ -676,14 +676,10 @@ static int ssb_pcmcia_do_get_invariants(struct pcmcia_device *p_dev,
        case SSB_PCMCIA_CIS_ANTGAIN:
                GOTO_ERROR_ON(tuple->TupleDataLen != 2,
                        "antg tpl size");
-               sprom->antenna_gain.ghz24.a0 = tuple->TupleData[1];
-               sprom->antenna_gain.ghz24.a1 = tuple->TupleData[1];
-               sprom->antenna_gain.ghz24.a2 = tuple->TupleData[1];
-               sprom->antenna_gain.ghz24.a3 = tuple->TupleData[1];
-               sprom->antenna_gain.ghz5.a0 = tuple->TupleData[1];
-               sprom->antenna_gain.ghz5.a1 = tuple->TupleData[1];
-               sprom->antenna_gain.ghz5.a2 = tuple->TupleData[1];
-               sprom->antenna_gain.ghz5.a3 = tuple->TupleData[1];
+               sprom->antenna_gain.a0 = tuple->TupleData[1];
+               sprom->antenna_gain.a1 = tuple->TupleData[1];
+               sprom->antenna_gain.a2 = tuple->TupleData[1];
+               sprom->antenna_gain.a3 = tuple->TupleData[1];
                break;
        case SSB_PCMCIA_CIS_BFLAGS:
                GOTO_ERROR_ON((tuple->TupleDataLen != 3) &&
index 63fd709038caed0d7bbb70121159f27028bd0b41..b2d36f7736c537ef5ba6ec65d6144f965b75f971 100644 (file)
@@ -551,14 +551,10 @@ int ssb_sdio_get_invariants(struct ssb_bus *bus,
                        case SSB_SDIO_CIS_ANTGAIN:
                                GOTO_ERROR_ON(tuple->size != 2,
                                              "antg tpl size");
-                               sprom->antenna_gain.ghz24.a0 = tuple->data[1];
-                               sprom->antenna_gain.ghz24.a1 = tuple->data[1];
-                               sprom->antenna_gain.ghz24.a2 = tuple->data[1];
-                               sprom->antenna_gain.ghz24.a3 = tuple->data[1];
-                               sprom->antenna_gain.ghz5.a0 = tuple->data[1];
-                               sprom->antenna_gain.ghz5.a1 = tuple->data[1];
-                               sprom->antenna_gain.ghz5.a2 = tuple->data[1];
-                               sprom->antenna_gain.ghz5.a3 = tuple->data[1];
+                               sprom->antenna_gain.a0 = tuple->data[1];
+                               sprom->antenna_gain.a1 = tuple->data[1];
+                               sprom->antenna_gain.a2 = tuple->data[1];
+                               sprom->antenna_gain.a3 = tuple->data[1];
                                break;
                        case SSB_SDIO_CIS_BFLAGS:
                                GOTO_ERROR_ON((tuple->size != 3) &&
index b3d17416d86a393d75bc518b9198fa7277b165d8..830cd62d84925e548cd7480b2d6fb3a4e582a08d 100644 (file)
@@ -365,7 +365,7 @@ config PPC_EPAPR_HV_BYTECHAN
 
 config PPC_EARLY_DEBUG_EHV_BC
        bool "Early console (udbg) support for ePAPR hypervisors"
-       depends on PPC_EPAPR_HV_BYTECHAN
+       depends on PPC_EPAPR_HV_BYTECHAN=y
        help
          Select this option to enable early console (a.k.a. "udbg") support
          via an ePAPR byte channel.  You also need to choose the byte channel
index c26a82e83f6e6d11b78f002dc3982df9a3b0a27b..b556a72264d1084b5e6809ea5b4a3f59c5583b82 100644 (file)
@@ -239,7 +239,7 @@ static void ehci_fsl_setup_phy(struct ehci_hcd *ehci,
        ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]);
 }
 
-static int ehci_fsl_usb_setup(struct ehci_hcd *ehci)
+static void ehci_fsl_usb_setup(struct ehci_hcd *ehci)
 {
        struct usb_hcd *hcd = ehci_to_hcd(ehci);
        struct fsl_usb2_platform_data *pdata;
@@ -299,19 +299,12 @@ static int ehci_fsl_usb_setup(struct ehci_hcd *ehci)
 #endif
                out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
        }
-
-       if (!(in_be32(non_ehci + FSL_SOC_USB_CTRL) & CTRL_PHY_CLK_VALID)) {
-               printk(KERN_WARNING "fsl-ehci: USB PHY clock invalid\n");
-               return -ENODEV;
-       }
-       return 0;
 }
 
 /* called after powerup, by probe or system-pm "wakeup" */
 static int ehci_fsl_reinit(struct ehci_hcd *ehci)
 {
-       if (ehci_fsl_usb_setup(ehci))
-               return -ENODEV;
+       ehci_fsl_usb_setup(ehci);
        ehci_port_power(ehci, 0);
 
        return 0;
index bdf43e2adc51a4fdb4f12ca4e70b1e5c42c62f2c..4918062211656c276f5904cc50d45605076ed026 100644 (file)
@@ -45,6 +45,5 @@
 #define FSL_SOC_USB_PRICTRL    0x40c   /* NOTE: big-endian */
 #define FSL_SOC_USB_SICTRL     0x410   /* NOTE: big-endian */
 #define FSL_SOC_USB_CTRL       0x500   /* NOTE: big-endian */
-#define CTRL_PHY_CLK_VALID     (1 << 17)
 #define SNOOP_SIZE_2GB         0x1e
 #endif                         /* _EHCI_FSL_H */
index 74d29b552901e3ee5a6ee1d5b65f86da6eb124ad..408a9927be925159d9dd93d7fddfbf96eb3389c6 100644 (file)
@@ -12,7 +12,7 @@ config PANEL_GENERIC_DPI
 
 config PANEL_DVI
        tristate "DVI output"
-       depends on OMAP2_DSS_DPI
+       depends on OMAP2_DSS_DPI && I2C
        help
          Driver for external monitors, connected via DVI. The driver uses i2c
          to read EDID information from the monitor.
index 052dc874cd3d9e6696c36f9e6e214081433d07e5..87b3e25294cf506f7b70431b0a6fbc7df569a5f0 100644 (file)
@@ -1276,6 +1276,9 @@ int dss_ovl_enable(struct omap_overlay *ovl)
 
        spin_unlock_irqrestore(&data_lock, flags);
 
+       /* wait for overlay to be enabled */
+       wait_pending_extra_info_updates();
+
        mutex_unlock(&apply_lock);
 
        return 0;
@@ -1313,6 +1316,9 @@ int dss_ovl_disable(struct omap_overlay *ovl)
 
        spin_unlock_irqrestore(&data_lock, flags);
 
+       /* wait for the overlay to be disabled */
+       wait_pending_extra_info_updates();
+
        mutex_unlock(&apply_lock);
 
        return 0;
index d7aa3b056529e9469a8e3c0346ebbe421a2df1be..a36b934b2db4f8c5d7a71d67c4849020b54d455f 100644 (file)
@@ -165,9 +165,25 @@ static int hdmi_runtime_get(void)
 
        DSSDBG("hdmi_runtime_get\n");
 
+       /*
+        * HACK: Add dss_runtime_get() to ensure DSS clock domain is enabled.
+        * This should be removed later.
+        */
+       r = dss_runtime_get();
+       if (r < 0)
+               goto err_get_dss;
+
        r = pm_runtime_get_sync(&hdmi.pdev->dev);
        WARN_ON(r < 0);
-       return r < 0 ? r : 0;
+       if (r < 0)
+               goto err_get_hdmi;
+
+       return 0;
+
+err_get_hdmi:
+       dss_runtime_put();
+err_get_dss:
+       return r;
 }
 
 static void hdmi_runtime_put(void)
@@ -178,6 +194,12 @@ static void hdmi_runtime_put(void)
 
        r = pm_runtime_put_sync(&hdmi.pdev->dev);
        WARN_ON(r < 0);
+
+       /*
+        * HACK: This is added to complement the dss_runtime_get() call in
+        * hdmi_runtime_get(). This should be removed later.
+        */
+       dss_runtime_put();
 }
 
 int hdmi_init_display(struct omap_dss_device *dssdev)
index 2d72334ca3da9a7d3bac43fba0c7e1ce6c26621e..6847a478b4598d76138b9a331e92d5d0f0239d5c 100644 (file)
@@ -479,14 +479,7 @@ int ti_hdmi_4xxx_read_edid(struct hdmi_ip_data *ip_data,
 
 bool ti_hdmi_4xxx_detect(struct hdmi_ip_data *ip_data)
 {
-       int r;
-
-       void __iomem *base = hdmi_core_sys_base(ip_data);
-
-       /* HPD */
-       r = REG_GET(base, HDMI_CORE_SYS_SYS_STAT, 1, 1);
-
-       return r == 1;
+       return gpio_get_value(ip_data->hpd_gpio);
 }
 
 static void hdmi_core_init(struct hdmi_core_video_config *video_cfg,
index d5aaca9cfa7e2b7b6a4e5770b5965cbc199e262a..8497727d66de0d282d158d35a22b938918f3356a 100644 (file)
@@ -1810,7 +1810,11 @@ static void hw_init(void)
                break;
        }
 
+       /* magic required on VX900 for correct modesetting on IGA1 */
+       via_write_reg_mask(VIACR, 0x45, 0x00, 0x01);
+
        /* probably this should go to the scaling code one day */
+       via_write_reg_mask(VIACR, 0xFD, 0, 0x80); /* VX900 hw scale on IGA2 */
        viafb_write_regx(scaling_parameters, ARRAY_SIZE(scaling_parameters));
 
        /* Fill VPIT Parameters */
index 95aeedf198f8c9b6ee08fa59b8767d66f3ec0cc6..958e5129c6012560746643b9ec2c1de8ee350219 100644 (file)
@@ -367,29 +367,45 @@ static void __devexit virtballoon_remove(struct virtio_device *vdev)
 #ifdef CONFIG_PM
 static int virtballoon_freeze(struct virtio_device *vdev)
 {
+       struct virtio_balloon *vb = vdev->priv;
+
        /*
         * The kthread is already frozen by the PM core before this
         * function is called.
         */
 
+       while (vb->num_pages)
+               leak_balloon(vb, vb->num_pages);
+       update_balloon_size(vb);
+
        /* Ensure we don't get any more requests from the host */
        vdev->config->reset(vdev);
        vdev->config->del_vqs(vdev);
        return 0;
 }
 
+static int restore_common(struct virtio_device *vdev)
+{
+       struct virtio_balloon *vb = vdev->priv;
+       int ret;
+
+       ret = init_vqs(vdev->priv);
+       if (ret)
+               return ret;
+
+       fill_balloon(vb, towards_target(vb));
+       update_balloon_size(vb);
+       return 0;
+}
+
 static int virtballoon_thaw(struct virtio_device *vdev)
 {
-       return init_vqs(vdev->priv);
+       return restore_common(vdev);
 }
 
 static int virtballoon_restore(struct virtio_device *vdev)
 {
        struct virtio_balloon *vb = vdev->priv;
-       struct page *page, *page2;
-
-       /* We're starting from a clean slate */
-       vb->num_pages = 0;
 
        /*
         * If a request wasn't complete at the time of freezing, this
@@ -397,12 +413,7 @@ static int virtballoon_restore(struct virtio_device *vdev)
         */
        vb->need_stats_update = 0;
 
-       /* We don't have these pages in the balloon anymore! */
-       list_for_each_entry_safe(page, page2, &vb->pages, lru) {
-               list_del(&page->lru);
-               totalram_pages++;
-       }
-       return init_vqs(vdev->priv);
+       return restore_common(vdev);
 }
 #endif
 
index 877b107f77a769577111ce5f9eee41742be8fa32..df9e8f0e327d3247e025794a8ce431f9015439d8 100644 (file)
@@ -1098,7 +1098,7 @@ config BOOKE_WDT_DEFAULT_TIMEOUT
          For Freescale Book-E processors, this is a number between 0 and 63.
          For other Book-E processors, this is a number between 0 and 3.
 
-         The value can be overidden by the wdt_period command-line parameter.
+         The value can be overridden by the wdt_period command-line parameter.
 
 # PPC64 Architecture
 
index 337265b47305b7f74d7935f7da1b4c85e7fd99cf..7c0fdfca26469be5643f994a88c950c2855e4768 100644 (file)
@@ -198,9 +198,13 @@ static long booke_wdt_ioctl(struct file *file,
                booke_wdt_period = tmp;
 #endif
                booke_wdt_set();
-               return 0;
+               /* Fall */
        case WDIOC_GETTIMEOUT:
+#ifdef CONFIG_FSL_BOOKE
+               return put_user(period_to_sec(booke_wdt_period), p);
+#else
                return put_user(booke_wdt_period, p);
+#endif
        default:
                return -ENOTTY;
        }
index 8464ea1c36a1080f4c4b4045333a70b963d08b5d..3c166d3f4e558e4d73ef3ccc333a5678cf7654ee 100644 (file)
@@ -231,7 +231,7 @@ static int __devinit cru_detect(unsigned long map_entry,
 
        cmn_regs.u1.reax = CRU_BIOS_SIGNATURE_VALUE;
 
-       set_memory_x((unsigned long)bios32_entrypoint, (2 * PAGE_SIZE));
+       set_memory_x((unsigned long)bios32_map, 2);
        asminline_call(&cmn_regs, bios32_entrypoint);
 
        if (cmn_regs.u1.ral != 0) {
@@ -250,7 +250,8 @@ static int __devinit cru_detect(unsigned long map_entry,
                        cru_rom_addr =
                                ioremap(cru_physical_address, cru_length);
                        if (cru_rom_addr) {
-                               set_memory_x((unsigned long)cru_rom_addr, cru_length);
+                               set_memory_x((unsigned long)cru_rom_addr & PAGE_MASK,
+                                       (cru_length + PAGE_SIZE - 1) >> PAGE_SHIFT);
                                retval = 0;
                        }
                }
index 8e210aafdfd05396db165bd32c4f68a07e25e05f..dfae030a7ef2553ee6e2d44b59834bc4e3e57003 100644 (file)
@@ -264,7 +264,7 @@ static int __devinit pnx4008_wdt_probe(struct platform_device *pdev)
        wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (wdt_mem == NULL) {
                printk(KERN_INFO MODULE_NAME
-                       "failed to get memory region resouce\n");
+                       "failed to get memory region resource\n");
                return -ENOENT;
        }
 
index 4bc3744e14e4bf54f80a84585d3626d64635ba21..404172f02c9bea73f2be2b523c979693e69679d1 100644 (file)
@@ -312,18 +312,26 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev)
        dev = &pdev->dev;
        wdt_dev = &pdev->dev;
 
-       /* get the memory region for the watchdog timer */
-
        wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (wdt_mem == NULL) {
                dev_err(dev, "no memory resource specified\n");
                return -ENOENT;
        }
 
+       wdt_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (wdt_irq == NULL) {
+               dev_err(dev, "no irq resource specified\n");
+               ret = -ENOENT;
+               goto err;
+       }
+
+       /* get the memory region for the watchdog timer */
+
        size = resource_size(wdt_mem);
        if (!request_mem_region(wdt_mem->start, size, pdev->name)) {
                dev_err(dev, "failed to get memory region\n");
-               return -EBUSY;
+               ret = -EBUSY;
+               goto err;
        }
 
        wdt_base = ioremap(wdt_mem->start, size);
@@ -335,29 +343,17 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev)
 
        DBG("probe: mapped wdt_base=%p\n", wdt_base);
 
-       wdt_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (wdt_irq == NULL) {
-               dev_err(dev, "no irq resource specified\n");
-               ret = -ENOENT;
-               goto err_map;
-       }
-
-       ret = request_irq(wdt_irq->start, s3c2410wdt_irq, 0, pdev->name, pdev);
-       if (ret != 0) {
-               dev_err(dev, "failed to install irq (%d)\n", ret);
-               goto err_map;
-       }
-
        wdt_clock = clk_get(&pdev->dev, "watchdog");
        if (IS_ERR(wdt_clock)) {
                dev_err(dev, "failed to find watchdog clock source\n");
                ret = PTR_ERR(wdt_clock);
-               goto err_irq;
+               goto err_map;
        }
 
        clk_enable(wdt_clock);
 
-       if (s3c2410wdt_cpufreq_register() < 0) {
+       ret = s3c2410wdt_cpufreq_register();
+       if (ret < 0) {
                printk(KERN_ERR PFX "failed to register cpufreq\n");
                goto err_clk;
        }
@@ -378,12 +374,18 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev)
                                                        "cannot start\n");
        }
 
+       ret = request_irq(wdt_irq->start, s3c2410wdt_irq, 0, pdev->name, pdev);
+       if (ret != 0) {
+               dev_err(dev, "failed to install irq (%d)\n", ret);
+               goto err_cpufreq;
+       }
+
        watchdog_set_nowayout(&s3c2410_wdd, nowayout);
 
        ret = watchdog_register_device(&s3c2410_wdd);
        if (ret) {
                dev_err(dev, "cannot register watchdog (%d)\n", ret);
-               goto err_cpufreq;
+               goto err_irq;
        }
 
        if (tmr_atboot && started == 0) {
@@ -408,23 +410,26 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev)
 
        return 0;
 
+ err_irq:
+       free_irq(wdt_irq->start, pdev);
+
  err_cpufreq:
        s3c2410wdt_cpufreq_deregister();
 
  err_clk:
        clk_disable(wdt_clock);
        clk_put(wdt_clock);
-
- err_irq:
-       free_irq(wdt_irq->start, pdev);
+       wdt_clock = NULL;
 
  err_map:
        iounmap(wdt_base);
 
  err_req:
        release_mem_region(wdt_mem->start, size);
-       wdt_mem = NULL;
 
+ err:
+       wdt_irq = NULL;
+       wdt_mem = NULL;
        return ret;
 }
 
@@ -432,18 +437,18 @@ static int __devexit s3c2410wdt_remove(struct platform_device *dev)
 {
        watchdog_unregister_device(&s3c2410_wdd);
 
+       free_irq(wdt_irq->start, dev);
+
        s3c2410wdt_cpufreq_deregister();
 
        clk_disable(wdt_clock);
        clk_put(wdt_clock);
        wdt_clock = NULL;
 
-       free_irq(wdt_irq->start, dev);
-       wdt_irq = NULL;
-
        iounmap(wdt_base);
 
        release_mem_region(wdt_mem->start, resource_size(wdt_mem));
+       wdt_irq = NULL;
        wdt_mem = NULL;
        return 0;
 }
index 969beb0e22311a4f7e7f4155524709d5dd8269bf..67e4b9047cc944eb63beca468f77e1194956f931 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -490,6 +490,8 @@ static void kiocb_batch_free(struct kioctx *ctx, struct kiocb_batch *batch)
                kmem_cache_free(kiocb_cachep, req);
                ctx->reqs_active--;
        }
+       if (unlikely(!ctx->reqs_active && ctx->dead))
+               wake_up_all(&ctx->wait);
        spin_unlock_irq(&ctx->ctx_lock);
 }
 
index a6395bdb26aeb13b7b98c74df4f77780c1c95412..1ff94054d35aba8a5c0748585006641010a322af 100644 (file)
@@ -259,6 +259,13 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
        current->mm->free_area_cache = current->mm->mmap_base;
        current->mm->cached_hole_size = 0;
 
+       retval = setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT);
+       if (retval < 0) {
+               /* Someone check-me: is this error path enough? */
+               send_sig(SIGKILL, current, 0);
+               return retval;
+       }
+
        install_exec_creds(bprm);
        current->flags &= ~PF_FORKNOEXEC;
 
@@ -352,13 +359,6 @@ beyond_if:
                return retval;
        }
 
-       retval = setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT);
-       if (retval < 0) { 
-               /* Someone check-me: is this error path enough? */ 
-               send_sig(SIGKILL, current, 0); 
-               return retval;
-       }
-
        current->mm->start_stack =
                (unsigned long) create_aout_tables((char __user *) bprm->p, bprm);
 #ifdef __alpha__
index bcb884e2d613e76d94570dd81b99ba27e3906a66..07d096c49920cf21308480da107a6064a889db47 100644 (file)
@@ -1421,7 +1421,7 @@ static int fill_thread_core_info(struct elf_thread_core_info *t,
        for (i = 1; i < view->n; ++i) {
                const struct user_regset *regset = &view->regsets[i];
                do_thread_regset_writeback(t->task, regset);
-               if (regset->core_note_type &&
+               if (regset->core_note_type && regset->get &&
                    (!regset->active || regset->active(t->task, regset))) {
                        int ret;
                        size_t size = regset->n * regset->size;
index 63a196b97d5094a02e0f68b4fe5084051e7ad33a..bc7e24420ac0bee0ac2cab03e96224d1edf4adc7 100644 (file)
@@ -584,10 +584,26 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
                         * If either that or op not supported returned, follow
                         * the normal lookup.
                         */
-                       if ((rc == 0) || (rc == -ENOENT))
+                       switch (rc) {
+                       case 0:
+                               /*
+                                * The server may allow us to open things like
+                                * FIFOs, but the client isn't set up to deal
+                                * with that. If it's not a regular file, just
+                                * close it and proceed as if it were a normal
+                                * lookup.
+                                */
+                               if (newInode && !S_ISREG(newInode->i_mode)) {
+                                       CIFSSMBClose(xid, pTcon, fileHandle);
+                                       break;
+                               }
+                       case -ENOENT:
                                posix_open = true;
-                       else if ((rc == -EINVAL) || (rc != -EOPNOTSUPP))
+                       case -EOPNOTSUPP:
+                               break;
+                       default:
                                pTcon->broken_posix_open = true;
+                       }
                }
                if (!posix_open)
                        rc = cifs_get_inode_info_unix(&newInode, full_path,
index a5f54b7d98224dd613efaa3c89edfdebdc8817e6..745da3d0653e38a0f48db4f0741f3414e44d974e 100644 (file)
@@ -534,6 +534,11 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
        if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
                fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode;
                fattr->cf_dtype = DT_DIR;
+               /*
+                * Server can return wrong NumberOfLinks value for directories
+                * when Unix extensions are disabled - fake it.
+                */
+               fattr->cf_nlink = 2;
        } else {
                fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
                fattr->cf_dtype = DT_REG;
@@ -541,9 +546,9 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
                /* clear write bits if ATTR_READONLY is set */
                if (fattr->cf_cifsattrs & ATTR_READONLY)
                        fattr->cf_mode &= ~(S_IWUGO);
-       }
 
-       fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
+               fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
+       }
 
        fattr->cf_uid = cifs_sb->mnt_uid;
        fattr->cf_gid = cifs_sb->mnt_gid;
@@ -1322,7 +1327,6 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
                        }
 /*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need
        to set uid/gid */
-                       inc_nlink(inode);
 
                        cifs_unix_basic_to_fattr(&fattr, pInfo, cifs_sb);
                        cifs_fill_uniqueid(inode->i_sb, &fattr);
@@ -1355,7 +1359,6 @@ mkdir_retry_old:
                d_drop(direntry);
        } else {
 mkdir_get_info:
-               inc_nlink(inode);
                if (pTcon->unix_ext)
                        rc = cifs_get_inode_info_unix(&newinode, full_path,
                                                      inode->i_sb, xid);
@@ -1436,6 +1439,11 @@ mkdir_get_info:
                }
        }
 mkdir_out:
+       /*
+        * Force revalidate to get parent dir info when needed since cached
+        * attributes are invalid now.
+        */
+       CIFS_I(inode)->time = 0;
        kfree(full_path);
        FreeXid(xid);
        cifs_put_tlink(tlink);
@@ -1475,7 +1483,6 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
        cifs_put_tlink(tlink);
 
        if (!rc) {
-               drop_nlink(inode);
                spin_lock(&direntry->d_inode->i_lock);
                i_size_write(direntry->d_inode, 0);
                clear_nlink(direntry->d_inode);
@@ -1483,12 +1490,15 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
        }
 
        cifsInode = CIFS_I(direntry->d_inode);
-       cifsInode->time = 0;    /* force revalidate to go get info when
-                                  needed */
+       /* force revalidate to go get info when needed */
+       cifsInode->time = 0;
 
        cifsInode = CIFS_I(inode);
-       cifsInode->time = 0;    /* force revalidate to get parent dir info
-                                  since cached search results now invalid */
+       /*
+        * Force revalidate to get parent dir info when needed since cached
+        * attributes are invalid now.
+        */
+       cifsInode->time = 0;
 
        direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
                current_fs_time(inode->i_sb);
index fe19ac13f75f5c4e65ed1afaecd1c5d1ae34ffb6..bcbdb33fcc205aad37110be50752131aae894062 100644 (file)
@@ -104,7 +104,7 @@ static unsigned int d_hash_shift __read_mostly;
 
 static struct hlist_bl_head *dentry_hashtable __read_mostly;
 
-static inline struct hlist_bl_head *d_hash(struct dentry *parent,
+static inline struct hlist_bl_head *d_hash(const struct dentry *parent,
                                        unsigned long hash)
 {
        hash += ((unsigned long) parent ^ GOLDEN_RATIO_PRIME) / L1_CACHE_BYTES;
@@ -137,6 +137,26 @@ int proc_nr_dentry(ctl_table *table, int write, void __user *buffer,
 }
 #endif
 
+/*
+ * Compare 2 name strings, return 0 if they match, otherwise non-zero.
+ * The strings are both count bytes long, and count is non-zero.
+ */
+static inline int dentry_cmp(const unsigned char *cs, size_t scount,
+                               const unsigned char *ct, size_t tcount)
+{
+       if (scount != tcount)
+               return 1;
+
+       do {
+               if (*cs != *ct)
+                       return 1;
+               cs++;
+               ct++;
+               tcount--;
+       } while (tcount);
+       return 0;
+}
+
 static void __d_free(struct rcu_head *head)
 {
        struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu);
@@ -1717,8 +1737,9 @@ EXPORT_SYMBOL(d_add_ci);
  * child is looked up. Thus, an interlocking stepping of sequence lock checks
  * is formed, giving integrity down the path walk.
  */
-struct dentry *__d_lookup_rcu(struct dentry *parent, struct qstr *name,
-                               unsigned *seq, struct inode **inode)
+struct dentry *__d_lookup_rcu(const struct dentry *parent,
+                               const struct qstr *name,
+                               unsigned *seqp, struct inode **inode)
 {
        unsigned int len = name->len;
        unsigned int hash = name->hash;
@@ -1748,6 +1769,7 @@ struct dentry *__d_lookup_rcu(struct dentry *parent, struct qstr *name,
         * See Documentation/filesystems/path-lookup.txt for more details.
         */
        hlist_bl_for_each_entry_rcu(dentry, node, b, d_hash) {
+               unsigned seq;
                struct inode *i;
                const char *tname;
                int tlen;
@@ -1756,7 +1778,7 @@ struct dentry *__d_lookup_rcu(struct dentry *parent, struct qstr *name,
                        continue;
 
 seqretry:
-               *seq = read_seqcount_begin(&dentry->d_seq);
+               seq = read_seqcount_begin(&dentry->d_seq);
                if (dentry->d_parent != parent)
                        continue;
                if (d_unhashed(dentry))
@@ -1771,7 +1793,7 @@ seqretry:
                 * edge of memory when walking. If we could load this
                 * atomically some other way, we could drop this check.
                 */
-               if (read_seqcount_retry(&dentry->d_seq, *seq))
+               if (read_seqcount_retry(&dentry->d_seq, seq))
                        goto seqretry;
                if (unlikely(parent->d_flags & DCACHE_OP_COMPARE)) {
                        if (parent->d_op->d_compare(parent, *inode,
@@ -1788,6 +1810,7 @@ seqretry:
                 * order to do anything useful with the returned dentry
                 * anyway.
                 */
+               *seqp = seq;
                *inode = i;
                return dentry;
        }
index 0b3109ee42571e258fd4a2ff3ef342e9ddb1658c..ca0c59a4246c92d66812063df59403d199e6d8e0 100644 (file)
@@ -52,6 +52,7 @@
 #include <linux/mutex.h>
 #include <linux/sctp.h>
 #include <linux/slab.h>
+#include <net/sctp/sctp.h>
 #include <net/sctp/user.h>
 #include <net/ipv6.h>
 
@@ -474,9 +475,6 @@ static void process_sctp_notification(struct connection *con,
                        int prim_len, ret;
                        int addr_len;
                        struct connection *new_con;
-                       sctp_peeloff_arg_t parg;
-                       int parglen = sizeof(parg);
-                       int err;
 
                        /*
                         * We get this before any data for an association.
@@ -525,23 +523,19 @@ static void process_sctp_notification(struct connection *con,
                                return;
 
                        /* Peel off a new sock */
-                       parg.associd = sn->sn_assoc_change.sac_assoc_id;
-                       ret = kernel_getsockopt(con->sock, IPPROTO_SCTP,
-                                               SCTP_SOCKOPT_PEELOFF,
-                                               (void *)&parg, &parglen);
+                       sctp_lock_sock(con->sock->sk);
+                       ret = sctp_do_peeloff(con->sock->sk,
+                               sn->sn_assoc_change.sac_assoc_id,
+                               &new_con->sock);
+                       sctp_release_sock(con->sock->sk);
                        if (ret < 0) {
                                log_print("Can't peel off a socket for "
                                          "connection %d to node %d: err=%d",
-                                         parg.associd, nodeid, ret);
-                               return;
-                       }
-                       new_con->sock = sockfd_lookup(parg.sd, &err);
-                       if (!new_con->sock) {
-                               log_print("sockfd_lookup error %d", err);
+                                         (int)sn->sn_assoc_change.sac_assoc_id,
+                                         nodeid, ret);
                                return;
                        }
                        add_sock(new_con->sock, new_con);
-                       sockfd_put(new_con->sock);
 
                        log_print("connecting to %d sctp association %d",
                                 nodeid, (int)sn->sn_assoc_change.sac_assoc_id);
index 349209dc6a9162d18b7da50c891a389aa9c648d8..3a06f4043df42a811add69fd7ede7b582a94c347 100644 (file)
@@ -429,7 +429,7 @@ ecryptfs_miscdev_write(struct file *file, const char __user *buf,
                goto memdup;
        } else if (count < MIN_MSG_PKT_SIZE || count > MAX_MSG_PKT_SIZE) {
                printk(KERN_WARNING "%s: Acceptable packet size range is "
-                      "[%d-%lu], but amount of data written is [%zu].",
+                      "[%d-%zu], but amount of data written is [%zu].",
                       __func__, MIN_MSG_PKT_SIZE, MAX_MSG_PKT_SIZE, count);
                return -EINVAL;
        }
index 92ce83a11e90acbb0bceda45b682a83535089342..153dee14fe559b9180a2f79b4b1f8534e25c76f5 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1915,7 +1915,6 @@ static int coredump_wait(int exit_code, struct core_state *core_state)
 {
        struct task_struct *tsk = current;
        struct mm_struct *mm = tsk->mm;
-       struct completion *vfork_done;
        int core_waiters = -EBUSY;
 
        init_completion(&core_state->startup);
@@ -1927,22 +1926,9 @@ static int coredump_wait(int exit_code, struct core_state *core_state)
                core_waiters = zap_threads(tsk, mm, core_state, exit_code);
        up_write(&mm->mmap_sem);
 
-       if (unlikely(core_waiters < 0))
-               goto fail;
-
-       /*
-        * Make sure nobody is waiting for us to release the VM,
-        * otherwise we can deadlock when we wait on each other
-        */
-       vfork_done = tsk->vfork_done;
-       if (vfork_done) {
-               tsk->vfork_done = NULL;
-               complete(vfork_done);
-       }
-
-       if (core_waiters)
+       if (core_waiters > 0)
                wait_for_completion(&core_state->startup);
-fail:
+
        return core_waiters;
 }
 
index 376816fcd04084f0cad9ad522aab51d8ce0ff7f1..351a3e797789a802669a084d3eef1c771583c6e3 100644 (file)
@@ -167,14 +167,19 @@ void gfs2_glock_add_to_lru(struct gfs2_glock *gl)
        spin_unlock(&lru_lock);
 }
 
-static void gfs2_glock_remove_from_lru(struct gfs2_glock *gl)
+static void __gfs2_glock_remove_from_lru(struct gfs2_glock *gl)
 {
-       spin_lock(&lru_lock);
        if (!list_empty(&gl->gl_lru)) {
                list_del_init(&gl->gl_lru);
                atomic_dec(&lru_count);
                clear_bit(GLF_LRU, &gl->gl_flags);
        }
+}
+
+static void gfs2_glock_remove_from_lru(struct gfs2_glock *gl)
+{
+       spin_lock(&lru_lock);
+       __gfs2_glock_remove_from_lru(gl);
        spin_unlock(&lru_lock);
 }
 
@@ -217,11 +222,12 @@ void gfs2_glock_put(struct gfs2_glock *gl)
        struct gfs2_sbd *sdp = gl->gl_sbd;
        struct address_space *mapping = gfs2_glock2aspace(gl);
 
-       if (atomic_dec_and_test(&gl->gl_ref)) {
+       if (atomic_dec_and_lock(&gl->gl_ref, &lru_lock)) {
+               __gfs2_glock_remove_from_lru(gl);
+               spin_unlock(&lru_lock);
                spin_lock_bucket(gl->gl_hash);
                hlist_bl_del_rcu(&gl->gl_list);
                spin_unlock_bucket(gl->gl_hash);
-               gfs2_glock_remove_from_lru(gl);
                GLOCK_BUG_ON(gl, !list_empty(&gl->gl_holders));
                GLOCK_BUG_ON(gl, mapping && mapping->nrpages);
                trace_gfs2_glock_put(gl);
index a7d611b93f0fca912ce716736df2524cad7b40be..56987460cdae2f2ca075aad642a4cd7f53a0152f 100644 (file)
@@ -391,10 +391,6 @@ static int alloc_dinode(struct gfs2_inode *dip, u64 *no_addr, u64 *generation)
        int error;
        int dblocks = 1;
 
-       error = gfs2_rindex_update(sdp);
-       if (error)
-               fs_warn(sdp, "rindex update returns %d\n", error);
-
        error = gfs2_inplace_reserve(dip, RES_DINODE);
        if (error)
                goto out;
@@ -1043,6 +1039,7 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry)
        rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr);
        if (!rgd)
                goto out_inodes;
+
        gfs2_holder_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + 2);
 
 
index 6aacf3f230a29d934347d2d2b130547769b2004e..24f609c9ef911edb3b3cabc9dc98dc4a78e1b92d 100644 (file)
@@ -800,6 +800,11 @@ static int init_inodes(struct gfs2_sbd *sdp, int undo)
                fs_err(sdp, "can't get quota file inode: %d\n", error);
                goto fail_rindex;
        }
+
+       error = gfs2_rindex_update(sdp);
+       if (error)
+               goto fail_qinode;
+
        return 0;
 
 fail_qinode:
index 981bfa32121a16c11c53fea23f0e734617755bfa..49ada95209d0108e333ddd164b44534edc8fa86b 100644 (file)
@@ -683,16 +683,21 @@ int gfs2_rindex_update(struct gfs2_sbd *sdp)
        struct gfs2_glock *gl = ip->i_gl;
        struct gfs2_holder ri_gh;
        int error = 0;
+       int unlock_required = 0;
 
        /* Read new copy from disk if we don't have the latest */
        if (!sdp->sd_rindex_uptodate) {
                mutex_lock(&sdp->sd_rindex_mutex);
-               error = gfs2_glock_nq_init(gl, LM_ST_SHARED, 0, &ri_gh);
-               if (error)
-                       return error;
+               if (!gfs2_glock_is_locked_by_me(gl)) {
+                       error = gfs2_glock_nq_init(gl, LM_ST_SHARED, 0, &ri_gh);
+                       if (error)
+                               return error;
+                       unlock_required = 1;
+               }
                if (!sdp->sd_rindex_uptodate)
                        error = gfs2_ri_update(ip);
-               gfs2_glock_dq_uninit(&ri_gh);
+               if (unlock_required)
+                       gfs2_glock_dq_uninit(&ri_gh);
                mutex_unlock(&sdp->sd_rindex_mutex);
        }
 
index a780ea515c47988623fc4954b734562182ed24c5..e2ba62820a0f35ee0531a4ad6ac0dc6725ad0b58 100644 (file)
@@ -1374,6 +1374,34 @@ static inline int can_lookup(struct inode *inode)
        return 1;
 }
 
+unsigned int full_name_hash(const unsigned char *name, unsigned int len)
+{
+       unsigned long hash = init_name_hash();
+       while (len--)
+               hash = partial_name_hash(*name++, hash);
+       return end_name_hash(hash);
+}
+EXPORT_SYMBOL(full_name_hash);
+
+/*
+ * We know there's a real path component here of at least
+ * one character.
+ */
+static inline unsigned long hash_name(const char *name, unsigned int *hashp)
+{
+       unsigned long hash = init_name_hash();
+       unsigned long len = 0, c;
+
+       c = (unsigned char)*name;
+       do {
+               len++;
+               hash = partial_name_hash(c, hash);
+               c = (unsigned char)name[len];
+       } while (c && c != '/');
+       *hashp = end_name_hash(hash);
+       return len;
+}
+
 /*
  * Name resolution.
  * This is the basic name resolution function, turning a pathname into
@@ -1394,31 +1422,22 @@ static int link_path_walk(const char *name, struct nameidata *nd)
 
        /* At this point we know we have a real path component. */
        for(;;) {
-               unsigned long hash;
                struct qstr this;
-               unsigned int c;
+               long len;
                int type;
 
                err = may_lookup(nd);
                if (err)
                        break;
 
+               len = hash_name(name, &this.hash);
                this.name = name;
-               c = *(const unsigned char *)name;
-
-               hash = init_name_hash();
-               do {
-                       name++;
-                       hash = partial_name_hash(c, hash);
-                       c = *(const unsigned char *)name;
-               } while (c && (c != '/'));
-               this.len = name - (const char *) this.name;
-               this.hash = end_name_hash(hash);
+               this.len = len;
 
                type = LAST_NORM;
-               if (this.name[0] == '.') switch (this.len) {
+               if (name[0] == '.') switch (len) {
                        case 2:
-                               if (this.name[1] == '.') {
+                               if (name[1] == '.') {
                                        type = LAST_DOTDOT;
                                        nd->flags |= LOOKUP_JUMPED;
                                }
@@ -1437,12 +1456,18 @@ static int link_path_walk(const char *name, struct nameidata *nd)
                        }
                }
 
-               /* remove trailing slashes? */
-               if (!c)
+               if (!name[len])
                        goto last_component;
-               while (*++name == '/');
-               if (!*name)
+               /*
+                * If it wasn't NUL, we know it was '/'. Skip that
+                * slash, and continue until no more slashes.
+                */
+               do {
+                       len++;
+               } while (unlikely(name[len] == '/'));
+               if (!name[len])
                        goto last_component;
+               name += len;
 
                err = walk_component(nd, &next, &this, type, LOOKUP_FOLLOW);
                if (err < 0)
@@ -1775,24 +1800,21 @@ static struct dentry *lookup_hash(struct nameidata *nd)
 struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
 {
        struct qstr this;
-       unsigned long hash;
        unsigned int c;
 
        WARN_ON_ONCE(!mutex_is_locked(&base->d_inode->i_mutex));
 
        this.name = name;
        this.len = len;
+       this.hash = full_name_hash(name, len);
        if (!len)
                return ERR_PTR(-EACCES);
 
-       hash = init_name_hash();
        while (len--) {
                c = *(const unsigned char *)name++;
                if (c == '/' || c == '\0')
                        return ERR_PTR(-EACCES);
-               hash = partial_name_hash(c, hash);
        }
-       this.hash = end_name_hash(hash);
        /*
         * See if the low-level filesystem might want
         * to use its own hash..
index f14fde2b03d68f03e38b1aa62580227a5243cc91..e0281992ddc33377bb47287d967336012c2d3d48 100644 (file)
@@ -1,7 +1,7 @@
 /**
  * attrib.c - NTFS attribute operations.  Part of the Linux-NTFS project.
  *
- * Copyright (c) 2001-2007 Anton Altaparmakov
+ * Copyright (c) 2001-2012 Anton Altaparmakov and Tuxera Inc.
  * Copyright (c) 2002 Richard Russon
  *
  * This program/include file is free software; you can redistribute it and/or
@@ -345,10 +345,10 @@ LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn,
        unsigned long flags;
        bool is_retry = false;
 
+       BUG_ON(!ni);
        ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, %s_locked.",
                        ni->mft_no, (unsigned long long)vcn,
                        write_locked ? "write" : "read");
-       BUG_ON(!ni);
        BUG_ON(!NInoNonResident(ni));
        BUG_ON(vcn < 0);
        if (!ni->runlist.rl) {
@@ -469,9 +469,9 @@ runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni, const VCN vcn,
        int err = 0;
        bool is_retry = false;
 
+       BUG_ON(!ni);
        ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, with%s ctx.",
                        ni->mft_no, (unsigned long long)vcn, ctx ? "" : "out");
-       BUG_ON(!ni);
        BUG_ON(!NInoNonResident(ni));
        BUG_ON(vcn < 0);
        if (!ni->runlist.rl) {
index 382857f9c7db34c0edd3957f9beb65355e02f2a1..3014a36a255b97ddcac0b1852fa0d11c613b7a9d 100644 (file)
@@ -1,7 +1,7 @@
 /**
  * mft.c - NTFS kernel mft record operations. Part of the Linux-NTFS project.
  *
- * Copyright (c) 2001-2011 Anton Altaparmakov and Tuxera Inc.
+ * Copyright (c) 2001-2012 Anton Altaparmakov and Tuxera Inc.
  * Copyright (c) 2002 Richard Russon
  *
  * This program/include file is free software; you can redistribute it and/or
@@ -1367,7 +1367,7 @@ static int ntfs_mft_bitmap_extend_allocation_nolock(ntfs_volume *vol)
                        ntfs_error(vol->sb, "Failed to merge runlists for mft "
                                        "bitmap.");
                        if (ntfs_cluster_free_from_rl(vol, rl2)) {
-                               ntfs_error(vol->sb, "Failed to dealocate "
+                               ntfs_error(vol->sb, "Failed to deallocate "
                                                "allocated cluster.%s", es);
                                NVolSetErrors(vol);
                        }
@@ -1805,7 +1805,7 @@ static int ntfs_mft_data_extend_allocation_nolock(ntfs_volume *vol)
                ntfs_error(vol->sb, "Failed to merge runlists for mft data "
                                "attribute.");
                if (ntfs_cluster_free_from_rl(vol, rl2)) {
-                       ntfs_error(vol->sb, "Failed to dealocate clusters "
+                       ntfs_error(vol->sb, "Failed to deallocate clusters "
                                        "from the mft data attribute.%s", es);
                        NVolSetErrors(vol);
                }
index 5a4a8af5c406a20e51d57807400a572e3bcbf6bc..f907611cca73c2de10ce7645b8afafb3319cf9fd 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * super.c - NTFS kernel super block handling. Part of the Linux-NTFS project.
  *
- * Copyright (c) 2001-2011 Anton Altaparmakov and Tuxera Inc.
+ * Copyright (c) 2001-2012 Anton Altaparmakov and Tuxera Inc.
  * Copyright (c) 2001,2002 Richard Russon
  *
  * This program/include file is free software; you can redistribute it and/or
@@ -1239,7 +1239,6 @@ static int check_windows_hibernation_status(ntfs_volume *vol)
 {
        MFT_REF mref;
        struct inode *vi;
-       ntfs_inode *ni;
        struct page *page;
        u32 *kaddr, *kend;
        ntfs_name *name = NULL;
@@ -1290,7 +1289,6 @@ static int check_windows_hibernation_status(ntfs_volume *vol)
                                "is not the system volume.", i_size_read(vi));
                goto iput_out;
        }
-       ni = NTFS_I(vi);
        page = ntfs_map_page(vi->i_mapping, 0);
        if (IS_ERR(page)) {
                ntfs_error(vol->sb, "Failed to read from hiberfil.sys.");
index 8a3d4fde26040600f7ddb9d7c3e67a4807b265ff..6afd7d6a9899c49fe721a7bb989c947ea5dc9c75 100644 (file)
@@ -70,7 +70,7 @@ extern void ioport_unmap(void __iomem *);
 /* Destroy a virtual mapping cookie for a PCI BAR (memory or IO) */
 struct pci_dev;
 extern void pci_iounmap(struct pci_dev *dev, void __iomem *);
-#else
+#elif defined(CONFIG_GENERIC_IOMAP)
 struct pci_dev;
 static inline void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
 { }
index e58fcf891370e73996a7fe09b510a7b61d7a9fb8..ce37349860fece8cdf991165db8c8849a677e270 100644 (file)
@@ -25,7 +25,7 @@ extern void __iomem *__pci_ioport_map(struct pci_dev *dev, unsigned long port,
 #define __pci_ioport_map(dev, port, nr) ioport_map((port), (nr))
 #endif
 
-#else
+#elif defined(CONFIG_GENERIC_PCI_IOMAP)
 static inline void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max)
 {
        return NULL;
index a5c0e10fd47d4a93a3bbc49c04bbff4f686b08c9..1e38a19d68f6220d3c89d9f3ffae84b8cbb012a2 100644 (file)
@@ -2,6 +2,7 @@ header-y += drm.h
 header-y += drm_fourcc.h
 header-y += drm_mode.h
 header-y += drm_sarea.h
+header-y += exynos_drm.h
 header-y += i810_drm.h
 header-y += i915_drm.h
 header-y += mga_drm.h
index 5e120f1c5cd927ec154ef1bc5d59ae207f62d92e..1ed3aae893a5b2224554820cdbe3e7c9ad9d6ed4 100644 (file)
@@ -97,15 +97,30 @@ struct drm_exynos_plane_set_zpos {
 #define DRM_IOCTL_EXYNOS_PLANE_SET_ZPOS        DRM_IOWR(DRM_COMMAND_BASE + \
                DRM_EXYNOS_PLANE_SET_ZPOS, struct drm_exynos_plane_set_zpos)
 
+#ifdef __KERNEL__
+
 /**
- * Platform Specific Structure for DRM based FIMD.
+ * A structure for lcd panel information.
  *
  * @timing: default video mode for initializing
+ * @width_mm: physical size of lcd width.
+ * @height_mm: physical size of lcd height.
+ */
+struct exynos_drm_panel_info {
+       struct fb_videomode timing;
+       u32 width_mm;
+       u32 height_mm;
+};
+
+/**
+ * Platform Specific Structure for DRM based FIMD.
+ *
+ * @panel: default panel info for initializing
  * @default_win: default window layer number to be used for UI.
  * @bpp: default bit per pixel.
  */
 struct exynos_drm_fimd_pdata {
-       struct fb_videomode             timing;
+       struct exynos_drm_panel_info panel;
        u32                             vidcon0;
        u32                             vidcon1;
        unsigned int                    default_win;
@@ -139,4 +154,5 @@ struct exynos_drm_hdmi_pdata {
        unsigned int                    bpp;
 };
 
-#endif
+#endif /* __KERNEL__ */
+#endif /* _EXYNOS_DRM_H_ */
index 514ed45c462eaf0516cbdd9f07d3f96bfada4cc7..d117b29d106227b1036520f870b25b9df316c4f3 100644 (file)
@@ -23,6 +23,8 @@
 #ifndef ASM_ARM_HARDWARE_SERIAL_AMBA_H
 #define ASM_ARM_HARDWARE_SERIAL_AMBA_H
 
+#include <linux/types.h>
+
 /* -------------------------------------------------------------------------------
  *  From AMBA UART (PL010) Block Specification
  * -------------------------------------------------------------------------------
index b9f65fbee42f0bdaa8515b46a180817092efda3f..5af9a075498f144fa3c6ea6d86744201a65428b7 100644 (file)
@@ -176,6 +176,12 @@ int __bcma_driver_register(struct bcma_driver *drv, struct module *owner);
 
 extern void bcma_driver_unregister(struct bcma_driver *drv);
 
+/* Set a fallback SPROM.
+ * See kdoc at the function definition for complete documentation. */
+extern int bcma_arch_register_fallback_sprom(
+               int (*sprom_callback)(struct bcma_bus *bus,
+               struct ssb_sprom *out));
+
 struct bcma_bus {
        /* The MMIO area. */
        void __iomem *mmio;
@@ -284,6 +290,7 @@ static inline void bcma_maskset16(struct bcma_device *cc,
        bcma_write16(cc, offset, (bcma_read16(cc, offset) & mask) | set);
 }
 
+extern struct bcma_device *bcma_find_core(struct bcma_bus *bus, u16 coreid);
 extern bool bcma_core_is_enabled(struct bcma_device *core);
 extern void bcma_core_disable(struct bcma_device *core, u32 flags);
 extern int bcma_core_enable(struct bcma_device *core, u32 flags);
index e72938b1071431dcbef56e80d2bbd9fff5bfc228..8bbfe31fbac864db2fa60e9edeef149097d3a32e 100644 (file)
@@ -56,6 +56,9 @@
 #define         BCMA_CC_OTPS_HW_PROTECT        0x00000001
 #define         BCMA_CC_OTPS_SW_PROTECT        0x00000002
 #define         BCMA_CC_OTPS_CID_PROTECT       0x00000004
+#define  BCMA_CC_OTPS_GU_PROG_IND      0x00000F00      /* General Use programmed indication */
+#define  BCMA_CC_OTPS_GU_PROG_IND_SHIFT        8
+#define  BCMA_CC_OTPS_GU_PROG_HW       0x00000100      /* HW region programmed */
 #define BCMA_CC_OTPC                   0x0014          /* OTP control */
 #define         BCMA_CC_OTPC_RECWAIT           0xFF000000
 #define         BCMA_CC_OTPC_PROGWAIT          0x00FFFF00
@@ -72,6 +75,8 @@
 #define         BCMA_CC_OTPP_READ              0x40000000
 #define         BCMA_CC_OTPP_START             0x80000000
 #define         BCMA_CC_OTPP_BUSY              0x80000000
+#define BCMA_CC_OTPL                   0x001C          /* OTP layout */
+#define  BCMA_CC_OTPL_GURGN_OFFSET     0x00000FFF      /* offset of general use region */
 #define BCMA_CC_IRQSTAT                        0x0020
 #define BCMA_CC_IRQMASK                        0x0024
 #define         BCMA_CC_IRQ_GPIO               0x00000001      /* gpio intr */
 #define         BCMA_CC_IRQ_WDRESET            0x80000000      /* watchdog reset occurred */
 #define BCMA_CC_CHIPCTL                        0x0028          /* Rev >= 11 only */
 #define BCMA_CC_CHIPSTAT               0x002C          /* Rev >= 11 only */
+#define  BCMA_CC_CHIPST_4313_SPROM_PRESENT     1
+#define  BCMA_CC_CHIPST_4313_OTP_PRESENT       2
+#define  BCMA_CC_CHIPST_4331_SPROM_PRESENT     2
+#define  BCMA_CC_CHIPST_4331_OTP_PRESENT       4
 #define BCMA_CC_JCMD                   0x0030          /* Rev >= 10 only */
 #define  BCMA_CC_JCMD_START            0x80000000
 #define  BCMA_CC_JCMD_BUSY             0x80000000
 #define BCMA_CC_PLLCTL_ADDR            0x0660
 #define BCMA_CC_PLLCTL_DATA            0x0664
 #define BCMA_CC_SPROM                  0x0800 /* SPROM beginning */
-#define BCMA_CC_SPROM_PCIE6            0x0830 /* SPROM beginning on PCIe rev >= 6 */
 
 /* Divider allocation in 4716/47162/5356 */
 #define BCMA_CC_PMU5_MAINPLL_CPU       1
index d64a55b23afda64f4b490ef475e092edcf3c32b7..ff5f5256d175c8dde1345394f8fedd4e701b03e0 100644 (file)
@@ -47,27 +47,6 @@ struct dentry_stat_t {
 };
 extern struct dentry_stat_t dentry_stat;
 
-/*
- * Compare 2 name strings, return 0 if they match, otherwise non-zero.
- * The strings are both count bytes long, and count is non-zero.
- */
-static inline int dentry_cmp(const unsigned char *cs, size_t scount,
-                               const unsigned char *ct, size_t tcount)
-{
-       int ret;
-       if (scount != tcount)
-               return 1;
-       do {
-               ret = (*cs != *ct);
-               if (ret)
-                       break;
-               cs++;
-               ct++;
-               tcount--;
-       } while (tcount);
-       return ret;
-}
-
 /* Name hashing routines. Initial hash value */
 /* Hash courtesy of the R5 hash in reiserfs modulo sign bits */
 #define init_name_hash()               0
@@ -89,14 +68,7 @@ static inline unsigned long end_name_hash(unsigned long hash)
 }
 
 /* Compute the hash for a name string. */
-static inline unsigned int
-full_name_hash(const unsigned char *name, unsigned int len)
-{
-       unsigned long hash = init_name_hash();
-       while (len--)
-               hash = partial_name_hash(*name++, hash);
-       return end_name_hash(hash);
-}
+extern unsigned int full_name_hash(const unsigned char *, unsigned int);
 
 /*
  * Try to keep struct dentry aligned on 64 byte cachelines (this will
@@ -309,7 +281,8 @@ extern struct dentry *d_ancestor(struct dentry *, struct dentry *);
 extern struct dentry *d_lookup(struct dentry *, struct qstr *);
 extern struct dentry *d_hash_and_lookup(struct dentry *, struct qstr *);
 extern struct dentry *__d_lookup(struct dentry *, struct qstr *);
-extern struct dentry *__d_lookup_rcu(struct dentry *parent, struct qstr *name,
+extern struct dentry *__d_lookup_rcu(const struct dentry *parent,
+                               const struct qstr *name,
                                unsigned *seq, struct inode **inode);
 
 /**
index fee66317e071547a4a75e0b90b61399b97249ed2..35f7237ec972bef4ce1ba24cd617571a193ce806 100644 (file)
 #include <linux/errno.h>
 #include <linux/list.h>
 
+/*
+ * Keep this list arranged in rough order of priority. Anything listed after
+ * KMSG_DUMP_OOPS will not be logged by default unless printk.always_kmsg_dump
+ * is passed to the kernel.
+ */
 enum kmsg_dump_reason {
-       KMSG_DUMP_OOPS,
        KMSG_DUMP_PANIC,
+       KMSG_DUMP_OOPS,
+       KMSG_DUMP_EMERG,
        KMSG_DUMP_RESTART,
        KMSG_DUMP_HALT,
        KMSG_DUMP_POWEROFF,
-       KMSG_DUMP_EMERG,
 };
 
 /**
index 4d34356fe644ee5dca447071829ae06ab68eeb60..b80de520670b64a67dc2ceb8b4e4e11c1d623071 100644 (file)
@@ -129,7 +129,6 @@ extern void mem_cgroup_print_oom_info(struct mem_cgroup *memcg,
 extern void mem_cgroup_replace_page_cache(struct page *oldpage,
                                        struct page *newpage);
 
-extern void mem_cgroup_reset_owner(struct page *page);
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
 extern int do_swap_account;
 #endif
@@ -392,10 +391,6 @@ static inline void mem_cgroup_replace_page_cache(struct page *oldpage,
                                struct page *newpage)
 {
 }
-
-static inline void mem_cgroup_reset_owner(struct page *page)
-{
-}
 #endif /* CONFIG_CGROUP_MEM_CONT */
 
 #if !defined(CONFIG_CGROUP_MEM_RES_CTLR) || !defined(CONFIG_DEBUG_VM)
index aea61905499b0e20598969cb02e63f32a3010d2d..44d8144e9ae8e1ad7ba7742197001f121719d263 100644 (file)
@@ -622,7 +622,10 @@ int mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac);
 int mlx4_get_eth_qp(struct mlx4_dev *dev, u8 port, u64 mac, int *qpn);
 void mlx4_put_eth_qp(struct mlx4_dev *dev, u8 port, u64 mac, int qpn);
 void mlx4_set_stats_bitmap(struct mlx4_dev *dev, u64 *stats_bitmap);
-
+int mlx4_SET_PORT_general(struct mlx4_dev *dev, u8 port, int mtu,
+                         u8 pptx, u8 pfctx, u8 pprx, u8 pfcrx);
+int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn,
+                          u8 promisc);
 int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx);
 int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index);
 void mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, int index);
index f1b7d037c2c5eb2580a5489b6331b136741de6a7..b195a34440bbbee8441304616efd80921ff89cd2 100644 (file)
@@ -417,7 +417,7 @@ typedef rx_handler_result_t rx_handler_func_t(struct sk_buff **pskb);
 
 extern void __napi_schedule(struct napi_struct *n);
 
-static inline int napi_disable_pending(struct napi_struct *n)
+static inline bool napi_disable_pending(struct napi_struct *n)
 {
        return test_bit(NAPI_STATE_DISABLE, &n->state);
 }
@@ -431,7 +431,7 @@ static inline int napi_disable_pending(struct napi_struct *n)
  * insure only one NAPI poll instance runs.  We also make
  * sure there is no pending NAPI disable.
  */
-static inline int napi_schedule_prep(struct napi_struct *n)
+static inline bool napi_schedule_prep(struct napi_struct *n)
 {
        return !napi_disable_pending(n) &&
                !test_and_set_bit(NAPI_STATE_SCHED, &n->state);
@@ -451,13 +451,13 @@ static inline void napi_schedule(struct napi_struct *n)
 }
 
 /* Try to reschedule poll. Called by dev->poll() after napi_complete().  */
-static inline int napi_reschedule(struct napi_struct *napi)
+static inline bool napi_reschedule(struct napi_struct *napi)
 {
        if (napi_schedule_prep(napi)) {
                __napi_schedule(napi);
-               return 1;
+               return true;
        }
-       return 0;
+       return false;
 }
 
 /**
@@ -1868,7 +1868,7 @@ static inline void netif_tx_stop_all_queues(struct net_device *dev)
        }
 }
 
-static inline int netif_tx_queue_stopped(const struct netdev_queue *dev_queue)
+static inline bool netif_tx_queue_stopped(const struct netdev_queue *dev_queue)
 {
        return test_bit(__QUEUE_STATE_DRV_XOFF, &dev_queue->state);
 }
@@ -1879,17 +1879,17 @@ static inline int netif_tx_queue_stopped(const struct netdev_queue *dev_queue)
  *
  *     Test if transmit queue on device is currently unable to send.
  */
-static inline int netif_queue_stopped(const struct net_device *dev)
+static inline bool netif_queue_stopped(const struct net_device *dev)
 {
        return netif_tx_queue_stopped(netdev_get_tx_queue(dev, 0));
 }
 
-static inline int netif_xmit_stopped(const struct netdev_queue *dev_queue)
+static inline bool netif_xmit_stopped(const struct netdev_queue *dev_queue)
 {
        return dev_queue->state & QUEUE_STATE_ANY_XOFF;
 }
 
-static inline int netif_xmit_frozen_or_stopped(const struct netdev_queue *dev_queue)
+static inline bool netif_xmit_frozen_or_stopped(const struct netdev_queue *dev_queue)
 {
        return dev_queue->state & QUEUE_STATE_ANY_XOFF_OR_FROZEN;
 }
@@ -1954,7 +1954,7 @@ static inline void netdev_reset_queue(struct net_device *dev_queue)
  *
  *     Test if the device has been brought up.
  */
-static inline int netif_running(const struct net_device *dev)
+static inline bool netif_running(const struct net_device *dev)
 {
        return test_bit(__LINK_STATE_START, &dev->state);
 }
@@ -2004,16 +2004,16 @@ static inline void netif_stop_subqueue(struct net_device *dev, u16 queue_index)
  *
  * Check individual transmit queue of a device with multiple transmit queues.
  */
-static inline int __netif_subqueue_stopped(const struct net_device *dev,
-                                        u16 queue_index)
+static inline bool __netif_subqueue_stopped(const struct net_device *dev,
+                                           u16 queue_index)
 {
        struct netdev_queue *txq = netdev_get_tx_queue(dev, queue_index);
 
        return netif_tx_queue_stopped(txq);
 }
 
-static inline int netif_subqueue_stopped(const struct net_device *dev,
-                                        struct sk_buff *skb)
+static inline bool netif_subqueue_stopped(const struct net_device *dev,
+                                         struct sk_buff *skb)
 {
        return __netif_subqueue_stopped(dev, skb_get_queue_mapping(skb));
 }
@@ -2052,7 +2052,7 @@ static inline u16 skb_tx_hash(const struct net_device *dev,
  *
  * Check if device has multiple transmit queues
  */
-static inline int netif_is_multiqueue(const struct net_device *dev)
+static inline bool netif_is_multiqueue(const struct net_device *dev)
 {
        return dev->num_tx_queues > 1;
 }
@@ -2122,7 +2122,7 @@ extern int netdev_rx_handler_register(struct net_device *dev,
                                      void *rx_handler_data);
 extern void netdev_rx_handler_unregister(struct net_device *dev);
 
-extern int             dev_valid_name(const char *name);
+extern bool            dev_valid_name(const char *name);
 extern int             dev_ioctl(struct net *net, unsigned int cmd, void __user *);
 extern int             dev_ethtool(struct net *net, struct ifreq *);
 extern unsigned                dev_get_flags(const struct net_device *);
@@ -2188,7 +2188,7 @@ extern void linkwatch_forget_dev(struct net_device *dev);
  *
  * Check if carrier is present on device
  */
-static inline int netif_carrier_ok(const struct net_device *dev)
+static inline bool netif_carrier_ok(const struct net_device *dev)
 {
        return !test_bit(__LINK_STATE_NOCARRIER, &dev->state);
 }
@@ -2240,7 +2240,7 @@ static inline void netif_dormant_off(struct net_device *dev)
  *
  * Check if carrier is present on device
  */
-static inline int netif_dormant(const struct net_device *dev)
+static inline bool netif_dormant(const struct net_device *dev)
 {
        return test_bit(__LINK_STATE_DORMANT, &dev->state);
 }
@@ -2252,7 +2252,7 @@ static inline int netif_dormant(const struct net_device *dev)
  *
  * Check if carrier is operational
  */
-static inline int netif_oper_up(const struct net_device *dev)
+static inline bool netif_oper_up(const struct net_device *dev)
 {
        return (dev->operstate == IF_OPER_UP ||
                dev->operstate == IF_OPER_UNKNOWN /* backward compat */);
@@ -2264,7 +2264,7 @@ static inline int netif_oper_up(const struct net_device *dev)
  *
  * Check if device has not been removed from system.
  */
-static inline int netif_device_present(struct net_device *dev)
+static inline bool netif_device_present(struct net_device *dev)
 {
        return test_bit(__LINK_STATE_PRESENT, &dev->state);
 }
@@ -2334,9 +2334,9 @@ static inline void __netif_tx_lock_bh(struct netdev_queue *txq)
        txq->xmit_lock_owner = smp_processor_id();
 }
 
-static inline int __netif_tx_trylock(struct netdev_queue *txq)
+static inline bool __netif_tx_trylock(struct netdev_queue *txq)
 {
-       int ok = spin_trylock(&txq->_xmit_lock);
+       bool ok = spin_trylock(&txq->_xmit_lock);
        if (likely(ok))
                txq->xmit_lock_owner = smp_processor_id();
        return ok;
@@ -2557,6 +2557,8 @@ extern void               dev_load(struct net *net, const char *name);
 extern void            dev_mcast_init(void);
 extern struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev,
                                               struct rtnl_link_stats64 *storage);
+extern void netdev_stats_to_stats64(struct rtnl_link_stats64 *stats64,
+                                   const struct net_device_stats *netdev_stats);
 
 extern int             netdev_max_backlog;
 extern int             netdev_tstamp_prequeue;
@@ -2612,7 +2614,7 @@ void netif_stacked_transfer_operstate(const struct net_device *rootdev,
 
 netdev_features_t netif_skb_features(struct sk_buff *skb);
 
-static inline int net_gso_ok(netdev_features_t features, int gso_type)
+static inline bool net_gso_ok(netdev_features_t features, int gso_type)
 {
        netdev_features_t feature = gso_type << NETIF_F_GSO_SHIFT;
 
@@ -2627,14 +2629,14 @@ static inline int net_gso_ok(netdev_features_t features, int gso_type)
        return (features & feature) == feature;
 }
 
-static inline int skb_gso_ok(struct sk_buff *skb, netdev_features_t features)
+static inline bool 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,
-       netdev_features_t features)
+static inline bool 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));
@@ -2646,7 +2648,7 @@ static inline void netif_set_gso_max_size(struct net_device *dev,
        dev->gso_max_size = size;
 }
 
-static inline int netif_is_bond_slave(struct net_device *dev)
+static inline bool netif_is_bond_slave(struct net_device *dev)
 {
        return dev->flags & IFF_SLAVE && dev->priv_flags & IFF_BONDING;
 }
index e144f54185c019a01d2210791e54f1feb12b1586..1697036336b6623a474212ebf8e4eeda4d4dc752 100644 (file)
@@ -10,6 +10,7 @@ header-y += nfnetlink.h
 header-y += nfnetlink_acct.h
 header-y += nfnetlink_compat.h
 header-y += nfnetlink_conntrack.h
+header-y += nfnetlink_cttimeout.h
 header-y += nfnetlink_log.h
 header-y += nfnetlink_queue.h
 header-y += x_tables.h
@@ -22,6 +23,7 @@ header-y += xt_CT.h
 header-y += xt_DSCP.h
 header-y += xt_IDLETIMER.h
 header-y += xt_LED.h
+header-y += xt_LOG.h
 header-y += xt_MARK.h
 header-y += xt_nfacct.h
 header-y += xt_NFLOG.h
index 3540c6e262f7b1288c31e32b0769d40a90e9b1e3..2f8e18a232273faa679a1d7ee60944b292f16de6 100644 (file)
@@ -11,6 +11,8 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/types.h>
+
 /* The protocol version */
 #define IPSET_PROTOCOL         6
 
@@ -148,6 +150,7 @@ enum ipset_cmd_flags {
        IPSET_FLAG_LIST_SETNAME = (1 << IPSET_FLAG_BIT_LIST_SETNAME),
        IPSET_FLAG_BIT_LIST_HEADER = 2,
        IPSET_FLAG_LIST_HEADER  = (1 << IPSET_FLAG_BIT_LIST_HEADER),
+       IPSET_FLAG_CMD_MAX = 15,        /* Lower half */
 };
 
 /* Flags at CADT attribute level */
@@ -156,6 +159,9 @@ enum ipset_cadt_flags {
        IPSET_FLAG_BEFORE       = (1 << IPSET_FLAG_BIT_BEFORE),
        IPSET_FLAG_BIT_PHYSDEV  = 1,
        IPSET_FLAG_PHYSDEV      = (1 << IPSET_FLAG_BIT_PHYSDEV),
+       IPSET_FLAG_BIT_NOMATCH  = 2,
+       IPSET_FLAG_NOMATCH      = (1 << IPSET_FLAG_BIT_NOMATCH),
+       IPSET_FLAG_CADT_MAX     = 15,   /* Upper half */
 };
 
 /* Commands with settype-specific attributes */
@@ -168,19 +174,10 @@ enum ipset_adt {
        IPSET_CADT_MAX,
 };
 
-#ifdef __KERNEL__
-#include <linux/ip.h>
-#include <linux/ipv6.h>
-#include <linux/netlink.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter/x_tables.h>
-#include <linux/vmalloc.h>
-#include <net/netlink.h>
-
 /* Sets are identified by an index in kernel space. Tweak with ip_set_id_t
  * and IPSET_INVALID_ID if you want to increase the max number of sets.
  */
-typedef u16 ip_set_id_t;
+typedef __u16 ip_set_id_t;
 
 #define IPSET_INVALID_ID               65535
 
@@ -203,6 +200,15 @@ enum ip_set_kopt {
        IPSET_DIM_THREE_SRC = (1 << IPSET_DIM_THREE),
 };
 
+#ifdef __KERNEL__
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/netlink.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/vmalloc.h>
+#include <net/netlink.h>
+
 /* Set features */
 enum ip_set_feature {
        IPSET_TYPE_IP_FLAG = 0,
@@ -288,7 +294,10 @@ struct ip_set_type {
        u8 features;
        /* Set type dimension */
        u8 dimension;
-       /* Supported family: may be AF_UNSPEC for both AF_INET/AF_INET6 */
+       /*
+        * Supported family: may be NFPROTO_UNSPEC for both
+        * NFPROTO_IPV4/NFPROTO_IPV6.
+        */
        u8 family;
        /* Type revisions */
        u8 revision_min, revision_max;
@@ -450,6 +459,8 @@ bitmap_bytes(u32 a, u32 b)
        return 4 * ((((b - a + 8) / 8) + 3) / 4);
 }
 
+#endif /* __KERNEL__ */
+
 /* Interface to iptables/ip6tables */
 
 #define SO_IP_SET              83
@@ -475,6 +486,4 @@ struct ip_set_req_version {
        unsigned version;
 };
 
-#endif /* __KERNEL__ */
-
 #endif /*_IP_SET_H */
index b89fb79cb44fb9ed819c192776b525b243b8f895..05a5d72680bed904c23687a69e43a7759bc61848 100644 (file)
@@ -113,6 +113,12 @@ htable_bits(u32 hashsize)
 }
 
 #ifdef IP_SET_HASH_WITH_NETS
+#ifdef IP_SET_HASH_WITH_NETS_PACKED
+/* When cidr is packed with nomatch, cidr - 1 is stored in the entry */
+#define CIDR(cidr)     (cidr + 1)
+#else
+#define CIDR(cidr)     (cidr)
+#endif
 
 #define SET_HOST_MASK(family)  (family == AF_INET ? 32 : 128)
 
@@ -262,6 +268,12 @@ ip_set_hash_destroy(struct ip_set *set)
 #define type_pf_data_list      TOKEN(TYPE, PF, _data_list)
 #define type_pf_data_tlist     TOKEN(TYPE, PF, _data_tlist)
 #define type_pf_data_next      TOKEN(TYPE, PF, _data_next)
+#define type_pf_data_flags     TOKEN(TYPE, PF, _data_flags)
+#ifdef IP_SET_HASH_WITH_NETS
+#define type_pf_data_match     TOKEN(TYPE, PF, _data_match)
+#else
+#define type_pf_data_match(d)  1
+#endif
 
 #define type_pf_elem           TOKEN(TYPE, PF, _elem)
 #define type_pf_telem          TOKEN(TYPE, PF, _telem)
@@ -308,8 +320,10 @@ ip_set_hash_destroy(struct ip_set *set)
  * we spare the maintenance of the internal counters. */
 static int
 type_pf_elem_add(struct hbucket *n, const struct type_pf_elem *value,
-                u8 ahash_max)
+                u8 ahash_max, u32 cadt_flags)
 {
+       struct type_pf_elem *data;
+
        if (n->pos >= n->size) {
                void *tmp;
 
@@ -330,7 +344,13 @@ type_pf_elem_add(struct hbucket *n, const struct type_pf_elem *value,
                n->value = tmp;
                n->size += AHASH_INIT_SIZE;
        }
-       type_pf_data_copy(ahash_data(n, n->pos++), value);
+       data = ahash_data(n, n->pos++);
+       type_pf_data_copy(data, value);
+#ifdef IP_SET_HASH_WITH_NETS
+       /* Resizing won't overwrite stored flags */
+       if (cadt_flags)
+               type_pf_data_flags(data, cadt_flags);
+#endif
        return 0;
 }
 
@@ -353,9 +373,12 @@ retry:
        htable_bits++;
        pr_debug("attempt to resize set %s from %u to %u, t %p\n",
                 set->name, orig->htable_bits, htable_bits, orig);
-       if (!htable_bits)
+       if (!htable_bits) {
                /* In case we have plenty of memory :-) */
+               pr_warning("Cannot increase the hashsize of set %s further\n",
+                          set->name);
                return -IPSET_ERR_HASH_FULL;
+       }
        t = ip_set_alloc(sizeof(*t)
                         + jhash_size(htable_bits) * sizeof(struct hbucket));
        if (!t)
@@ -368,7 +391,7 @@ retry:
                for (j = 0; j < n->pos; j++) {
                        data = ahash_data(n, j);
                        m = hbucket(t, HKEY(data, h->initval, htable_bits));
-                       ret = type_pf_elem_add(m, data, AHASH_MAX(h));
+                       ret = type_pf_elem_add(m, data, AHASH_MAX(h), 0);
                        if (ret < 0) {
                                read_unlock_bh(&set->lock);
                                ahash_destroy(t);
@@ -406,9 +429,14 @@ type_pf_add(struct ip_set *set, void *value, u32 timeout, u32 flags)
        struct hbucket *n;
        int i, ret = 0;
        u32 key, multi = 0;
+       u32 cadt_flags = flags >> 16;
 
-       if (h->elements >= h->maxelem)
+       if (h->elements >= h->maxelem) {
+               if (net_ratelimit())
+                       pr_warning("Set %s is full, maxelem %u reached\n",
+                                  set->name, h->maxelem);
                return -IPSET_ERR_HASH_FULL;
+       }
 
        rcu_read_lock_bh();
        t = rcu_dereference_bh(h->table);
@@ -416,11 +444,17 @@ type_pf_add(struct ip_set *set, void *value, u32 timeout, u32 flags)
        n = hbucket(t, key);
        for (i = 0; i < n->pos; i++)
                if (type_pf_data_equal(ahash_data(n, i), d, &multi)) {
+#ifdef IP_SET_HASH_WITH_NETS
+                       if (flags & IPSET_FLAG_EXIST)
+                               /* Support overwriting just the flags */
+                               type_pf_data_flags(ahash_data(n, i),
+                                                  cadt_flags);
+#endif
                        ret = -IPSET_ERR_EXIST;
                        goto out;
                }
        TUNE_AHASH_MAX(h, multi);
-       ret = type_pf_elem_add(n, value, AHASH_MAX(h));
+       ret = type_pf_elem_add(n, value, AHASH_MAX(h), cadt_flags);
        if (ret != 0) {
                if (ret == -EAGAIN)
                        type_pf_data_next(h, d);
@@ -428,7 +462,7 @@ type_pf_add(struct ip_set *set, void *value, u32 timeout, u32 flags)
        }
 
 #ifdef IP_SET_HASH_WITH_NETS
-       add_cidr(h, d->cidr, HOST_MASK);
+       add_cidr(h, CIDR(d->cidr), HOST_MASK);
 #endif
        h->elements++;
 out:
@@ -463,7 +497,7 @@ type_pf_del(struct ip_set *set, void *value, u32 timeout, u32 flags)
                n->pos--;
                h->elements--;
 #ifdef IP_SET_HASH_WITH_NETS
-               del_cidr(h, d->cidr, HOST_MASK);
+               del_cidr(h, CIDR(d->cidr), HOST_MASK);
 #endif
                if (n->pos + AHASH_INIT_SIZE < n->size) {
                        void *tmp = kzalloc((n->size - AHASH_INIT_SIZE)
@@ -506,7 +540,7 @@ type_pf_test_cidrs(struct ip_set *set, struct type_pf_elem *d, u32 timeout)
                for (i = 0; i < n->pos; i++) {
                        data = ahash_data(n, i);
                        if (type_pf_data_equal(data, d, &multi))
-                               return 1;
+                               return type_pf_data_match(data);
                }
        }
        return 0;
@@ -528,7 +562,7 @@ type_pf_test(struct ip_set *set, void *value, u32 timeout, u32 flags)
 #ifdef IP_SET_HASH_WITH_NETS
        /* If we test an IP address and not a network address,
         * try all possible network sizes */
-       if (d->cidr == SET_HOST_MASK(set->family))
+       if (CIDR(d->cidr) == SET_HOST_MASK(set->family))
                return type_pf_test_cidrs(set, d, timeout);
 #endif
 
@@ -537,7 +571,7 @@ type_pf_test(struct ip_set *set, void *value, u32 timeout, u32 flags)
        for (i = 0; i < n->pos; i++) {
                data = ahash_data(n, i);
                if (type_pf_data_equal(data, d, &multi))
-                       return 1;
+                       return type_pf_data_match(data);
        }
        return 0;
 }
@@ -693,7 +727,7 @@ type_pf_data_timeout_set(struct type_pf_elem *data, u32 timeout)
 
 static int
 type_pf_elem_tadd(struct hbucket *n, const struct type_pf_elem *value,
-                 u8 ahash_max, u32 timeout)
+                 u8 ahash_max, u32 cadt_flags, u32 timeout)
 {
        struct type_pf_elem *data;
 
@@ -720,6 +754,11 @@ type_pf_elem_tadd(struct hbucket *n, const struct type_pf_elem *value,
        data = ahash_tdata(n, n->pos++);
        type_pf_data_copy(data, value);
        type_pf_data_timeout_set(data, timeout);
+#ifdef IP_SET_HASH_WITH_NETS
+       /* Resizing won't overwrite stored flags */
+       if (cadt_flags)
+               type_pf_data_flags(data, cadt_flags);
+#endif
        return 0;
 }
 
@@ -740,7 +779,7 @@ type_pf_expire(struct ip_set_hash *h)
                        if (type_pf_data_expired(data)) {
                                pr_debug("expired %u/%u\n", i, j);
 #ifdef IP_SET_HASH_WITH_NETS
-                               del_cidr(h, data->cidr, HOST_MASK);
+                               del_cidr(h, CIDR(data->cidr), HOST_MASK);
 #endif
                                if (j != n->pos - 1)
                                        /* Not last one */
@@ -790,9 +829,12 @@ type_pf_tresize(struct ip_set *set, bool retried)
 retry:
        ret = 0;
        htable_bits++;
-       if (!htable_bits)
+       if (!htable_bits) {
                /* In case we have plenty of memory :-) */
+               pr_warning("Cannot increase the hashsize of set %s further\n",
+                          set->name);
                return -IPSET_ERR_HASH_FULL;
+       }
        t = ip_set_alloc(sizeof(*t)
                         + jhash_size(htable_bits) * sizeof(struct hbucket));
        if (!t)
@@ -805,7 +847,7 @@ retry:
                for (j = 0; j < n->pos; j++) {
                        data = ahash_tdata(n, j);
                        m = hbucket(t, HKEY(data, h->initval, htable_bits));
-                       ret = type_pf_elem_tadd(m, data, AHASH_MAX(h),
+                       ret = type_pf_elem_tadd(m, data, AHASH_MAX(h), 0,
                                                type_pf_data_timeout(data));
                        if (ret < 0) {
                                read_unlock_bh(&set->lock);
@@ -839,12 +881,17 @@ type_pf_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)
        int ret = 0, i, j = AHASH_MAX(h) + 1;
        bool flag_exist = flags & IPSET_FLAG_EXIST;
        u32 key, multi = 0;
+       u32 cadt_flags = flags >> 16;
 
        if (h->elements >= h->maxelem)
                /* FIXME: when set is full, we slow down here */
                type_pf_expire(h);
-       if (h->elements >= h->maxelem)
+       if (h->elements >= h->maxelem) {
+               if (net_ratelimit())
+                       pr_warning("Set %s is full, maxelem %u reached\n",
+                                  set->name, h->maxelem);
                return -IPSET_ERR_HASH_FULL;
+       }
 
        rcu_read_lock_bh();
        t = rcu_dereference_bh(h->table);
@@ -854,6 +901,7 @@ type_pf_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)
                data = ahash_tdata(n, i);
                if (type_pf_data_equal(data, d, &multi)) {
                        if (type_pf_data_expired(data) || flag_exist)
+                               /* Just timeout value may be updated */
                                j = i;
                        else {
                                ret = -IPSET_ERR_EXIST;
@@ -866,15 +914,18 @@ type_pf_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)
        if (j != AHASH_MAX(h) + 1) {
                data = ahash_tdata(n, j);
 #ifdef IP_SET_HASH_WITH_NETS
-               del_cidr(h, data->cidr, HOST_MASK);
-               add_cidr(h, d->cidr, HOST_MASK);
+               del_cidr(h, CIDR(data->cidr), HOST_MASK);
+               add_cidr(h, CIDR(d->cidr), HOST_MASK);
 #endif
                type_pf_data_copy(data, d);
                type_pf_data_timeout_set(data, timeout);
+#ifdef IP_SET_HASH_WITH_NETS
+               type_pf_data_flags(data, cadt_flags);
+#endif
                goto out;
        }
        TUNE_AHASH_MAX(h, multi);
-       ret = type_pf_elem_tadd(n, d, AHASH_MAX(h), timeout);
+       ret = type_pf_elem_tadd(n, d, AHASH_MAX(h), cadt_flags, timeout);
        if (ret != 0) {
                if (ret == -EAGAIN)
                        type_pf_data_next(h, d);
@@ -882,7 +933,7 @@ type_pf_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)
        }
 
 #ifdef IP_SET_HASH_WITH_NETS
-       add_cidr(h, d->cidr, HOST_MASK);
+       add_cidr(h, CIDR(d->cidr), HOST_MASK);
 #endif
        h->elements++;
 out:
@@ -916,7 +967,7 @@ type_pf_tdel(struct ip_set *set, void *value, u32 timeout, u32 flags)
                n->pos--;
                h->elements--;
 #ifdef IP_SET_HASH_WITH_NETS
-               del_cidr(h, d->cidr, HOST_MASK);
+               del_cidr(h, CIDR(d->cidr), HOST_MASK);
 #endif
                if (n->pos + AHASH_INIT_SIZE < n->size) {
                        void *tmp = kzalloc((n->size - AHASH_INIT_SIZE)
@@ -954,8 +1005,17 @@ type_pf_ttest_cidrs(struct ip_set *set, struct type_pf_elem *d, u32 timeout)
                n = hbucket(t, key);
                for (i = 0; i < n->pos; i++) {
                        data = ahash_tdata(n, i);
-                       if (type_pf_data_equal(data, d, &multi))
-                               return !type_pf_data_expired(data);
+#ifdef IP_SET_HASH_WITH_MULTI
+                       if (type_pf_data_equal(data, d, &multi)) {
+                               if (!type_pf_data_expired(data))
+                                       return type_pf_data_match(data);
+                               multi = 0;
+                       }
+#else
+                       if (type_pf_data_equal(data, d, &multi) &&
+                           !type_pf_data_expired(data))
+                               return type_pf_data_match(data);
+#endif
                }
        }
        return 0;
@@ -973,15 +1033,16 @@ type_pf_ttest(struct ip_set *set, void *value, u32 timeout, u32 flags)
        u32 key, multi = 0;
 
 #ifdef IP_SET_HASH_WITH_NETS
-       if (d->cidr == SET_HOST_MASK(set->family))
+       if (CIDR(d->cidr) == SET_HOST_MASK(set->family))
                return type_pf_ttest_cidrs(set, d, timeout);
 #endif
        key = HKEY(d, h->initval, t->htable_bits);
        n = hbucket(t, key);
        for (i = 0; i < n->pos; i++) {
                data = ahash_tdata(n, i);
-               if (type_pf_data_equal(data, d, &multi))
-                       return !type_pf_data_expired(data);
+               if (type_pf_data_equal(data, d, &multi) &&
+                   !type_pf_data_expired(data))
+                       return type_pf_data_match(data);
        }
        return 0;
 }
@@ -1094,14 +1155,17 @@ type_pf_gc_init(struct ip_set *set)
 #undef type_pf_data_isnull
 #undef type_pf_data_copy
 #undef type_pf_data_zero_out
+#undef type_pf_data_netmask
 #undef type_pf_data_list
 #undef type_pf_data_tlist
+#undef type_pf_data_next
+#undef type_pf_data_flags
+#undef type_pf_data_match
 
 #undef type_pf_elem
 #undef type_pf_telem
 #undef type_pf_data_timeout
 #undef type_pf_data_expired
-#undef type_pf_data_netmask
 #undef type_pf_data_timeout_set
 
 #undef type_pf_elem_add
@@ -1111,6 +1175,7 @@ type_pf_gc_init(struct ip_set *set)
 #undef type_pf_test
 
 #undef type_pf_elem_tadd
+#undef type_pf_del_telem
 #undef type_pf_expire
 #undef type_pf_tadd
 #undef type_pf_tdel
index 6e135f97e59a6eee9e0854ddc6c0db35a2ca01e4..e59868ae12d42114df83e28f3712bd28de1a4564 100644 (file)
@@ -18,7 +18,10 @@ enum tcp_conntrack {
        TCP_CONNTRACK_LISTEN,   /* obsolete */
 #define TCP_CONNTRACK_SYN_SENT2        TCP_CONNTRACK_LISTEN
        TCP_CONNTRACK_MAX,
-       TCP_CONNTRACK_IGNORE
+       TCP_CONNTRACK_IGNORE,
+       TCP_CONNTRACK_RETRANS,
+       TCP_CONNTRACK_UNACK,
+       TCP_CONNTRACK_TIMEOUT_MAX
 };
 
 /* Window scaling is advertised by the sender */
index b64454c2f79f67aad7d18d4ff3168cbed7867b3e..6fd1f0d07e64436a25863880e5d4ba239bc54bb5 100644 (file)
@@ -49,7 +49,8 @@ struct nfgenmsg {
 #define NFNL_SUBSYS_OSF                        5
 #define NFNL_SUBSYS_IPSET              6
 #define NFNL_SUBSYS_ACCT               7
-#define NFNL_SUBSYS_COUNT              8
+#define NFNL_SUBSYS_CTNETLINK_TIMEOUT  8
+#define NFNL_SUBSYS_COUNT              9
 
 #ifdef __KERNEL__
 
index d498a4426ebfdd9002712b622cfc62b823fa6644..e58e4b93c10813c4959c59e81349b2432c0d722e 100644 (file)
@@ -173,10 +173,21 @@ enum ctattr_expect {
        CTA_EXPECT_HELP_NAME,
        CTA_EXPECT_ZONE,
        CTA_EXPECT_FLAGS,
+       CTA_EXPECT_CLASS,
+       CTA_EXPECT_NAT,
+       CTA_EXPECT_FN,
        __CTA_EXPECT_MAX
 };
 #define CTA_EXPECT_MAX (__CTA_EXPECT_MAX - 1)
 
+enum ctattr_expect_nat {
+       CTA_EXPECT_NAT_UNSPEC,
+       CTA_EXPECT_NAT_DIR,
+       CTA_EXPECT_NAT_TUPLE,
+       __CTA_EXPECT_NAT_MAX
+};
+#define CTA_EXPECT_NAT_MAX (__CTA_EXPECT_NAT_MAX - 1)
+
 enum ctattr_help {
        CTA_HELP_UNSPEC,
        CTA_HELP_NAME,
diff --git a/include/linux/netfilter/nfnetlink_cttimeout.h b/include/linux/netfilter/nfnetlink_cttimeout.h
new file mode 100644 (file)
index 0000000..a2810a7
--- /dev/null
@@ -0,0 +1,114 @@
+#ifndef _CTTIMEOUT_NETLINK_H
+#define _CTTIMEOUT_NETLINK_H
+#include <linux/netfilter/nfnetlink.h>
+
+enum ctnl_timeout_msg_types {
+       IPCTNL_MSG_TIMEOUT_NEW,
+       IPCTNL_MSG_TIMEOUT_GET,
+       IPCTNL_MSG_TIMEOUT_DELETE,
+
+       IPCTNL_MSG_TIMEOUT_MAX
+};
+
+enum ctattr_timeout {
+       CTA_TIMEOUT_UNSPEC,
+       CTA_TIMEOUT_NAME,
+       CTA_TIMEOUT_L3PROTO,
+       CTA_TIMEOUT_L4PROTO,
+       CTA_TIMEOUT_DATA,
+       CTA_TIMEOUT_USE,
+       __CTA_TIMEOUT_MAX
+};
+#define CTA_TIMEOUT_MAX (__CTA_TIMEOUT_MAX - 1)
+
+enum ctattr_timeout_generic {
+       CTA_TIMEOUT_GENERIC_UNSPEC,
+       CTA_TIMEOUT_GENERIC_TIMEOUT,
+       __CTA_TIMEOUT_GENERIC_MAX
+};
+#define CTA_TIMEOUT_GENERIC_MAX (__CTA_TIMEOUT_GENERIC_MAX - 1)
+
+enum ctattr_timeout_tcp {
+       CTA_TIMEOUT_TCP_UNSPEC,
+       CTA_TIMEOUT_TCP_SYN_SENT,
+       CTA_TIMEOUT_TCP_SYN_RECV,
+       CTA_TIMEOUT_TCP_ESTABLISHED,
+       CTA_TIMEOUT_TCP_FIN_WAIT,
+       CTA_TIMEOUT_TCP_CLOSE_WAIT,
+       CTA_TIMEOUT_TCP_LAST_ACK,
+       CTA_TIMEOUT_TCP_TIME_WAIT,
+       CTA_TIMEOUT_TCP_CLOSE,
+       CTA_TIMEOUT_TCP_SYN_SENT2,
+       CTA_TIMEOUT_TCP_RETRANS,
+       CTA_TIMEOUT_TCP_UNACK,
+       __CTA_TIMEOUT_TCP_MAX
+};
+#define CTA_TIMEOUT_TCP_MAX (__CTA_TIMEOUT_TCP_MAX - 1)
+
+enum ctattr_timeout_udp {
+       CTA_TIMEOUT_UDP_UNSPEC,
+       CTA_TIMEOUT_UDP_UNREPLIED,
+       CTA_TIMEOUT_UDP_REPLIED,
+       __CTA_TIMEOUT_UDP_MAX
+};
+#define CTA_TIMEOUT_UDP_MAX (__CTA_TIMEOUT_UDP_MAX - 1)
+
+enum ctattr_timeout_udplite {
+       CTA_TIMEOUT_UDPLITE_UNSPEC,
+       CTA_TIMEOUT_UDPLITE_UNREPLIED,
+       CTA_TIMEOUT_UDPLITE_REPLIED,
+       __CTA_TIMEOUT_UDPLITE_MAX
+};
+#define CTA_TIMEOUT_UDPLITE_MAX (__CTA_TIMEOUT_UDPLITE_MAX - 1)
+
+enum ctattr_timeout_icmp {
+       CTA_TIMEOUT_ICMP_UNSPEC,
+       CTA_TIMEOUT_ICMP_TIMEOUT,
+       __CTA_TIMEOUT_ICMP_MAX
+};
+#define CTA_TIMEOUT_ICMP_MAX (__CTA_TIMEOUT_ICMP_MAX - 1)
+
+enum ctattr_timeout_dccp {
+       CTA_TIMEOUT_DCCP_UNSPEC,
+       CTA_TIMEOUT_DCCP_REQUEST,
+       CTA_TIMEOUT_DCCP_RESPOND,
+       CTA_TIMEOUT_DCCP_PARTOPEN,
+       CTA_TIMEOUT_DCCP_OPEN,
+       CTA_TIMEOUT_DCCP_CLOSEREQ,
+       CTA_TIMEOUT_DCCP_CLOSING,
+       CTA_TIMEOUT_DCCP_TIMEWAIT,
+       __CTA_TIMEOUT_DCCP_MAX
+};
+#define CTA_TIMEOUT_DCCP_MAX (__CTA_TIMEOUT_DCCP_MAX - 1)
+
+enum ctattr_timeout_sctp {
+       CTA_TIMEOUT_SCTP_UNSPEC,
+       CTA_TIMEOUT_SCTP_CLOSED,
+       CTA_TIMEOUT_SCTP_COOKIE_WAIT,
+       CTA_TIMEOUT_SCTP_COOKIE_ECHOED,
+       CTA_TIMEOUT_SCTP_ESTABLISHED,
+       CTA_TIMEOUT_SCTP_SHUTDOWN_SENT,
+       CTA_TIMEOUT_SCTP_SHUTDOWN_RECD,
+       CTA_TIMEOUT_SCTP_SHUTDOWN_ACK_SENT,
+       __CTA_TIMEOUT_SCTP_MAX
+};
+#define CTA_TIMEOUT_SCTP_MAX (__CTA_TIMEOUT_SCTP_MAX - 1)
+
+enum ctattr_timeout_icmpv6 {
+       CTA_TIMEOUT_ICMPV6_UNSPEC,
+       CTA_TIMEOUT_ICMPV6_TIMEOUT,
+       __CTA_TIMEOUT_ICMPV6_MAX
+};
+#define CTA_TIMEOUT_ICMPV6_MAX (__CTA_TIMEOUT_ICMPV6_MAX - 1)
+
+enum ctattr_timeout_gre {
+       CTA_TIMEOUT_GRE_UNSPEC,
+       CTA_TIMEOUT_GRE_UNREPLIED,
+       CTA_TIMEOUT_GRE_REPLIED,
+       __CTA_TIMEOUT_GRE_MAX
+};
+#define CTA_TIMEOUT_GRE_MAX (__CTA_TIMEOUT_GRE_MAX - 1)
+
+#define CTNL_TIMEOUT_NAME_MAX  32
+
+#endif
index b56e76811c04380e9779dbe82c2cfa4a5b0c6abd..a064b8af360cac57143280730ba60009379a7c4b 100644 (file)
@@ -16,4 +16,16 @@ struct xt_ct_target_info {
        struct nf_conn  *ct __attribute__((aligned(8)));
 };
 
+struct xt_ct_target_info_v1 {
+       __u16 flags;
+       __u16 zone;
+       __u32 ct_events;
+       __u32 exp_events;
+       char helper[16];
+       char timeout[32];
+
+       /* Used internally by the kernel */
+       struct nf_conn  *ct __attribute__((aligned(8)));
+};
+
 #endif /* _XT_CT_H */
diff --git a/include/linux/netfilter/xt_LOG.h b/include/linux/netfilter/xt_LOG.h
new file mode 100644 (file)
index 0000000..cac0790
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef _XT_LOG_H
+#define _XT_LOG_H
+
+/* make sure not to change this without changing nf_log.h:NF_LOG_* (!) */
+#define XT_LOG_TCPSEQ          0x01    /* Log TCP sequence numbers */
+#define XT_LOG_TCPOPT          0x02    /* Log TCP options */
+#define XT_LOG_IPOPT           0x04    /* Log IP options */
+#define XT_LOG_UID             0x08    /* Log UID owning local socket */
+#define XT_LOG_NFLOG           0x10    /* Unsupported, don't reuse */
+#define XT_LOG_MACDECODE       0x20    /* Decode MAC header */
+#define XT_LOG_MASK            0x2f
+
+struct xt_log_info {
+       unsigned char level;
+       unsigned char logflags;
+       char prefix[30];
+};
+
+#endif /* _XT_LOG_H */
index f9930c87fff3a7beb35f558a788909ee1f27c5df..31f8bec95650292bcfb7770f3900f4634c5d9594 100644 (file)
@@ -4,11 +4,9 @@ header-y += ipt_CLUSTERIP.h
 header-y += ipt_ECN.h
 header-y += ipt_LOG.h
 header-y += ipt_REJECT.h
-header-y += ipt_SAME.h
 header-y += ipt_TTL.h
 header-y += ipt_ULOG.h
 header-y += ipt_addrtype.h
 header-y += ipt_ah.h
 header-y += ipt_ecn.h
-header-y += ipt_realm.h
 header-y += ipt_ttl.h
index dcdbadf9fd4a94180ed0705db436e4470bf0e9dd..5d8152077d7154324d61e5bd8241cdcb450c22d7 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _IPT_LOG_H
 #define _IPT_LOG_H
 
+#warning "Please update iptables, this file will be removed soon!"
+
 /* make sure not to change this without changing netfilter.h:NF_LOG_* (!) */
 #define IPT_LOG_TCPSEQ         0x01    /* Log TCP sequence numbers */
 #define IPT_LOG_TCPOPT         0x02    /* Log TCP options */
diff --git a/include/linux/netfilter_ipv4/ipt_SAME.h b/include/linux/netfilter_ipv4/ipt_SAME.h
deleted file mode 100644 (file)
index 5bca782..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef _IPT_SAME_H
-#define _IPT_SAME_H
-
-#include <linux/types.h>
-
-#define IPT_SAME_MAX_RANGE     10
-
-#define IPT_SAME_NODST         0x01
-
-struct ipt_same_info {
-       unsigned char info;
-       __u32 rangesize;
-       __u32 ipnum;
-       __u32 *iparray;
-
-       /* hangs off end. */
-       struct nf_nat_range range[IPT_SAME_MAX_RANGE];
-};
-
-#endif /*_IPT_SAME_H*/
diff --git a/include/linux/netfilter_ipv4/ipt_realm.h b/include/linux/netfilter_ipv4/ipt_realm.h
deleted file mode 100644 (file)
index b3996ea..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef _IPT_REALM_H
-#define _IPT_REALM_H
-
-#include <linux/netfilter/xt_realm.h>
-#define ipt_realm_info xt_realm_info
-
-#endif /* _IPT_REALM_H */
index 9dd5579e02ec75b82a503fc818d292e19b6b78c0..3dd0bc4e07358612622e41a30fdc9fd374b5250b 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _IP6T_LOG_H
 #define _IP6T_LOG_H
 
+#warning "Please update iptables, this file will be removed soon!"
+
 /* make sure not to change this without changing netfilter.h:NF_LOG_* (!) */
 #define IP6T_LOG_TCPSEQ                0x01    /* Log TCP sequence numbers */
 #define IP6T_LOG_TCPOPT                0x02    /* Log TCP options */
index b4999abcb2a240f28b1e1afa659ac9cb4ff78ee2..39c1fcf089c0a99ec654d4c5fb190eda696dd665 100644 (file)
@@ -107,6 +107,7 @@ enum nfc_attrs {
        NFC_ATTR_TARGET_SENSF_RES,
        NFC_ATTR_COMM_MODE,
        NFC_ATTR_RF_MODE,
+       NFC_ATTR_DEVICE_POWERED,
 /* private: internal use only */
        __NFC_ATTR_AFTER_LAST
 };
index ad56e21a9f10c0dfbb9b272b183a33dd90e0c1ca..c37d67add090b0cc45cd9555ee886e5ff7d7f091 100644 (file)
  * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX
  *     or %NL80211_ATTR_MAC.
  *
- * @NL80211_CMD_GET_BEACON: retrieve beacon information (returned in a
- *     %NL80222_CMD_NEW_BEACON message)
- * @NL80211_CMD_SET_BEACON: set the beacon on an access point interface
- *     using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD,
- *     %NL80211_ATTR_BEACON_HEAD and %NL80211_ATTR_BEACON_TAIL attributes.
- *     Following attributes are provided for drivers that generate full Beacon
- *     and Probe Response frames internally: %NL80211_ATTR_SSID,
+ * @NL80211_CMD_GET_BEACON: (not used)
+ * @NL80211_CMD_SET_BEACON: change the beacon on an access point interface
+ *     using the %NL80211_ATTR_BEACON_HEAD and %NL80211_ATTR_BEACON_TAIL
+ *     attributes. For drivers that generate the beacon and probe responses
+ *     internally, the following attributes must be provided: %NL80211_ATTR_IE,
+ *     %NL80211_ATTR_IE_PROBE_RESP and %NL80211_ATTR_IE_ASSOC_RESP.
+ * @NL80211_CMD_START_AP: Start AP operation on an AP interface, parameters
+ *     are like for %NL80211_CMD_SET_BEACON, and additionally parameters that
+ *     do not change are used, these include %NL80211_ATTR_BEACON_INTERVAL,
+ *     %NL80211_ATTR_DTIM_PERIOD, %NL80211_ATTR_SSID,
  *     %NL80211_ATTR_HIDDEN_SSID, %NL80211_ATTR_CIPHERS_PAIRWISE,
  *     %NL80211_ATTR_CIPHER_GROUP, %NL80211_ATTR_WPA_VERSIONS,
  *     %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY,
- *     %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_IE, %NL80211_ATTR_IE_PROBE_RESP,
- *     %NL80211_ATTR_IE_ASSOC_RESP.
- * @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface,
- *     parameters are like for %NL80211_CMD_SET_BEACON.
- * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it
+ *     %NL80211_ATTR_AUTH_TYPE and %NL80211_ATTR_INACTIVITY_TIMEOUT.
+ * @NL80211_CMD_NEW_BEACON: old alias for %NL80211_CMD_START_AP
+ * @NL80211_CMD_STOP_AP: Stop AP operation on the given interface
+ * @NL80211_CMD_DEL_BEACON: old alias for %NL80211_CMD_STOP_AP
  *
  * @NL80211_CMD_GET_STATION: Get station attributes for station identified by
  *     %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
@@ -565,8 +567,10 @@ enum nl80211_commands {
 
        NL80211_CMD_GET_BEACON,
        NL80211_CMD_SET_BEACON,
-       NL80211_CMD_NEW_BEACON,
-       NL80211_CMD_DEL_BEACON,
+       NL80211_CMD_START_AP,
+       NL80211_CMD_NEW_BEACON = NL80211_CMD_START_AP,
+       NL80211_CMD_STOP_AP,
+       NL80211_CMD_DEL_BEACON = NL80211_CMD_STOP_AP,
 
        NL80211_CMD_GET_STATION,
        NL80211_CMD_SET_STATION,
@@ -1193,6 +1197,16 @@ enum nl80211_commands {
  * @NL80211_ATTR_NOACK_MAP: This u16 bitmap contains the No Ack Policy of
  *      up to 16 TIDs.
  *
+ * @NL80211_ATTR_INACTIVITY_TIMEOUT: timeout value in seconds, this can be
+ *     used by the drivers which has MLME in firmware and does not have support
+ *     to report per station tx/rx activity to free up the staion entry from
+ *     the list. This needs to be used when the driver advertises the
+ *     capability to timeout the stations.
+ *
+ * @NL80211_ATTR_RX_SIGNAL_DBM: signal strength in dBm (as a 32-bit int);
+ *     this attribute is (depending on the driver capabilities) added to
+ *     received frames indicated with %NL80211_CMD_FRAME.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1438,6 +1452,10 @@ enum nl80211_attrs {
 
        NL80211_ATTR_NOACK_MAP,
 
+       NL80211_ATTR_INACTIVITY_TIMEOUT,
+
+       NL80211_ATTR_RX_SIGNAL_DBM,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -2108,6 +2126,10 @@ enum nl80211_mntr_flags {
  * @NL80211_MESHCONF_FORWARDING: set Mesh STA as forwarding or non-forwarding
  * or forwarding entity (default is TRUE - forwarding entity)
  *
+ * @NL80211_MESHCONF_RSSI_THRESHOLD: RSSI threshold in dBm. This specifies the
+ * threshold for average signal strength of candidate station to establish
+ * a peer link.
+ *
  * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute
  *
  * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
@@ -2133,6 +2155,7 @@ enum nl80211_meshconf_params {
        NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
        NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
        NL80211_MESHCONF_FORWARDING,
+       NL80211_MESHCONF_RSSI_THRESHOLD,
 
        /* keep last */
        __NL80211_MESHCONF_ATTR_AFTER_LAST,
@@ -2800,10 +2823,13 @@ enum nl80211_ap_sme_features {
  *     TX status to the socket error queue when requested with the
  *     socket option.
  * @NL80211_FEATURE_HT_IBSS: This driver supports IBSS with HT datarates.
+ * @NL80211_FEATURE_INACTIVITY_TIMER: This driver takes care of freeing up
+ *     the connected inactive stations in AP mode.
  */
 enum nl80211_feature_flags {
        NL80211_FEATURE_SK_TX_STATUS    = 1 << 0,
        NL80211_FEATURE_HT_IBSS         = 1 << 1,
+       NL80211_FEATURE_INACTIVITY_TIMER = 1 << 2,
 };
 
 /**
index a75a831e2057f96e3519d100f988a584e18ac669..92cf6ad35e0ea01d33ab70ea3cb70394f96762e2 100644 (file)
@@ -281,6 +281,14 @@ static inline struct property *of_find_property(const struct device_node *np,
        return NULL;
 }
 
+static inline struct device_node *of_find_compatible_node(
+                                               struct device_node *from,
+                                               const char *type,
+                                               const char *compat)
+{
+       return NULL;
+}
+
 static inline int of_property_read_u32_array(const struct device_node *np,
                                             const char *propname,
                                             u32 *out_values, size_t sz)
index 32cd1f67462e9b4a80f602474878c6ff632d6976..21638ae14e07c71a005d6cfcea61958e8cd8f970 100644 (file)
@@ -348,9 +348,9 @@ do {                                                                        \
 #define _this_cpu_generic_to_op(pcp, val, op)                          \
 do {                                                                   \
        unsigned long flags;                                            \
-       local_irq_save(flags);                                          \
+       raw_local_irq_save(flags);                                      \
        *__this_cpu_ptr(&(pcp)) op val;                                 \
-       local_irq_restore(flags);                                       \
+       raw_local_irq_restore(flags);                                   \
 } while (0)
 
 #ifndef this_cpu_write
@@ -449,10 +449,10 @@ do {                                                                      \
 ({                                                                     \
        typeof(pcp) ret__;                                              \
        unsigned long flags;                                            \
-       local_irq_save(flags);                                          \
+       raw_local_irq_save(flags);                                      \
        __this_cpu_add(pcp, val);                                       \
        ret__ = __this_cpu_read(pcp);                                   \
-       local_irq_restore(flags);                                       \
+       raw_local_irq_restore(flags);                                   \
        ret__;                                                          \
 })
 
@@ -479,10 +479,10 @@ do {                                                                      \
 #define _this_cpu_generic_xchg(pcp, nval)                              \
 ({     typeof(pcp) ret__;                                              \
        unsigned long flags;                                            \
-       local_irq_save(flags);                                          \
+       raw_local_irq_save(flags);                                      \
        ret__ = __this_cpu_read(pcp);                                   \
        __this_cpu_write(pcp, nval);                                    \
-       local_irq_restore(flags);                                       \
+       raw_local_irq_restore(flags);                                   \
        ret__;                                                          \
 })
 
@@ -507,11 +507,11 @@ do {                                                                      \
 ({                                                                     \
        typeof(pcp) ret__;                                              \
        unsigned long flags;                                            \
-       local_irq_save(flags);                                          \
+       raw_local_irq_save(flags);                                      \
        ret__ = __this_cpu_read(pcp);                                   \
        if (ret__ == (oval))                                            \
                __this_cpu_write(pcp, nval);                            \
-       local_irq_restore(flags);                                       \
+       raw_local_irq_restore(flags);                                   \
        ret__;                                                          \
 })
 
@@ -544,10 +544,10 @@ do {                                                                      \
 ({                                                                     \
        int ret__;                                                      \
        unsigned long flags;                                            \
-       local_irq_save(flags);                                          \
+       raw_local_irq_save(flags);                                      \
        ret__ = __this_cpu_generic_cmpxchg_double(pcp1, pcp2,           \
                        oval1, oval2, nval1, nval2);                    \
-       local_irq_restore(flags);                                       \
+       raw_local_irq_restore(flags);                                   \
        ret__;                                                          \
 })
 
@@ -718,12 +718,13 @@ do {                                                                      \
 # ifndef __this_cpu_add_return_8
 #  define __this_cpu_add_return_8(pcp, val)    __this_cpu_generic_add_return(pcp, val)
 # endif
-# define __this_cpu_add_return(pcp, val)       __pcpu_size_call_return2(this_cpu_add_return_, pcp, val)
+# define __this_cpu_add_return(pcp, val)       \
+       __pcpu_size_call_return2(__this_cpu_add_return_, pcp, val)
 #endif
 
-#define __this_cpu_sub_return(pcp, val)        this_cpu_add_return(pcp, -(val))
-#define __this_cpu_inc_return(pcp)     this_cpu_add_return(pcp, 1)
-#define __this_cpu_dec_return(pcp)     this_cpu_add_return(pcp, -1)
+#define __this_cpu_sub_return(pcp, val)        __this_cpu_add_return(pcp, -(val))
+#define __this_cpu_inc_return(pcp)     __this_cpu_add_return(pcp, 1)
+#define __this_cpu_dec_return(pcp)     __this_cpu_add_return(pcp, -1)
 
 #define __this_cpu_generic_xchg(pcp, nval)                             \
 ({     typeof(pcp) ret__;                                              \
index 8abee65562230fe05174d2ded6bc8ec50249348b..686f37327a4949f50ad3d02b888f8f445f291ece 100644 (file)
@@ -335,8 +335,11 @@ static inline int copy_regset_to_user(struct task_struct *target,
 {
        const struct user_regset *regset = &view->regsets[setno];
 
+       if (!regset->get)
+               return -EOPNOTSUPP;
+
        if (!access_ok(VERIFY_WRITE, data, size))
-               return -EIO;
+               return -EFAULT;
 
        return regset->get(target, regset, offset, size, NULL, data);
 }
@@ -358,8 +361,11 @@ static inline int copy_regset_from_user(struct task_struct *target,
 {
        const struct user_regset *regset = &view->regsets[setno];
 
+       if (!regset->set)
+               return -EOPNOTSUPP;
+
        if (!access_ok(VERIFY_READ, data, size))
-               return -EIO;
+               return -EFAULT;
 
        return regset->set(target, regset, offset, size, NULL, data);
 }
index 7d379a6bfd886679fcfefee2ed90fb636d6cd028..0657368bd78fb9207369b484fa2aa294f90ce5dc 100644 (file)
@@ -1777,7 +1777,6 @@ extern void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *
 /*
  * Per process flags
  */
-#define PF_STARTING    0x00000002      /* being created */
 #define PF_EXITING     0x00000004      /* getting shut down */
 #define PF_EXITPIDONE  0x00000008      /* pi exit done on shut down */
 #define PF_VCPU                0x00000010      /* I'm a virtual CPU */
@@ -2371,7 +2370,7 @@ static inline int thread_group_empty(struct task_struct *p)
  * Protects ->fs, ->files, ->mm, ->group_info, ->comm, keyring
  * subscriptions and synchronises with wait4().  Also used in procfs.  Also
  * pins the final release of task.io_context.  Also protects ->cpuset and
- * ->cgroup.subsys[].
+ * ->cgroup.subsys[]. And ->vfork_done.
  *
  * Nests both inside and outside of read_lock(&tasklist_lock).
  * It must not be nested with write_lock_irq(&tasklist_lock),
index 79ef8209bbb706b51a2276df717d97d83dec3234..8dc8257eab8b2131ba45f73e19b43135bce5fdb6 100644 (file)
@@ -1173,7 +1173,7 @@ static inline struct sk_buff *__skb_dequeue_tail(struct sk_buff_head *list)
 }
 
 
-static inline int skb_is_nonlinear(const struct sk_buff *skb)
+static inline bool skb_is_nonlinear(const struct sk_buff *skb)
 {
        return skb->data_len;
 }
@@ -2469,12 +2469,12 @@ static inline struct sec_path *skb_sec_path(struct sk_buff *skb)
 }
 #endif
 
-static inline int skb_is_gso(const struct sk_buff *skb)
+static inline bool skb_is_gso(const struct sk_buff *skb)
 {
        return skb_shinfo(skb)->gso_size;
 }
 
-static inline int skb_is_gso_v6(const struct sk_buff *skb)
+static inline bool skb_is_gso_v6(const struct sk_buff *skb)
 {
        return skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6;
 }
index bbc2612cb64a83b75dc03484eb8c345e4bac98de..d2768318002519510971a60a156ff32591f6790c 100644 (file)
@@ -19,7 +19,7 @@ struct ssb_driver;
 struct ssb_sprom_core_pwr_info {
        u8 itssi_2g, itssi_5g;
        u8 maxpwr_2g, maxpwr_5gl, maxpwr_5g, maxpwr_5gh;
-       u16 pa_2g[3], pa_5gl[3], pa_5g[3], pa_5gh[3];
+       u16 pa_2g[4], pa_5gl[4], pa_5g[4], pa_5gh[4];
 };
 
 struct ssb_sprom {
@@ -32,9 +32,12 @@ struct ssb_sprom {
        u8 et0mdcport;          /* MDIO for enet0 */
        u8 et1mdcport;          /* MDIO for enet1 */
        u16 board_rev;          /* Board revision number from SPROM. */
+       u16 board_num;          /* Board number from SPROM. */
+       u16 board_type;         /* Board type from SPROM. */
        u8 country_code;        /* Country Code */
-       u16 leddc_on_time;      /* LED Powersave Duty Cycle On Count */
-       u16 leddc_off_time;     /* LED Powersave Duty Cycle Off Count */
+       char alpha2[2];         /* Country Code as two chars like EU or US */
+       u8 leddc_on_time;       /* LED Powersave Duty Cycle On Count */
+       u8 leddc_off_time;      /* LED Powersave Duty Cycle Off Count */
        u8 ant_available_a;     /* 2GHz antenna available bits (up to 4) */
        u8 ant_available_bg;    /* 5GHz antenna available bits (up to 4) */
        u16 pa0b0;
@@ -53,10 +56,10 @@ struct ssb_sprom {
        u8 gpio1;               /* GPIO pin 1 */
        u8 gpio2;               /* GPIO pin 2 */
        u8 gpio3;               /* GPIO pin 3 */
-       u16 maxpwr_bg;          /* 2.4GHz Amplifier Max Power (in dBm Q5.2) */
-       u16 maxpwr_al;          /* 5.2GHz Amplifier Max Power (in dBm Q5.2) */
-       u16 maxpwr_a;           /* 5.3GHz Amplifier Max Power (in dBm Q5.2) */
-       u16 maxpwr_ah;          /* 5.8GHz Amplifier Max Power (in dBm Q5.2) */
+       u8 maxpwr_bg;           /* 2.4GHz Amplifier Max Power (in dBm Q5.2) */
+       u8 maxpwr_al;           /* 5.2GHz Amplifier Max Power (in dBm Q5.2) */
+       u8 maxpwr_a;            /* 5.3GHz Amplifier Max Power (in dBm Q5.2) */
+       u8 maxpwr_ah;           /* 5.8GHz Amplifier Max Power (in dBm Q5.2) */
        u8 itssi_a;             /* Idle TSSI Target for A-PHY */
        u8 itssi_bg;            /* Idle TSSI Target for B/G-PHY */
        u8 tri2g;               /* 2.4GHz TX isolation */
@@ -67,8 +70,8 @@ struct ssb_sprom {
        u8 txpid5gl[4];         /* 4.9 - 5.1GHz TX power index */
        u8 txpid5g[4];          /* 5.1 - 5.5GHz TX power index */
        u8 txpid5gh[4];         /* 5.5 - ...GHz TX power index */
-       u8 rxpo2g;              /* 2GHz RX power offset */
-       u8 rxpo5g;              /* 5GHz RX power offset */
+       s8 rxpo2g;              /* 2GHz RX power offset */
+       s8 rxpo5g;              /* 5GHz RX power offset */
        u8 rssisav2g;           /* 2GHz RSSI params */
        u8 rssismc2g;
        u8 rssismf2g;
@@ -94,12 +97,7 @@ struct ssb_sprom {
         * on each band. Values in dBm/4 (Q5.2). Negative gain means the
         * loss in the connectors is bigger than the gain. */
        struct {
-               struct {
-                       s8 a0, a1, a2, a3;
-               } ghz24;        /* 2.4GHz band */
-               struct {
-                       s8 a0, a1, a2, a3;
-               } ghz5;         /* 5GHz band */
+               s8 a0, a1, a2, a3;
        } antenna_gain;
 
        struct {
@@ -111,7 +109,79 @@ struct ssb_sprom {
                } ghz5;
        } fem;
 
-       /* TODO - add any parameters needed from rev 2, 3, 4, 5 or 8 SPROMs */
+       u16 mcs2gpo[8];
+       u16 mcs5gpo[8];
+       u16 mcs5glpo[8];
+       u16 mcs5ghpo[8];
+       u8 opo;
+
+       u8 rxgainerr2ga[3];
+       u8 rxgainerr5gla[3];
+       u8 rxgainerr5gma[3];
+       u8 rxgainerr5gha[3];
+       u8 rxgainerr5gua[3];
+
+       u8 noiselvl2ga[3];
+       u8 noiselvl5gla[3];
+       u8 noiselvl5gma[3];
+       u8 noiselvl5gha[3];
+       u8 noiselvl5gua[3];
+
+       u8 regrev;
+       u8 txchain;
+       u8 rxchain;
+       u8 antswitch;
+       u16 cddpo;
+       u16 stbcpo;
+       u16 bw40po;
+       u16 bwduppo;
+
+       u8 tempthresh;
+       u8 tempoffset;
+       u16 rawtempsense;
+       u8 measpower;
+       u8 tempsense_slope;
+       u8 tempcorrx;
+       u8 tempsense_option;
+       u8 freqoffset_corr;
+       u8 iqcal_swp_dis;
+       u8 hw_iqcal_en;
+       u8 elna2g;
+       u8 elna5g;
+       u8 phycal_tempdelta;
+       u8 temps_period;
+       u8 temps_hysteresis;
+       u8 measpower1;
+       u8 measpower2;
+       u8 pcieingress_war;
+
+       /* power per rate from sromrev 9 */
+       u16 cckbw202gpo;
+       u16 cckbw20ul2gpo;
+       u32 legofdmbw202gpo;
+       u32 legofdmbw20ul2gpo;
+       u32 legofdmbw205glpo;
+       u32 legofdmbw20ul5glpo;
+       u32 legofdmbw205gmpo;
+       u32 legofdmbw20ul5gmpo;
+       u32 legofdmbw205ghpo;
+       u32 legofdmbw20ul5ghpo;
+       u32 mcsbw202gpo;
+       u32 mcsbw20ul2gpo;
+       u32 mcsbw402gpo;
+       u32 mcsbw205glpo;
+       u32 mcsbw20ul5glpo;
+       u32 mcsbw405glpo;
+       u32 mcsbw205gmpo;
+       u32 mcsbw20ul5gmpo;
+       u32 mcsbw405gmpo;
+       u32 mcsbw205ghpo;
+       u32 mcsbw20ul5ghpo;
+       u32 mcsbw405ghpo;
+       u16 mcs32po;
+       u16 legofdm40duppo;
+       u8 sar2g;
+       u8 sar5g;
 };
 
 /* Information about the PCB the circuitry is soldered on. */
index 4a82ca0bb0b209a12c65a83b42138098e6572ad1..262ebd1747d4d2d0121f20a5114741d48c8a48fe 100644 (file)
@@ -109,12 +109,14 @@ struct bt_power {
  */
 #define BT_CHANNEL_POLICY_AMP_PREFERRED                2
 
-__printf(2, 3)
-int bt_printk(const char *level, const char *fmt, ...);
+__printf(1, 2)
+int bt_info(const char *fmt, ...);
+__printf(1, 2)
+int bt_err(const char *fmt, ...);
 
-#define BT_INFO(fmt, arg...)   bt_printk(KERN_INFO, pr_fmt(fmt), ##arg)
-#define BT_ERR(fmt, arg...)    bt_printk(KERN_ERR, pr_fmt(fmt), ##arg)
-#define BT_DBG(fmt, arg...)    pr_debug(fmt "\n", ##arg)
+#define BT_INFO(fmt, ...)      bt_info(fmt "\n", ##__VA_ARGS__)
+#define BT_ERR(fmt, ...)       bt_err(fmt "\n", ##__VA_ARGS__)
+#define BT_DBG(fmt, ...)       pr_debug(fmt "\n", ##__VA_ARGS__)
 
 /* Connection and socket states */
 enum {
@@ -129,6 +131,33 @@ enum {
        BT_CLOSED
 };
 
+/* If unused will be removed by compiler */
+static inline const char *state_to_string(int state)
+{
+       switch (state) {
+       case BT_CONNECTED:
+               return "BT_CONNECTED";
+       case BT_OPEN:
+               return "BT_OPEN";
+       case BT_BOUND:
+               return "BT_BOUND";
+       case BT_LISTEN:
+               return "BT_LISTEN";
+       case BT_CONNECT:
+               return "BT_CONNECT";
+       case BT_CONNECT2:
+               return "BT_CONNECT2";
+       case BT_CONFIG:
+               return "BT_CONFIG";
+       case BT_DISCONN:
+               return "BT_DISCONN";
+       case BT_CLOSED:
+               return "BT_CLOSED";
+       }
+
+       return "invalid state";
+}
+
 /* BD Address */
 typedef struct {
        __u8 b[6];
@@ -193,7 +222,6 @@ struct bt_skb_cb {
        __u16 tx_seq;
        __u8 retries;
        __u8 sar;
-       unsigned short channel;
        __u8 force_active;
 };
 #define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb))
index 00596e816b4d6d8dd79f6272d0e293f163d277d0..344b0f972828f4167393948c4263a628309ca7c6 100644 (file)
@@ -77,14 +77,6 @@ enum {
 
        HCI_RAW,
 
-       HCI_SETUP,
-       HCI_AUTO_OFF,
-       HCI_MGMT,
-       HCI_PAIRABLE,
-       HCI_SERVICE_CACHE,
-       HCI_LINK_KEYS,
-       HCI_DEBUG_KEYS,
-
        HCI_RESET,
 };
 
@@ -93,7 +85,22 @@ enum {
  * states from the controller.
  */
 enum {
+       HCI_SETUP,
+       HCI_AUTO_OFF,
+       HCI_MGMT,
+       HCI_PAIRABLE,
+       HCI_SERVICE_CACHE,
+       HCI_LINK_KEYS,
+       HCI_DEBUG_KEYS,
+
        HCI_LE_SCAN,
+       HCI_SSP_ENABLED,
+       HCI_HS_ENABLED,
+       HCI_LE_ENABLED,
+       HCI_CONNECTABLE,
+       HCI_DISCOVERABLE,
+       HCI_LINK_SECURITY,
+       HCI_PENDING_CLASS,
 };
 
 /* HCI ioctl defines */
@@ -130,6 +137,7 @@ enum {
 #define HCI_IDLE_TIMEOUT       (6000)  /* 6 seconds */
 #define HCI_INIT_TIMEOUT       (10000) /* 10 seconds */
 #define HCI_CMD_TIMEOUT                (1000)  /* 1 seconds */
+#define HCI_ACL_TX_TIMEOUT     (45000) /* 45 seconds */
 
 /* HCI data types */
 #define HCI_COMMAND_PKT                0x01
@@ -229,7 +237,9 @@ enum {
 #define LMP_EXTFEATURES        0x80
 
 /* Extended LMP features */
-#define LMP_HOST_LE    0x02
+#define LMP_HOST_SSP           0x01
+#define LMP_HOST_LE            0x02
+#define LMP_HOST_LE_BREDR      0x04
 
 /* Connection modes */
 #define HCI_CM_ACTIVE  0x0000
@@ -268,10 +278,11 @@ enum {
 #define HCI_LK_UNAUTH_COMBINATION      0x04
 #define HCI_LK_AUTH_COMBINATION                0x05
 #define HCI_LK_CHANGED_COMBINATION     0x06
-/* The spec doesn't define types for SMP keys */
-#define HCI_LK_SMP_LTK                 0x81
-#define HCI_LK_SMP_IRK                 0x82
-#define HCI_LK_SMP_CSRK                        0x83
+/* The spec doesn't define types for SMP keys, the _MASTER suffix is implied */
+#define HCI_SMP_STK                    0x80
+#define HCI_SMP_STK_SLAVE              0x81
+#define HCI_SMP_LTK                    0x82
+#define HCI_SMP_LTK_SLAVE              0x83
 
 /* ---- HCI Error Codes ---- */
 #define HCI_ERROR_AUTH_FAILURE         0x05
@@ -284,6 +295,22 @@ enum {
 #define HCI_FLOW_CTL_MODE_PACKET_BASED 0x00
 #define HCI_FLOW_CTL_MODE_BLOCK_BASED  0x01
 
+/* Extended Inquiry Response field types */
+#define EIR_FLAGS              0x01 /* flags */
+#define EIR_UUID16_SOME                0x02 /* 16-bit UUID, more available */
+#define EIR_UUID16_ALL         0x03 /* 16-bit UUID, all listed */
+#define EIR_UUID32_SOME                0x04 /* 32-bit UUID, more available */
+#define EIR_UUID32_ALL         0x05 /* 32-bit UUID, all listed */
+#define EIR_UUID128_SOME       0x06 /* 128-bit UUID, more available */
+#define EIR_UUID128_ALL                0x07 /* 128-bit UUID, all listed */
+#define EIR_NAME_SHORT         0x08 /* shortened local name */
+#define EIR_NAME_COMPLETE      0x09 /* complete local name */
+#define EIR_TX_POWER           0x0A /* transmit power level */
+#define EIR_CLASS_OF_DEV       0x0D /* Class of Device */
+#define EIR_SSP_HASH_C         0x0E /* Simple Pairing Hash C */
+#define EIR_SSP_RAND_R         0x0F /* Simple Pairing Randomizer R */
+#define EIR_DEVICE_ID          0x10 /* device ID */
+
 /* -----  HCI Commands ---- */
 #define HCI_OP_NOP                     0x0000
 
@@ -666,8 +693,8 @@ struct hci_cp_host_buffer_size {
 
 #define HCI_OP_WRITE_EIR               0x0c52
 struct hci_cp_write_eir {
-       uint8_t         fec;
-       uint8_t         data[HCI_MAX_EIR_LENGTH];
+       __u8    fec;
+       __u8    data[HCI_MAX_EIR_LENGTH];
 } __packed;
 
 #define HCI_OP_READ_SSP_MODE           0x0c55
@@ -698,8 +725,8 @@ struct hci_rp_read_flow_control_mode {
 
 #define HCI_OP_WRITE_LE_HOST_SUPPORTED 0x0c6d
 struct hci_cp_write_le_host_supported {
-       __u8 le;
-       __u8 simul;
+       __u8    le;
+       __u8    simul;
 } __packed;
 
 #define HCI_OP_READ_LOCAL_VERSION      0x1001
@@ -1155,6 +1182,19 @@ struct hci_ev_le_meta {
        __u8     subevent;
 } __packed;
 
+#define HCI_EV_NUM_COMP_BLOCKS         0x48
+struct hci_comp_blocks_info {
+       __le16   handle;
+       __le16   pkts;
+       __le16   blocks;
+} __packed;
+
+struct hci_ev_num_comp_blocks {
+       __le16   num_blocks;
+       __u8     num_hndl;
+       struct hci_comp_blocks_info handles[0];
+} __packed;
+
 /* Low energy meta events */
 #define HCI_EV_LE_CONN_COMPLETE                0x01
 struct hci_ev_le_conn_complete {
@@ -1288,6 +1328,7 @@ struct sockaddr_hci {
 
 #define HCI_CHANNEL_RAW                0
 #define HCI_CHANNEL_CONTROL    1
+#define HCI_CHANNEL_MONITOR    2
 
 struct hci_filter {
        unsigned long type_mask;
@@ -1389,5 +1430,6 @@ struct hci_inquiry_req {
 #define IREQ_CACHE_FLUSH 0x0001
 
 extern bool enable_hs;
+extern bool enable_le;
 
 #endif /* __HCI_H */
index 453893b3120ef6b81d024047a420802dedcb9247..daefaac511311348ac2772eeeed9d2f9ca0c7679 100644 (file)
@@ -44,14 +44,31 @@ struct inquiry_data {
 };
 
 struct inquiry_entry {
-       struct inquiry_entry    *next;
+       struct list_head        all;            /* inq_cache.all */
+       struct list_head        list;           /* unknown or resolve */
+       enum {
+               NAME_NOT_KNOWN,
+               NAME_NEEDED,
+               NAME_PENDING,
+               NAME_KNOWN,
+       } name_state;
        __u32                   timestamp;
        struct inquiry_data     data;
 };
 
-struct inquiry_cache {
+struct discovery_state {
+       int                     type;
+       enum {
+               DISCOVERY_STOPPED,
+               DISCOVERY_STARTING,
+               DISCOVERY_FINDING,
+               DISCOVERY_RESOLVING,
+               DISCOVERY_STOPPING,
+       } state;
+       struct list_head        all;            /* All devices found during inquiry */
+       struct list_head        unknown;        /* Name state not known */
+       struct list_head        resolve;        /* Name needs to be resolved */
        __u32                   timestamp;
-       struct inquiry_entry    *list;
 };
 
 struct hci_conn_hash {
@@ -72,18 +89,16 @@ struct bt_uuid {
        u8 svc_hint;
 };
 
-struct key_master_id {
-       __le16 ediv;
-       u8 rand[8];
-} __packed;
-
-struct link_key_data {
+struct smp_ltk {
+       struct list_head list;
        bdaddr_t bdaddr;
+       u8 bdaddr_type;
+       u8 authenticated;
        u8 type;
+       u8 enc_size;
+       __le16 ediv;
+       u8 rand[8];
        u8 val[16];
-       u8 pin_len;
-       u8 dlen;
-       u8 data[0];
 } __packed;
 
 struct link_key {
@@ -92,8 +107,6 @@ struct link_key {
        u8 type;
        u8 val[16];
        u8 pin_len;
-       u8 dlen;
-       u8 data[0];
 };
 
 struct oob_data {
@@ -109,11 +122,19 @@ struct adv_entry {
        u8 bdaddr_type;
 };
 
+struct le_scan_params {
+       u8 type;
+       u16 interval;
+       u16 window;
+       int timeout;
+};
+
+#define HCI_MAX_SHORT_NAME_LENGTH      10
+
 #define NUM_REASSEMBLY 4
 struct hci_dev {
        struct list_head list;
        struct mutex    lock;
-       atomic_t        refcnt;
 
        char            name[8];
        unsigned long   flags;
@@ -122,6 +143,7 @@ struct hci_dev {
        __u8            dev_type;
        bdaddr_t        bdaddr;
        __u8            dev_name[HCI_MAX_NAME_LENGTH];
+       __u8            short_name[HCI_MAX_SHORT_NAME_LENGTH];
        __u8            eir[HCI_MAX_EIR_LENGTH];
        __u8            dev_class[3];
        __u8            major_class;
@@ -129,7 +151,6 @@ struct hci_dev {
        __u8            features[8];
        __u8            host_features[8];
        __u8            commands[64];
-       __u8            ssp_mode;
        __u8            hci_ver;
        __u16           hci_rev;
        __u8            lmp_ver;
@@ -217,7 +238,7 @@ struct hci_dev {
 
        struct list_head        mgmt_pending;
 
-       struct inquiry_cache    inq_cache;
+       struct discovery_state  discovery;
        struct hci_conn_hash    conn_hash;
        struct list_head        blacklist;
 
@@ -225,6 +246,8 @@ struct hci_dev {
 
        struct list_head        link_keys;
 
+       struct list_head        long_term_keys;
+
        struct list_head        remote_oob_data;
 
        struct list_head        adv_entries;
@@ -234,7 +257,6 @@ struct hci_dev {
 
        struct sk_buff_head     driver_init;
 
-       void                    *driver_data;
        void                    *core_data;
 
        atomic_t                promisc;
@@ -246,15 +268,17 @@ struct hci_dev {
 
        struct rfkill           *rfkill;
 
-       struct module           *owner;
-
        unsigned long           dev_flags;
 
+       struct delayed_work     le_scan_disable;
+
+       struct work_struct      le_scan;
+       struct le_scan_params   le_scan_params;
+
        int (*open)(struct hci_dev *hdev);
        int (*close)(struct hci_dev *hdev);
        int (*flush)(struct hci_dev *hdev);
        int (*send)(struct sk_buff *skb);
-       void (*destruct)(struct hci_dev *hdev);
        void (*notify)(struct hci_dev *hdev, unsigned int evt);
        int (*ioctl)(struct hci_dev *hdev, unsigned int cmd, unsigned long arg);
 };
@@ -270,11 +294,10 @@ struct hci_conn {
        __u16           state;
        __u8            mode;
        __u8            type;
-       __u8            out;
+       bool            out;
        __u8            attempt;
        __u8            dev_class[3];
        __u8            features[8];
-       __u8            ssp_mode;
        __u16           interval;
        __u16           pkt_type;
        __u16           link_policy;
@@ -286,12 +309,10 @@ struct hci_conn {
        __u8            pin_length;
        __u8            enc_key_size;
        __u8            io_capability;
-       __u8            power_save;
        __u16           disc_timeout;
-       unsigned long   pend;
+       unsigned long   flags;
 
        __u8            remote_cap;
-       __u8            remote_oob;
        __u8            remote_auth;
 
        unsigned int    sent;
@@ -348,21 +369,26 @@ extern int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb);
 #define INQUIRY_CACHE_AGE_MAX   (HZ*30)   /* 30 seconds */
 #define INQUIRY_ENTRY_AGE_MAX   (HZ*60)   /* 60 seconds */
 
-static inline void inquiry_cache_init(struct hci_dev *hdev)
+static inline void discovery_init(struct hci_dev *hdev)
 {
-       struct inquiry_cache *c = &hdev->inq_cache;
-       c->list = NULL;
+       hdev->discovery.state = DISCOVERY_STOPPED;
+       INIT_LIST_HEAD(&hdev->discovery.all);
+       INIT_LIST_HEAD(&hdev->discovery.unknown);
+       INIT_LIST_HEAD(&hdev->discovery.resolve);
 }
 
+bool hci_discovery_active(struct hci_dev *hdev);
+
+void hci_discovery_set_state(struct hci_dev *hdev, int state);
+
 static inline int inquiry_cache_empty(struct hci_dev *hdev)
 {
-       struct inquiry_cache *c = &hdev->inq_cache;
-       return c->list == NULL;
+       return list_empty(&hdev->discovery.all);
 }
 
 static inline long inquiry_cache_age(struct hci_dev *hdev)
 {
-       struct inquiry_cache *c = &hdev->inq_cache;
+       struct discovery_state *c = &hdev->discovery;
        return jiffies - c->timestamp;
 }
 
@@ -372,8 +398,16 @@ static inline long inquiry_entry_age(struct inquiry_entry *e)
 }
 
 struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev,
-                                                       bdaddr_t *bdaddr);
-void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data);
+                                              bdaddr_t *bdaddr);
+struct inquiry_entry *hci_inquiry_cache_lookup_unknown(struct hci_dev *hdev,
+                                                      bdaddr_t *bdaddr);
+struct inquiry_entry *hci_inquiry_cache_lookup_resolve(struct hci_dev *hdev,
+                                                      bdaddr_t *bdaddr,
+                                                      int state);
+void hci_inquiry_cache_update_resolve(struct hci_dev *hdev,
+                                     struct inquiry_entry *ie);
+bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data,
+                             bool name_known, bool *ssp);
 
 /* ----- HCI Connections ----- */
 enum {
@@ -384,8 +418,19 @@ enum {
        HCI_CONN_MODE_CHANGE_PEND,
        HCI_CONN_SCO_SETUP_PEND,
        HCI_CONN_LE_SMP_PEND,
+       HCI_CONN_MGMT_CONNECTED,
+       HCI_CONN_SSP_ENABLED,
+       HCI_CONN_POWER_SAVE,
+       HCI_CONN_REMOTE_OOB,
 };
 
+static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
+{
+       struct hci_dev *hdev = conn->hdev;
+       return (test_bit(HCI_SSP_ENABLED, &hdev->flags) &&
+                               test_bit(HCI_CONN_SSP_ENABLED, &conn->flags));
+}
+
 static inline void hci_conn_hash_init(struct hci_dev *hdev)
 {
        struct hci_conn_hash *h = &hdev->conn_hash;
@@ -566,36 +611,33 @@ static inline void hci_conn_put(struct hci_conn *conn)
 }
 
 /* ----- HCI Devices ----- */
-static inline void __hci_dev_put(struct hci_dev *d)
+static inline void hci_dev_put(struct hci_dev *d)
 {
-       if (atomic_dec_and_test(&d->refcnt))
-               d->destruct(d);
+       put_device(&d->dev);
 }
 
-/*
- * hci_dev_put and hci_dev_hold are macros to avoid dragging all the
- * overhead of all the modular infrastructure into this header.
- */
-#define hci_dev_put(d)         \
-do {                           \
-       __hci_dev_put(d);       \
-       module_put(d->owner);   \
-} while (0)
-
-static inline struct hci_dev *__hci_dev_hold(struct hci_dev *d)
+static inline struct hci_dev *hci_dev_hold(struct hci_dev *d)
 {
-       atomic_inc(&d->refcnt);
+       get_device(&d->dev);
        return d;
 }
 
-#define hci_dev_hold(d)                                                \
-({                                                             \
-       try_module_get(d->owner) ? __hci_dev_hold(d) : NULL;    \
-})
-
 #define hci_dev_lock(d)                mutex_lock(&d->lock)
 #define hci_dev_unlock(d)      mutex_unlock(&d->lock)
 
+#define to_hci_dev(d) container_of(d, struct hci_dev, dev)
+#define to_hci_conn(c) container_of(c, struct hci_conn, dev)
+
+static inline void *hci_get_drvdata(struct hci_dev *hdev)
+{
+       return dev_get_drvdata(&hdev->dev);
+}
+
+static inline void hci_set_drvdata(struct hci_dev *hdev, void *data)
+{
+       dev_set_drvdata(&hdev->dev, data);
+}
+
 struct hci_dev *hci_dev_get(int index);
 struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst);
 
@@ -619,20 +661,23 @@ int hci_inquiry(void __user *arg);
 
 struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr);
 int hci_blacklist_clear(struct hci_dev *hdev);
-int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr);
-int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr);
+int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
+int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
 
 int hci_uuids_clear(struct hci_dev *hdev);
 
 int hci_link_keys_clear(struct hci_dev *hdev);
 struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
 int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
-                       bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len);
-struct link_key *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]);
-struct link_key *hci_find_link_key_type(struct hci_dev *hdev,
-                                       bdaddr_t *bdaddr, u8 type);
-int hci_add_ltk(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
-                       u8 key_size, __le16 ediv, u8 rand[8], u8 ltk[16]);
+                    bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len);
+struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]);
+int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type,
+               int new_key, u8 authenticated, u8 tk[16], u8 enc_size, u16 ediv,
+               u8 rand[8]);
+struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                    u8 addr_type);
+int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr);
+int hci_smp_ltks_clear(struct hci_dev *hdev);
 int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
 
 int hci_remote_oob_data_clear(struct hci_dev *hdev);
@@ -674,6 +719,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
 #define lmp_ssp_capable(dev)       ((dev)->features[6] & LMP_SIMPLE_PAIR)
 #define lmp_no_flush_capable(dev)  ((dev)->features[6] & LMP_NO_FLUSH)
 #define lmp_le_capable(dev)        ((dev)->features[4] & LMP_LE)
+#define lmp_bredr_capable(dev)     (!((dev)->features[4] & LMP_NO_BREDR))
 
 /* ----- Extended LMP capabilities ----- */
 #define lmp_host_le_capable(dev)   ((dev)->host_features[0] & LMP_HOST_LE)
@@ -755,7 +801,7 @@ static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status)
        if (conn->type != ACL_LINK && conn->type != LE_LINK)
                return;
 
-       if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
+       if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags))
                return;
 
        encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00;
@@ -796,7 +842,7 @@ static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status)
 
        hci_proto_auth_cfm(conn, status);
 
-       if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
+       if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags))
                return;
 
        encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00;
@@ -859,25 +905,71 @@ static inline void hci_role_switch_cfm(struct hci_conn *conn, __u8 status,
        read_unlock(&hci_cb_list_lock);
 }
 
+static inline bool eir_has_data_type(u8 *data, size_t data_len, u8 type)
+{
+       u8 field_len;
+       size_t parsed;
+
+       for (parsed = 0; parsed < data_len - 1; parsed += field_len) {
+               field_len = data[0];
+
+               if (field_len == 0)
+                       break;
+
+               parsed += field_len + 1;
+
+               if (parsed > data_len)
+                       break;
+
+               if (data[1] == type)
+                       return true;
+
+               data += field_len + 1;
+       }
+
+       return false;
+}
+
+static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
+                                 u8 data_len)
+{
+       eir[eir_len++] = sizeof(type) + data_len;
+       eir[eir_len++] = type;
+       memcpy(&eir[eir_len], data, data_len);
+       eir_len += data_len;
+
+       return eir_len;
+}
+
 int hci_register_cb(struct hci_cb *hcb);
 int hci_unregister_cb(struct hci_cb *hcb);
 
-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_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);
 
-void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data);
-
 /* ----- HCI Sockets ----- */
-void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb,
-                                                       struct sock *skip_sk);
+void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb);
+void hci_send_to_control(struct sk_buff *skb, struct sock *skip_sk);
+void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb);
+
+void hci_sock_dev_event(struct hci_dev *hdev, int event);
 
 /* Management interface */
+#define MGMT_ADDR_BREDR                        0x00
+#define MGMT_ADDR_LE_PUBLIC            0x01
+#define MGMT_ADDR_LE_RANDOM            0x02
+#define MGMT_ADDR_INVALID              0xff
+
+#define DISCOV_TYPE_BREDR              (BIT(MGMT_ADDR_BREDR))
+#define DISCOV_TYPE_LE                 (BIT(MGMT_ADDR_LE_PUBLIC) | \
+                                               BIT(MGMT_ADDR_LE_RANDOM))
+#define DISCOV_TYPE_INTERLEAVED                (BIT(MGMT_ADDR_BREDR) | \
+                                               BIT(MGMT_ADDR_LE_PUBLIC) | \
+                                               BIT(MGMT_ADDR_LE_RANDOM))
+
 int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len);
 int mgmt_index_added(struct hci_dev *hdev);
 int mgmt_index_removed(struct hci_dev *hdev);
@@ -886,56 +978,67 @@ 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 link_type,
-                                                               u8 addr_type);
-int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
-                                                               u8 addr_type);
-int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status);
+                     u8 persistent);
+int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
+                         u8 addr_type, u32 flags, u8 *name, u8 name_len,
+                         u8 *dev_class);
+int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                            u8 link_type, u8 addr_type);
+int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                          u8 link_type, u8 addr_type, u8 status);
 int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
-                                               u8 addr_type, u8 status);
+                       u8 addr_type, u8 status);
 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);
+                                u8 status);
 int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
-                                                               u8 status);
+                                    u8 status);
 int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
-                                               __le32 value, u8 confirm_hint);
+                             u8 link_type, u8 addr_type, __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_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr);
+                                    u8 link_type, u8 addr_type, u8 status);
+int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                        u8 link_type, u8 addr_type, u8 status);
+int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                             u8 link_type, u8 addr_type);
 int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
-                                                               u8 status);
-int mgmt_user_passkey_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);
+                                    u8 link_type, u8 addr_type, u8 status);
+int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                        u8 link_type, u8 addr_type, u8 status);
+int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
+                    u8 addr_type, u8 status);
+int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status);
+int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status);
+int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
+                                  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);
+                                           u8 *randomizer, u8 status);
+int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status);
 int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
-                               u8 addr_type, u8 *dev_class, s8 rssi, u8 *eir);
-int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name);
+                     u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name,
+                     u8 ssp, u8 *eir, u16 eir_len);
+int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
+                    u8 addr_type, s8 rssi, u8 *name, u8 name_len);
 int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status);
 int mgmt_stop_discovery_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);
+int mgmt_interleaved_discovery(struct hci_dev *hdev);
+int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
+int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
+
+int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent);
 
 /* HCI info for socket */
 #define hci_pi(sk) ((struct hci_pinfo *) sk)
 
-/* HCI socket flags */
-#define HCI_PI_MGMT_INIT       0
-
 struct hci_pinfo {
        struct bt_sock    bt;
        struct hci_dev    *hdev;
        struct hci_filter filter;
        __u32             cmsg_mask;
        unsigned short   channel;
-       unsigned long     flags;
 };
 
 /* HCI security filter */
@@ -966,5 +1069,7 @@ 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);
+int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window,
+               int timeout);
 
 #endif /* __HCI_CORE_H */
diff --git a/include/net/bluetooth/hci_mon.h b/include/net/bluetooth/hci_mon.h
new file mode 100644 (file)
index 0000000..77d1e57
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+   BlueZ - Bluetooth protocol stack for Linux
+
+   Copyright (C) 2011-2012  Intel Corporation
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
+   SOFTWARE IS DISCLAIMED.
+*/
+
+#ifndef __HCI_MON_H
+#define __HCI_MON_H
+
+struct hci_mon_hdr {
+       __le16  opcode;
+       __le16  index;
+       __le16  len;
+} __packed;
+#define HCI_MON_HDR_SIZE 6
+
+#define HCI_MON_NEW_INDEX      0
+#define HCI_MON_DEL_INDEX      1
+#define HCI_MON_COMMAND_PKT    2
+#define HCI_MON_EVENT_PKT      3
+#define HCI_MON_ACL_TX_PKT     4
+#define HCI_MON_ACL_RX_PKT     5
+#define HCI_MON_SCO_TX_PKT     6
+#define HCI_MON_SCO_RX_PKT     7
+
+struct hci_mon_new_index {
+       __u8            type;
+       __u8            bus;
+       bdaddr_t        bdaddr;
+       char            name[8];
+} __packed;
+#define HCI_MON_NEW_INDEX_SIZE 16
+
+#endif /* __HCI_MON_H */
index b1664ed884e68c461088217b9d97915e519592f0..9b242c6bf55b2d9ecf8b0bebb725a45b1a7ee947 100644 (file)
 #define L2CAP_DEFAULT_SDU_ITIME                0xFFFFFFFF
 #define L2CAP_DEFAULT_ACC_LAT          0xFFFFFFFF
 
-#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 */
+#define L2CAP_DISC_TIMEOUT             msecs_to_jiffies(100)
+#define L2CAP_DISC_REJ_TIMEOUT         msecs_to_jiffies(5000)
+#define L2CAP_ENC_TIMEOUT              msecs_to_jiffies(5000)
+#define L2CAP_CONN_TIMEOUT             msecs_to_jiffies(40000)
+#define L2CAP_INFO_TIMEOUT             msecs_to_jiffies(4000)
 
 /* L2CAP socket address */
 struct sockaddr_l2 {
@@ -492,51 +492,56 @@ struct l2cap_chan {
        struct sk_buff_head     srej_q;
        struct list_head        srej_l;
 
-       struct list_head list;
-       struct list_head global_l;
+       struct list_head        list;
+       struct list_head        global_l;
 
-       void            *data;
-       struct l2cap_ops *ops;
+       void                    *data;
+       struct l2cap_ops        *ops;
+       struct mutex            lock;
 };
 
 struct l2cap_ops {
-       char            *name;
+       char                    *name;
 
        struct l2cap_chan       *(*new_connection) (void *data);
        int                     (*recv) (void *data, struct sk_buff *skb);
        void                    (*close) (void *data);
        void                    (*state_change) (void *data, int state);
+       struct sk_buff          *(*alloc_skb) (struct l2cap_chan *chan,
+                                       unsigned long len, int nb, int *err);
+
 };
 
 struct l2cap_conn {
-       struct hci_conn *hcon;
-       struct hci_chan *hchan;
+       struct hci_conn         *hcon;
+       struct hci_chan         *hchan;
 
-       bdaddr_t        *dst;
-       bdaddr_t        *src;
+       bdaddr_t                *dst;
+       bdaddr_t                *src;
 
-       unsigned int    mtu;
+       unsigned int            mtu;
 
-       __u32           feat_mask;
+       __u32                   feat_mask;
+       __u8                    fixed_chan_mask;
 
-       __u8            info_state;
-       __u8            info_ident;
+       __u8                    info_state;
+       __u8                    info_ident;
 
-       struct delayed_work info_timer;
+       struct delayed_work     info_timer;
 
-       spinlock_t      lock;
+       spinlock_t              lock;
 
-       struct sk_buff *rx_skb;
-       __u32           rx_len;
-       __u8            tx_ident;
+       struct sk_buff          *rx_skb;
+       __u32                   rx_len;
+       __u8                    tx_ident;
 
-       __u8            disc_reason;
+       __u8                    disc_reason;
 
-       struct delayed_work  security_timer;
-       struct smp_chan *smp_chan;
+       struct delayed_work     security_timer;
+       struct smp_chan         *smp_chan;
 
-       struct list_head chan_l;
-       struct mutex    chan_lock;
+       struct list_head        chan_l;
+       struct mutex            chan_lock;
 };
 
 #define L2CAP_INFO_CL_MTU_REQ_SENT     0x01
@@ -551,9 +556,9 @@ struct l2cap_conn {
 #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk)
 
 struct l2cap_pinfo {
-       struct bt_sock  bt;
+       struct bt_sock          bt;
        struct l2cap_chan       *chan;
-       struct sk_buff  *rx_busy_skb;
+       struct sk_buff          *rx_busy_skb;
 };
 
 enum {
@@ -606,21 +611,37 @@ static inline void l2cap_chan_put(struct l2cap_chan *c)
                kfree(c);
 }
 
+static inline void l2cap_chan_lock(struct l2cap_chan *chan)
+{
+       mutex_lock(&chan->lock);
+}
+
+static inline void l2cap_chan_unlock(struct l2cap_chan *chan)
+{
+       mutex_unlock(&chan->lock);
+}
+
 static inline void l2cap_set_timer(struct l2cap_chan *chan,
                                        struct delayed_work *work, long timeout)
 {
-       BT_DBG("chan %p state %d timeout %ld", chan, chan->state, timeout);
+       BT_DBG("chan %p state %s timeout %ld", chan,
+                                       state_to_string(chan->state), timeout);
 
        if (!cancel_delayed_work(work))
                l2cap_chan_hold(chan);
        schedule_delayed_work(work, timeout);
 }
 
-static inline void l2cap_clear_timer(struct l2cap_chan *chan,
+static inline bool l2cap_clear_timer(struct l2cap_chan *chan,
                                        struct delayed_work *work)
 {
-       if (cancel_delayed_work(work))
+       bool ret;
+
+       ret = cancel_delayed_work(work);
+       if (ret)
                l2cap_chan_put(chan);
+
+       return ret;
 }
 
 #define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t))
index be65d34178839e6426f245ab64a6f4c55ad3e826..ffc1377e092eb2a9b15b91a799e4e18672b10bb6 100644 (file)
@@ -2,6 +2,7 @@
    BlueZ - Bluetooth protocol stack for Linux
 
    Copyright (C) 2010  Nokia Corporation
+   Copyright (C) 2011-2012  Intel Corporation
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License version 2 as
 #define MGMT_STATUS_INVALID_PARAMS     0x0d
 #define MGMT_STATUS_DISCONNECTED       0x0e
 #define MGMT_STATUS_NOT_POWERED                0x0f
+#define MGMT_STATUS_CANCELLED          0x10
+#define MGMT_STATUS_INVALID_INDEX      0x11
 
 struct mgmt_hdr {
-       __le16 opcode;
-       __le16 index;
-       __le16 len;
+       __le16  opcode;
+       __le16  index;
+       __le16  len;
 } __packed;
 
+struct mgmt_addr_info {
+       bdaddr_t        bdaddr;
+       __u8            type;
+} __packed;
+#define MGMT_ADDR_INFO_SIZE            7
+
 #define MGMT_OP_READ_VERSION           0x0001
+#define MGMT_READ_VERSION_SIZE         0
 struct mgmt_rp_read_version {
-       __u8 version;
-       __le16 revision;
+       __u8    version;
+       __le16  revision;
+} __packed;
+
+#define MGMT_OP_READ_COMMANDS          0x0002
+#define MGMT_READ_COMMANDS_SIZE                0
+struct mgmt_rp_read_commands {
+       __le16  num_commands;
+       __le16  num_events;
+       __le16  opcodes[0];
 } __packed;
 
 #define MGMT_OP_READ_INDEX_LIST                0x0003
+#define MGMT_READ_INDEX_LIST_SIZE      0
 struct mgmt_rp_read_index_list {
-       __le16 num_controllers;
-       __le16 index[0];
+       __le16  num_controllers;
+       __le16  index[0];
 } __packed;
 
 /* Reserve one extra byte for names in management messages so that they
  * are always guaranteed to be nul-terminated */
 #define MGMT_MAX_NAME_LENGTH           (HCI_MAX_NAME_LENGTH + 1)
-#define MGMT_MAX_SHORT_NAME_LENGTH     (10 + 1)
+#define MGMT_MAX_SHORT_NAME_LENGTH     (HCI_MAX_SHORT_NAME_LENGTH + 1)
 
 #define MGMT_SETTING_POWERED           0x00000001
 #define MGMT_SETTING_CONNECTABLE       0x00000002
@@ -75,28 +94,32 @@ struct mgmt_rp_read_index_list {
 #define MGMT_SETTING_LE                        0x00000200
 
 #define MGMT_OP_READ_INFO              0x0004
+#define MGMT_READ_INFO_SIZE            0
 struct mgmt_rp_read_info {
-       bdaddr_t bdaddr;
-       __u8 version;
-       __le16 manufacturer;
-       __le32 supported_settings;
-       __le32 current_settings;
-       __u8 dev_class[3];
-       __u8 name[MGMT_MAX_NAME_LENGTH];
-       __u8 short_name[MGMT_MAX_SHORT_NAME_LENGTH];
+       bdaddr_t        bdaddr;
+       __u8            version;
+       __le16          manufacturer;
+       __le32          supported_settings;
+       __le32          current_settings;
+       __u8            dev_class[3];
+       __u8            name[MGMT_MAX_NAME_LENGTH];
+       __u8            short_name[MGMT_MAX_SHORT_NAME_LENGTH];
 } __packed;
 
 struct mgmt_mode {
        __u8 val;
 } __packed;
 
+#define MGMT_SETTING_SIZE              1
+
 #define MGMT_OP_SET_POWERED            0x0005
 
 #define MGMT_OP_SET_DISCOVERABLE       0x0006
 struct mgmt_cp_set_discoverable {
-       __u8 val;
-       __u16 timeout;
+       __u8    val;
+       __u16   timeout;
 } __packed;
+#define MGMT_SET_DISCOVERABLE_SIZE     3
 
 #define MGMT_OP_SET_CONNECTABLE                0x0007
 
@@ -111,73 +134,76 @@ struct mgmt_cp_set_discoverable {
 #define MGMT_OP_SET_HS                 0x000C
 
 #define MGMT_OP_SET_LE                 0x000D
-
 #define MGMT_OP_SET_DEV_CLASS          0x000E
 struct mgmt_cp_set_dev_class {
-       __u8 major;
-       __u8 minor;
+       __u8    major;
+       __u8    minor;
 } __packed;
+#define MGMT_SET_DEV_CLASS_SIZE                2
 
 #define MGMT_OP_SET_LOCAL_NAME         0x000F
 struct mgmt_cp_set_local_name {
-       __u8 name[MGMT_MAX_NAME_LENGTH];
+       __u8    name[MGMT_MAX_NAME_LENGTH];
+       __u8    short_name[MGMT_MAX_SHORT_NAME_LENGTH];
 } __packed;
+#define MGMT_SET_LOCAL_NAME_SIZE       260
 
 #define MGMT_OP_ADD_UUID               0x0010
 struct mgmt_cp_add_uuid {
-       __u8 uuid[16];
-       __u8 svc_hint;
+       __u8    uuid[16];
+       __u8    svc_hint;
 } __packed;
+#define MGMT_ADD_UUID_SIZE             17
 
 #define MGMT_OP_REMOVE_UUID            0x0011
 struct mgmt_cp_remove_uuid {
-       __u8 uuid[16];
+       __u8    uuid[16];
 } __packed;
+#define MGMT_REMOVE_UUID_SIZE          16
 
 struct mgmt_link_key_info {
-       bdaddr_t bdaddr;
-       u8 type;
-       u8 val[16];
-       u8 pin_len;
+       struct mgmt_addr_info addr;
+       __u8    type;
+       __u8    val[16];
+       __u8    pin_len;
 } __packed;
 
 #define MGMT_OP_LOAD_LINK_KEYS         0x0012
 struct mgmt_cp_load_link_keys {
-       __u8 debug_keys;
-       __le16 key_count;
-       struct mgmt_link_key_info keys[0];
+       __u8    debug_keys;
+       __le16  key_count;
+       struct  mgmt_link_key_info keys[0];
 } __packed;
+#define MGMT_LOAD_LINK_KEYS_SIZE       3
 
-#define MGMT_OP_REMOVE_KEYS            0x0013
-struct mgmt_cp_remove_keys {
-       bdaddr_t bdaddr;
-       __u8 disconnect;
+struct mgmt_ltk_info {
+       struct mgmt_addr_info addr;
+       __u8    authenticated;
+       __u8    master;
+       __u8    enc_size;
+       __le16  ediv;
+       __u8    rand[8];
+       __u8    val[16];
 } __packed;
-struct mgmt_rp_remove_keys {
-       bdaddr_t bdaddr;
-       __u8 status;
-};
+
+#define MGMT_OP_LOAD_LONG_TERM_KEYS    0x0013
+struct mgmt_cp_load_long_term_keys {
+       __le16  key_count;
+       struct  mgmt_ltk_info keys[0];
+} __packed;
+#define MGMT_LOAD_LONG_TERM_KEYS_SIZE  2
 
 #define MGMT_OP_DISCONNECT             0x0014
 struct mgmt_cp_disconnect {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
 } __packed;
+#define MGMT_DISCONNECT_SIZE           MGMT_ADDR_INFO_SIZE
 struct mgmt_rp_disconnect {
-       bdaddr_t bdaddr;
-       __u8 status;
-} __packed;
-
-#define MGMT_ADDR_BREDR                        0x00
-#define MGMT_ADDR_LE_PUBLIC            0x01
-#define MGMT_ADDR_LE_RANDOM            0x02
-#define MGMT_ADDR_INVALID              0xff
-
-struct mgmt_addr_info {
-       bdaddr_t bdaddr;
-       __u8 type;
+       struct mgmt_addr_info addr;
 } __packed;
 
 #define MGMT_OP_GET_CONNECTIONS                0x0015
+#define MGMT_GET_CONNECTIONS_SIZE      0
 struct mgmt_rp_get_connections {
        __le16 conn_count;
        struct mgmt_addr_info addr[0];
@@ -185,124 +211,152 @@ struct mgmt_rp_get_connections {
 
 #define MGMT_OP_PIN_CODE_REPLY         0x0016
 struct mgmt_cp_pin_code_reply {
-       bdaddr_t bdaddr;
-       __u8 pin_len;
-       __u8 pin_code[16];
+       struct mgmt_addr_info addr;
+       __u8    pin_len;
+       __u8    pin_code[16];
 } __packed;
+#define MGMT_PIN_CODE_REPLY_SIZE       (MGMT_ADDR_INFO_SIZE + 17)
 struct mgmt_rp_pin_code_reply {
-       bdaddr_t bdaddr;
-       uint8_t status;
+       struct mgmt_addr_info addr;
 } __packed;
 
 #define MGMT_OP_PIN_CODE_NEG_REPLY     0x0017
 struct mgmt_cp_pin_code_neg_reply {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
 } __packed;
+#define MGMT_PIN_CODE_NEG_REPLY_SIZE   MGMT_ADDR_INFO_SIZE
 
 #define MGMT_OP_SET_IO_CAPABILITY      0x0018
 struct mgmt_cp_set_io_capability {
-       __u8 io_capability;
+       __u8    io_capability;
 } __packed;
+#define MGMT_SET_IO_CAPABILITY_SIZE    1
 
 #define MGMT_OP_PAIR_DEVICE            0x0019
 struct mgmt_cp_pair_device {
        struct mgmt_addr_info addr;
-       __u8 io_cap;
+       __u8    io_cap;
 } __packed;
+#define MGMT_PAIR_DEVICE_SIZE          (MGMT_ADDR_INFO_SIZE + 1)
 struct mgmt_rp_pair_device {
        struct mgmt_addr_info addr;
-       __u8 status;
 } __packed;
 
-#define MGMT_OP_USER_CONFIRM_REPLY     0x001A
+#define MGMT_OP_CANCEL_PAIR_DEVICE     0x001A
+#define MGMT_CANCEL_PAIR_DEVICE_SIZE   MGMT_ADDR_INFO_SIZE
+
+#define MGMT_OP_UNPAIR_DEVICE          0x001B
+struct mgmt_cp_unpair_device {
+       struct mgmt_addr_info addr;
+       __u8 disconnect;
+} __packed;
+#define MGMT_UNPAIR_DEVICE_SIZE                (MGMT_ADDR_INFO_SIZE + 1)
+struct mgmt_rp_unpair_device {
+       struct mgmt_addr_info addr;
+};
+
+#define MGMT_OP_USER_CONFIRM_REPLY     0x001C
 struct mgmt_cp_user_confirm_reply {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
 } __packed;
+#define MGMT_USER_CONFIRM_REPLY_SIZE   MGMT_ADDR_INFO_SIZE
 struct mgmt_rp_user_confirm_reply {
-       bdaddr_t bdaddr;
-       __u8 status;
+       struct mgmt_addr_info addr;
 } __packed;
 
-#define MGMT_OP_USER_CONFIRM_NEG_REPLY 0x001B
+#define MGMT_OP_USER_CONFIRM_NEG_REPLY 0x001D
 struct mgmt_cp_user_confirm_neg_reply {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
 } __packed;
+#define MGMT_USER_CONFIRM_NEG_REPLY_SIZE MGMT_ADDR_INFO_SIZE
 
-#define MGMT_OP_USER_PASSKEY_REPLY     0x001C
+#define MGMT_OP_USER_PASSKEY_REPLY     0x001E
 struct mgmt_cp_user_passkey_reply {
-       bdaddr_t bdaddr;
-       __le32 passkey;
+       struct mgmt_addr_info addr;
+       __le32  passkey;
 } __packed;
+#define MGMT_USER_PASSKEY_REPLY_SIZE   (MGMT_ADDR_INFO_SIZE + 4)
 struct mgmt_rp_user_passkey_reply {
-       bdaddr_t bdaddr;
-       __u8 status;
+       struct mgmt_addr_info addr;
 } __packed;
 
-#define MGMT_OP_USER_PASSKEY_NEG_REPLY 0x001D
+#define MGMT_OP_USER_PASSKEY_NEG_REPLY 0x001F
 struct mgmt_cp_user_passkey_neg_reply {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
 } __packed;
+#define MGMT_USER_PASSKEY_NEG_REPLY_SIZE MGMT_ADDR_INFO_SIZE
 
-#define MGMT_OP_READ_LOCAL_OOB_DATA    0x001E
+#define MGMT_OP_READ_LOCAL_OOB_DATA    0x0020
+#define MGMT_READ_LOCAL_OOB_DATA_SIZE  0
 struct mgmt_rp_read_local_oob_data {
-       __u8 hash[16];
-       __u8 randomizer[16];
+       __u8    hash[16];
+       __u8    randomizer[16];
 } __packed;
 
-#define MGMT_OP_ADD_REMOTE_OOB_DATA    0x001F
+#define MGMT_OP_ADD_REMOTE_OOB_DATA    0x0021
 struct mgmt_cp_add_remote_oob_data {
-       bdaddr_t bdaddr;
-       __u8 hash[16];
-       __u8 randomizer[16];
+       struct mgmt_addr_info addr;
+       __u8    hash[16];
+       __u8    randomizer[16];
 } __packed;
+#define MGMT_ADD_REMOTE_OOB_DATA_SIZE  (MGMT_ADDR_INFO_SIZE + 32)
 
-#define MGMT_OP_REMOVE_REMOTE_OOB_DATA 0x0020
+#define MGMT_OP_REMOVE_REMOTE_OOB_DATA 0x0022
 struct mgmt_cp_remove_remote_oob_data {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
 } __packed;
+#define MGMT_REMOVE_REMOTE_OOB_DATA_SIZE MGMT_ADDR_INFO_SIZE
 
-#define MGMT_OP_START_DISCOVERY                0x0021
+#define MGMT_OP_START_DISCOVERY                0x0023
 struct mgmt_cp_start_discovery {
        __u8 type;
 } __packed;
+#define MGMT_START_DISCOVERY_SIZE      1
 
-#define MGMT_OP_STOP_DISCOVERY         0x0022
+#define MGMT_OP_STOP_DISCOVERY         0x0024
+struct mgmt_cp_stop_discovery {
+       __u8 type;
+} __packed;
+#define MGMT_STOP_DISCOVERY_SIZE       1
 
-#define MGMT_OP_CONFIRM_NAME           0x0023
+#define MGMT_OP_CONFIRM_NAME           0x0025
 struct mgmt_cp_confirm_name {
-       bdaddr_t bdaddr;
-       __u8 name_known;
+       struct mgmt_addr_info addr;
+       __u8    name_known;
 } __packed;
+#define MGMT_CONFIRM_NAME_SIZE         (MGMT_ADDR_INFO_SIZE + 1)
 struct mgmt_rp_confirm_name {
-       bdaddr_t bdaddr;
-       __u8 status;
+       struct mgmt_addr_info addr;
 } __packed;
 
-#define MGMT_OP_BLOCK_DEVICE           0x0024
+#define MGMT_OP_BLOCK_DEVICE           0x0026
 struct mgmt_cp_block_device {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
 } __packed;
+#define MGMT_BLOCK_DEVICE_SIZE         MGMT_ADDR_INFO_SIZE
 
-#define MGMT_OP_UNBLOCK_DEVICE         0x0025
+#define MGMT_OP_UNBLOCK_DEVICE         0x0027
 struct mgmt_cp_unblock_device {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
 } __packed;
+#define MGMT_UNBLOCK_DEVICE_SIZE       MGMT_ADDR_INFO_SIZE
 
 #define MGMT_EV_CMD_COMPLETE           0x0001
 struct mgmt_ev_cmd_complete {
-       __le16 opcode;
-       __u8 data[0];
+       __le16  opcode;
+       __u8    status;
+       __u8    data[0];
 } __packed;
 
 #define MGMT_EV_CMD_STATUS             0x0002
 struct mgmt_ev_cmd_status {
-       __u8 status;
-       __le16 opcode;
+       __le16  opcode;
+       __u8    status;
 } __packed;
 
 #define MGMT_EV_CONTROLLER_ERROR       0x0003
 struct mgmt_ev_controller_error {
-       __u8 error_code;
+       __u8    error_code;
 } __packed;
 
 #define MGMT_EV_INDEX_ADDED            0x0004
@@ -313,78 +367,96 @@ struct mgmt_ev_controller_error {
 
 #define MGMT_EV_CLASS_OF_DEV_CHANGED   0x0007
 struct mgmt_ev_class_of_dev_changed {
-       __u8 dev_class[3];
+       __u8    dev_class[3];
 };
 
 #define MGMT_EV_LOCAL_NAME_CHANGED     0x0008
 struct mgmt_ev_local_name_changed {
-       __u8 name[MGMT_MAX_NAME_LENGTH];
-       __u8 short_name[MGMT_MAX_SHORT_NAME_LENGTH];
+       __u8    name[MGMT_MAX_NAME_LENGTH];
+       __u8    short_name[MGMT_MAX_SHORT_NAME_LENGTH];
 } __packed;
 
 #define MGMT_EV_NEW_LINK_KEY           0x0009
 struct mgmt_ev_new_link_key {
-       __u8 store_hint;
+       __u8    store_hint;
        struct mgmt_link_key_info key;
 } __packed;
 
-#define MGMT_EV_CONNECTED              0x000A
+#define MGMT_EV_NEW_LONG_TERM_KEY      0x000A
+struct mgmt_ev_new_long_term_key {
+       __u8    store_hint;
+       struct mgmt_ltk_info key;
+} __packed;
 
-#define MGMT_EV_DISCONNECTED           0x000B
+#define MGMT_EV_DEVICE_CONNECTED       0x000B
+struct mgmt_ev_device_connected {
+       struct mgmt_addr_info addr;
+       __le32  flags;
+       __le16  eir_len;
+       __u8    eir[0];
+} __packed;
+
+#define MGMT_EV_DEVICE_DISCONNECTED    0x000C
 
-#define MGMT_EV_CONNECT_FAILED         0x000C
+#define MGMT_EV_CONNECT_FAILED         0x000D
 struct mgmt_ev_connect_failed {
        struct mgmt_addr_info addr;
-       __u8 status;
+       __u8    status;
 } __packed;
 
-#define MGMT_EV_PIN_CODE_REQUEST       0x000D
+#define MGMT_EV_PIN_CODE_REQUEST       0x000E
 struct mgmt_ev_pin_code_request {
-       bdaddr_t bdaddr;
-       __u8 secure;
+       struct mgmt_addr_info addr;
+       __u8    secure;
 } __packed;
 
-#define MGMT_EV_USER_CONFIRM_REQUEST   0x000E
+#define MGMT_EV_USER_CONFIRM_REQUEST   0x000F
 struct mgmt_ev_user_confirm_request {
-       bdaddr_t bdaddr;
-       __u8 confirm_hint;
-       __le32 value;
+       struct mgmt_addr_info addr;
+       __u8    confirm_hint;
+       __le32  value;
 } __packed;
 
-#define MGMT_EV_USER_PASSKEY_REQUEST   0x000F
+#define MGMT_EV_USER_PASSKEY_REQUEST   0x0010
 struct mgmt_ev_user_passkey_request {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
 } __packed;
 
-#define MGMT_EV_AUTH_FAILED            0x0010
+#define MGMT_EV_AUTH_FAILED            0x0011
 struct mgmt_ev_auth_failed {
-       bdaddr_t bdaddr;
-       __u8 status;
+       struct mgmt_addr_info addr;
+       __u8    status;
 } __packed;
 
-#define MGMT_EV_DEVICE_FOUND           0x0011
+#define MGMT_DEV_FOUND_CONFIRM_NAME    0x01
+#define MGMT_DEV_FOUND_LEGACY_PAIRING  0x02
+
+#define MGMT_EV_DEVICE_FOUND           0x0012
 struct mgmt_ev_device_found {
        struct mgmt_addr_info addr;
-       __u8 dev_class[3];
-       __s8 rssi;
-       __u8 confirm_name;
-       __u8 eir[HCI_MAX_EIR_LENGTH];
-} __packed;
-
-#define MGMT_EV_REMOTE_NAME            0x0012
-struct mgmt_ev_remote_name {
-       bdaddr_t bdaddr;
-       __u8 name[MGMT_MAX_NAME_LENGTH];
+       __s8    rssi;
+       __u8    flags[4];
+       __le16  eir_len;
+       __u8    eir[0];
 } __packed;
 
 #define MGMT_EV_DISCOVERING            0x0013
+struct mgmt_ev_discovering {
+       __u8    type;
+       __u8    discovering;
+} __packed;
 
 #define MGMT_EV_DEVICE_BLOCKED         0x0014
 struct mgmt_ev_device_blocked {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
 } __packed;
 
 #define MGMT_EV_DEVICE_UNBLOCKED       0x0015
 struct mgmt_ev_device_unblocked {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
+} __packed;
+
+#define MGMT_EV_DEVICE_UNPAIRED                0x0016
+struct mgmt_ev_device_unpaired {
+       struct mgmt_addr_info addr;
 } __packed;
index aeaf5fa2b9f15e9c0b6c5cd0ba41af510a012464..7b3acdd29134df26025d4a79460a4d113ad7dabe 100644 (file)
@@ -127,7 +127,7 @@ struct smp_chan {
        u8              rrnd[16]; /* SMP Pairing Random (remote) */
        u8              pcnf[16]; /* SMP Pairing Confirm */
        u8              tk[16]; /* SMP Temporary Key */
-       u8              smp_key_size;
+       u8              enc_key_size;
        unsigned long   smp_flags;
        struct crypto_blkcipher *tfm;
        struct work_struct confirm;
index e0c9ff3a197701b1d21ef975ff6c121a77bb70d4..57c9fddc2acf41514a067622e33cf418d3b3d9a6 100644 (file)
@@ -366,25 +366,13 @@ struct cfg80211_crypto_settings {
 };
 
 /**
- * struct beacon_parameters - beacon parameters
- *
- * Used to configure the beacon for an interface.
- *
+ * struct cfg80211_beacon_data - beacon data
  * @head: head portion of beacon (before TIM IE)
  *     or %NULL if not changed
  * @tail: tail portion of beacon (after TIM IE)
  *     or %NULL if not changed
- * @interval: beacon interval or zero if not changed
- * @dtim_period: DTIM period or zero if not changed
  * @head_len: length of @head
  * @tail_len: length of @tail
- * @ssid: SSID to be used in the BSS (note: may be %NULL if not provided from
- *     user space)
- * @ssid_len: length of @ssid
- * @hidden_ssid: whether to hide the SSID in Beacon/Probe Response frames
- * @crypto: crypto settings
- * @privacy: the BSS uses privacy
- * @auth_type: Authentication type (algorithm)
  * @beacon_ies: extra information element(s) to add into Beacon frames or %NULL
  * @beacon_ies_len: length of beacon_ies in octets
  * @proberesp_ies: extra information element(s) to add into Probe Response
@@ -396,24 +384,48 @@ struct cfg80211_crypto_settings {
  * @probe_resp_len: length of probe response template (@probe_resp)
  * @probe_resp: probe response template (AP mode only)
  */
-struct beacon_parameters {
-       u8 *head, *tail;
-       int interval, dtim_period;
-       int head_len, tail_len;
+struct cfg80211_beacon_data {
+       const u8 *head, *tail;
+       const u8 *beacon_ies;
+       const u8 *proberesp_ies;
+       const u8 *assocresp_ies;
+       const u8 *probe_resp;
+
+       size_t head_len, tail_len;
+       size_t beacon_ies_len;
+       size_t proberesp_ies_len;
+       size_t assocresp_ies_len;
+       size_t probe_resp_len;
+};
+
+/**
+ * struct cfg80211_ap_settings - AP configuration
+ *
+ * Used to configure an AP interface.
+ *
+ * @beacon: beacon data
+ * @beacon_interval: beacon interval
+ * @dtim_period: DTIM period
+ * @ssid: SSID to be used in the BSS (note: may be %NULL if not provided from
+ *     user space)
+ * @ssid_len: length of @ssid
+ * @hidden_ssid: whether to hide the SSID in Beacon/Probe Response frames
+ * @crypto: crypto settings
+ * @privacy: the BSS uses privacy
+ * @auth_type: Authentication type (algorithm)
+ * @inactivity_timeout: time in seconds to determine station's inactivity.
+ */
+struct cfg80211_ap_settings {
+       struct cfg80211_beacon_data beacon;
+
+       int beacon_interval, dtim_period;
        const u8 *ssid;
        size_t ssid_len;
        enum nl80211_hidden_ssid hidden_ssid;
        struct cfg80211_crypto_settings crypto;
        bool privacy;
        enum nl80211_auth_type auth_type;
-       const u8 *beacon_ies;
-       size_t beacon_ies_len;
-       const u8 *proberesp_ies;
-       size_t proberesp_ies_len;
-       const u8 *assocresp_ies;
-       size_t assocresp_ies_len;
-       int probe_resp_len;
-       u8 *probe_resp;
+       int inactivity_timeout;
 };
 
 /**
@@ -799,6 +811,7 @@ struct mesh_config {
         * Still keeping the same nomenclature to be in sync with the spec. */
        bool  dot11MeshGateAnnouncementProtocol;
        bool dot11MeshForwarding;
+       s32 rssi_threshold;
 };
 
 /**
@@ -1346,12 +1359,10 @@ struct cfg80211_gtk_rekey_data {
  *
  * @set_rekey_data: give the data necessary for GTK rekeying to the driver
  *
- * @add_beacon: Add a beacon with given parameters, @head, @interval
- *     and @dtim_period will be valid, @tail is optional.
- * @set_beacon: Change the beacon parameters for an access point mode
- *     interface. This should reject the call when no beacon has been
- *     configured.
- * @del_beacon: Remove beacon configuration and stop sending the beacon.
+ * @start_ap: Start acting in AP mode defined by the parameters.
+ * @change_beacon: Change the beacon parameters for an access point mode
+ *     interface. This should reject the call when AP mode wasn't started.
+ * @stop_ap: Stop being an AP, including stopping beaconing.
  *
  * @add_station: Add a new station.
  * @del_station: Remove a station; @mac may be NULL to remove all stations.
@@ -1518,11 +1529,11 @@ struct cfg80211_ops {
                                        struct net_device *netdev,
                                        u8 key_index);
 
-       int     (*add_beacon)(struct wiphy *wiphy, struct net_device *dev,
-                             struct beacon_parameters *info);
-       int     (*set_beacon)(struct wiphy *wiphy, struct net_device *dev,
-                             struct beacon_parameters *info);
-       int     (*del_beacon)(struct wiphy *wiphy, struct net_device *dev);
+       int     (*start_ap)(struct wiphy *wiphy, struct net_device *dev,
+                           struct cfg80211_ap_settings *settings);
+       int     (*change_beacon)(struct wiphy *wiphy, struct net_device *dev,
+                                struct cfg80211_beacon_data *info);
+       int     (*stop_ap)(struct wiphy *wiphy, struct net_device *dev);
 
 
        int     (*add_station)(struct wiphy *wiphy, struct net_device *dev,
@@ -1577,11 +1588,9 @@ struct cfg80211_ops {
        int     (*assoc)(struct wiphy *wiphy, struct net_device *dev,
                         struct cfg80211_assoc_request *req);
        int     (*deauth)(struct wiphy *wiphy, struct net_device *dev,
-                         struct cfg80211_deauth_request *req,
-                         void *cookie);
+                         struct cfg80211_deauth_request *req);
        int     (*disassoc)(struct wiphy *wiphy, struct net_device *dev,
-                           struct cfg80211_disassoc_request *req,
-                           void *cookie);
+                           struct cfg80211_disassoc_request *req);
 
        int     (*connect)(struct wiphy *wiphy, struct net_device *dev,
                           struct cfg80211_connect_params *sme);
@@ -3180,6 +3189,7 @@ void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp);
  * cfg80211_rx_mgmt - notification of received, unprocessed management frame
  * @dev: network device
  * @freq: Frequency on which the frame was received in MHz
+ * @sig_dbm: signal strength in mBm, or 0 if unknown
  * @buf: Management frame (header + body)
  * @len: length of the frame data
  * @gfp: context flags
@@ -3192,8 +3202,8 @@ void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp);
  * This function is called whenever an Action frame is received for a station
  * mode interface, but is not processed in kernel.
  */
-bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf,
-                     size_t len, gfp_t gfp);
+bool cfg80211_rx_mgmt(struct net_device *dev, int freq, int sig_dbm,
+                     const u8 *buf, size_t len, gfp_t gfp);
 
 /**
  * cfg80211_mgmt_tx_status - notification of TX status for management frame
@@ -3306,6 +3316,7 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
  * @frame: the frame
  * @len: length of the frame
  * @freq: frequency the frame was received on
+ * @sig_dbm: signal strength in mBm, or 0 if unknown
  * @gfp: allocation flags
  *
  * Use this function to report to userspace when a beacon was
@@ -3314,7 +3325,7 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
  */
 void cfg80211_report_obss_beacon(struct wiphy *wiphy,
                                 const u8 *frame, size_t len,
-                                int freq, gfp_t gfp);
+                                int freq, int sig_dbm, gfp_t gfp);
 
 /*
  * cfg80211_can_beacon_sec_chan - test if ht40 on extension channel can be used
@@ -3326,6 +3337,14 @@ int cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
                                 struct ieee80211_channel *chan,
                                 enum nl80211_channel_type channel_type);
 
+/*
+ * cfg80211_calculate_bitrate - calculate actual bitrate (in 100Kbps units)
+ * @rate: given rate_info to calculate bitrate from
+ *
+ * return 0 if MCS index >= 32
+ */
+u16 cfg80211_calculate_bitrate(struct rate_info *rate);
+
 /* Logging, debugging and troubleshooting/diagnostic helpers. */
 
 /* wiphy_printk helpers, similar to dev_printk */
index 06b795dd5906720886376b6e355dd13027ee6749..b94765e38e8074aa5a877c90b395f0bc8cb6bb4a 100644 (file)
@@ -35,12 +35,12 @@ struct inet_peer {
 
        u32                     metrics[RTAX_MAX];
        u32                     rate_tokens;    /* rate limiting for ICMP */
-       int                     redirect_genid;
        unsigned long           rate_last;
        unsigned long           pmtu_expires;
        u32                     pmtu_orig;
        u32                     pmtu_learned;
        struct inetpeer_addr_base redirect_learned;
+       struct list_head        gc_list;
        /*
         * Once inet_peer is queued for deletion (refcnt == -1), following fields
         * are not available: rid, ip_id_count, tcp_ts, tcp_ts_stamp
@@ -96,6 +96,8 @@ static inline struct inet_peer *inet_getpeer_v6(const struct in6_addr *v6daddr,
 extern void inet_putpeer(struct inet_peer *p);
 extern bool inet_peer_xrlim_allow(struct inet_peer *peer, int timeout);
 
+extern void inetpeer_invalidate_tree(int family);
+
 /*
  * temporary check to make sure we dont access rid, ip_id_count, tcp_ts,
  * tcp_ts_stamp if no refcount is taken on inet_peer
index 775009f9eaba4870b8bcd3b83a4eb67af889b772..b53d65f24f7be8497b60475952d5a66c579aee68 100644 (file)
@@ -388,7 +388,7 @@ static inline int sk_mc_loop(struct sock *sk)
        return 1;
 }
 
-extern int     ip_call_ra_chain(struct sk_buff *skb);
+extern bool ip_call_ra_chain(struct sk_buff *skb);
 
 /*
  *     Functions provided by ip_fragment.c
index 2e1d5ecc2d1b0c82a430690ac68d199613586052..cc7c19732389dba327a92742de4cfeba96b5903e 100644 (file)
@@ -62,6 +62,7 @@ struct sock_msg_q {
 #define AF_IUCV_FLAG_SYN 0x2
 #define AF_IUCV_FLAG_FIN 0x4
 #define AF_IUCV_FLAG_WIN 0x8
+#define AF_IUCV_FLAG_SHT 0x10
 
 struct af_iucv_trans_hdr {
        u16 magic;
index cbff4f94a2002465db85e0143175e1ccef6c7f2f..f7917f765cbcaf48fb9e7b6298efe7bec965415d 100644 (file)
@@ -341,9 +341,9 @@ struct ieee80211_bss_conf {
  *     used to indicate that a frame was already retried due to PS
  * @IEEE80211_TX_INTFL_DONT_ENCRYPT: completely internal to mac80211,
  *     used to indicate frame should not be encrypted
- * @IEEE80211_TX_CTL_POLL_RESPONSE: This frame is a response to a poll
- *     frame (PS-Poll or uAPSD) and should be sent although the station
- *     is in powersave mode.
+ * @IEEE80211_TX_CTL_NO_PS_BUFFER: This frame is a response to a poll
+ *     frame (PS-Poll or uAPSD) or a non-bufferable MMPDU and must
+ *     be sent although the station is in powersave mode.
  * @IEEE80211_TX_CTL_MORE_FRAMES: More frames will be passed to the
  *     transmit function after the current frame, this can be used
  *     by drivers to kick the DMA queue only if unset or when the
@@ -399,7 +399,7 @@ enum mac80211_tx_control_flags {
        IEEE80211_TX_INTFL_NEED_TXPROCESSING    = BIT(14),
        IEEE80211_TX_INTFL_RETRIED              = BIT(15),
        IEEE80211_TX_INTFL_DONT_ENCRYPT         = BIT(16),
-       IEEE80211_TX_CTL_POLL_RESPONSE          = BIT(17),
+       IEEE80211_TX_CTL_NO_PS_BUFFER           = BIT(17),
        IEEE80211_TX_CTL_MORE_FRAMES            = BIT(18),
        IEEE80211_TX_INTFL_RETRANSMISSION       = BIT(19),
        /* hole at 20, use later */
@@ -425,7 +425,7 @@ enum mac80211_tx_control_flags {
        IEEE80211_TX_CTL_SEND_AFTER_DTIM | IEEE80211_TX_CTL_AMPDU |           \
        IEEE80211_TX_STAT_TX_FILTERED | IEEE80211_TX_STAT_ACK |               \
        IEEE80211_TX_STAT_AMPDU | IEEE80211_TX_STAT_AMPDU_NO_BACK |           \
-       IEEE80211_TX_CTL_RATE_CTRL_PROBE | IEEE80211_TX_CTL_POLL_RESPONSE |   \
+       IEEE80211_TX_CTL_RATE_CTRL_PROBE | IEEE80211_TX_CTL_NO_PS_BUFFER |    \
        IEEE80211_TX_CTL_MORE_FRAMES | IEEE80211_TX_CTL_LDPC |                \
        IEEE80211_TX_CTL_STBC | IEEE80211_TX_STATUS_EOSP)
 
@@ -659,6 +659,8 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
  * @RX_FLAG_HT: HT MCS was used and rate_idx is MCS index
  * @RX_FLAG_40MHZ: HT40 (40 MHz) was used
  * @RX_FLAG_SHORT_GI: Short guard interval was used
+ * @RX_FLAG_NO_SIGNAL_VAL: The signal strength value is not present.
+ *     Valid only for data frames (mainly A-MPDU)
  */
 enum mac80211_rx_flags {
        RX_FLAG_MMIC_ERROR      = 1<<0,
@@ -672,6 +674,7 @@ enum mac80211_rx_flags {
        RX_FLAG_HT              = 1<<9,
        RX_FLAG_40MHZ           = 1<<10,
        RX_FLAG_SHORT_GI        = 1<<11,
+       RX_FLAG_NO_SIGNAL_VAL   = 1<<12,
 };
 
 /**
@@ -1634,7 +1637,7 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
  * the station sends a PS-Poll or a uAPSD trigger frame, mac80211
  * will inform the driver of this with the @allow_buffered_frames
  * callback; this callback is optional. mac80211 will then transmit
- * the frames as usual and set the %IEEE80211_TX_CTL_POLL_RESPONSE
+ * the frames as usual and set the %IEEE80211_TX_CTL_NO_PS_BUFFER
  * on each frame. The last frame in the service period (or the only
  * response to a PS-Poll) also has %IEEE80211_TX_STATUS_EOSP set to
  * indicate that it ends the service period; as this frame must have
@@ -1642,6 +1645,9 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
  * When TX status is reported for this frame, the service period is
  * marked has having ended and a new one can be started by the peer.
  *
+ * Additionally, non-bufferable MMPDUs can also be transmitted by
+ * mac80211 with the %IEEE80211_TX_CTL_NO_PS_BUFFER set in them.
+ *
  * Another race condition can happen on some devices like iwlwifi
  * when there are frames queued for the station and it wakes up
  * or polls; the frames that are already queued could end up being
@@ -2140,7 +2146,7 @@ enum ieee80211_frame_release_type {
  * @allow_buffered_frames: Prepare device to allow the given number of frames
  *     to go out to the given station. The frames will be sent by mac80211
  *     via the usual TX path after this call. The TX information for frames
- *     released will also have the %IEEE80211_TX_CTL_POLL_RESPONSE flag set
+ *     released will also have the %IEEE80211_TX_CTL_NO_PS_BUFFER flag set
  *     and the last one will also have %IEEE80211_TX_STATUS_EOSP set. In case
  *     frames from multiple TIDs are released and the driver might reorder
  *     them between the TIDs, it must set the %IEEE80211_TX_STATUS_EOSP flag
@@ -3562,6 +3568,8 @@ enum rate_control_changed {
  * @hw: The hardware the algorithm is invoked for.
  * @sband: The band this frame is being transmitted on.
  * @bss_conf: the current BSS configuration
+ * @skb: the skb that will be transmitted, the control information in it needs
+ *     to be filled in
  * @reported_rate: The rate control algorithm can fill this in to indicate
  *     which rate should be reported to userspace as the current rate and
  *     used for rate calculations in the mesh network.
@@ -3569,12 +3577,11 @@ enum rate_control_changed {
  *     RTS threshold
  * @short_preamble: whether mac80211 will request short-preamble transmission
  *     if the selected rate supports it
- * @max_rate_idx: user-requested maximum rate (not MCS for now)
+ * @max_rate_idx: user-requested maximum (legacy) rate
  *     (deprecated; this will be removed once drivers get updated to use
  *     rate_idx_mask)
- * @rate_idx_mask: user-requested rate mask (not MCS for now)
- * @skb: the skb that will be transmitted, the control information in it needs
- *     to be filled in
+ * @rate_idx_mask: user-requested (legacy) rate mask
+ * @rate_idx_mcs_mask: user-requested MCS rate mask
  * @bss: whether this frame is sent out in AP or IBSS mode
  */
 struct ieee80211_tx_rate_control {
index 2dcf31703acba7a18b9f167866390827054f9d98..96755c3798a552cbcb74d978685c0a3648ee86e4 100644 (file)
@@ -19,6 +19,9 @@ enum nf_ct_ext_id {
 #endif
 #ifdef CONFIG_NF_CONNTRACK_TIMESTAMP
        NF_CT_EXT_TSTAMP,
+#endif
+#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
+       NF_CT_EXT_TIMEOUT,
 #endif
        NF_CT_EXT_NUM,
 };
@@ -29,6 +32,7 @@ enum nf_ct_ext_id {
 #define NF_CT_EXT_ECACHE_TYPE struct nf_conntrack_ecache
 #define NF_CT_EXT_ZONE_TYPE struct nf_conntrack_zone
 #define NF_CT_EXT_TSTAMP_TYPE struct nf_conn_tstamp
+#define NF_CT_EXT_TIMEOUT_TYPE struct nf_conn_timeout
 
 /* Extensions: optional stuff which isn't permanently in struct. */
 struct nf_ct_ext {
index f1c1311adc2cb6fba8d013cc641e995105cdf655..5767dc242dee50cc07aad55fc211dc3d5e808650 100644 (file)
@@ -69,4 +69,17 @@ extern int nf_conntrack_broadcast_help(struct sk_buff *skb,
                                       enum ip_conntrack_info ctinfo,
                                       unsigned int timeout);
 
+struct nf_ct_helper_expectfn {
+       struct list_head head;
+       const char *name;
+       void (*expectfn)(struct nf_conn *ct, struct nf_conntrack_expect *exp);
+};
+
+void nf_ct_helper_expectfn_register(struct nf_ct_helper_expectfn *n);
+void nf_ct_helper_expectfn_unregister(struct nf_ct_helper_expectfn *n);
+struct nf_ct_helper_expectfn *
+nf_ct_helper_expectfn_find_by_name(const char *name);
+struct nf_ct_helper_expectfn *
+nf_ct_helper_expectfn_find_by_symbol(const void *symbol);
+
 #endif /*_NF_CONNTRACK_HELPER_H*/
index e3d3ee3c06a2cc477fb2b85acf33090a2ef3496e..90c67c7db7e9135b1a762ccb1700846c91aff281 100644 (file)
@@ -39,12 +39,13 @@ struct nf_conntrack_l4proto {
                      unsigned int dataoff,
                      enum ip_conntrack_info ctinfo,
                      u_int8_t pf,
-                     unsigned int hooknum);
+                     unsigned int hooknum,
+                     unsigned int *timeouts);
 
        /* Called when a new connection for this protocol found;
         * returns TRUE if it's OK.  If so, packet() called next. */
        bool (*new)(struct nf_conn *ct, const struct sk_buff *skb,
-                   unsigned int dataoff);
+                   unsigned int dataoff, unsigned int *timeouts);
 
        /* Called when a conntrack entry is destroyed */
        void (*destroy)(struct nf_conn *ct);
@@ -60,6 +61,9 @@ struct nf_conntrack_l4proto {
        /* Print out the private part of the conntrack. */
        int (*print_conntrack)(struct seq_file *s, struct nf_conn *);
 
+       /* Return the array of timeouts for this protocol. */
+       unsigned int *(*get_timeouts)(struct net *net);
+
        /* convert protoinfo to nfnetink attributes */
        int (*to_nlattr)(struct sk_buff *skb, struct nlattr *nla,
                         struct nf_conn *ct);
@@ -79,6 +83,17 @@ struct nf_conntrack_l4proto {
 
        size_t nla_size;
 
+#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
+       struct {
+               size_t obj_size;
+               int (*nlattr_to_obj)(struct nlattr *tb[], void *data);
+               int (*obj_to_nlattr)(struct sk_buff *skb, const void *data);
+
+               unsigned int nlattr_max;
+               const struct nla_policy *nla_policy;
+       } ctnl_timeout;
+#endif
+
 #ifdef CONFIG_SYSCTL
        struct ctl_table_header **ctl_table_header;
        struct ctl_table        *ctl_table;
diff --git a/include/net/netfilter/nf_conntrack_timeout.h b/include/net/netfilter/nf_conntrack_timeout.h
new file mode 100644 (file)
index 0000000..0e04db4
--- /dev/null
@@ -0,0 +1,78 @@
+#ifndef _NF_CONNTRACK_TIMEOUT_H
+#define _NF_CONNTRACK_TIMEOUT_H
+
+#include <net/net_namespace.h>
+#include <linux/netfilter/nf_conntrack_common.h>
+#include <linux/netfilter/nf_conntrack_tuple_common.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_extend.h>
+
+#define CTNL_TIMEOUT_NAME_MAX  32
+
+struct ctnl_timeout {
+       struct list_head        head;
+       struct rcu_head         rcu_head;
+       atomic_t                refcnt;
+       char                    name[CTNL_TIMEOUT_NAME_MAX];
+       __u16                   l3num;
+       __u8                    l4num;
+       char                    data[0];
+};
+
+struct nf_conn_timeout {
+       struct ctnl_timeout     *timeout;
+};
+
+#define NF_CT_TIMEOUT_EXT_DATA(__t) (unsigned int *) &((__t)->timeout->data)
+
+static inline
+struct nf_conn_timeout *nf_ct_timeout_find(const struct nf_conn *ct)
+{
+#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
+       return nf_ct_ext_find(ct, NF_CT_EXT_TIMEOUT);
+#else
+       return NULL;
+#endif
+}
+
+static inline
+struct nf_conn_timeout *nf_ct_timeout_ext_add(struct nf_conn *ct,
+                                             struct ctnl_timeout *timeout,
+                                             gfp_t gfp)
+{
+#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
+       struct nf_conn_timeout *timeout_ext;
+
+       timeout_ext = nf_ct_ext_add(ct, NF_CT_EXT_TIMEOUT, gfp);
+       if (timeout_ext == NULL)
+               return NULL;
+
+       timeout_ext->timeout = timeout;
+
+       return timeout_ext;
+#else
+       return NULL;
+#endif
+};
+
+#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
+extern int nf_conntrack_timeout_init(struct net *net);
+extern void nf_conntrack_timeout_fini(struct net *net);
+#else
+static inline int nf_conntrack_timeout_init(struct net *net)
+{
+        return 0;
+}
+
+static inline void nf_conntrack_timeout_fini(struct net *net)
+{
+        return;
+}
+#endif /* CONFIG_NF_CONNTRACK_TIMEOUT */
+
+#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
+extern struct ctnl_timeout *(*nf_ct_timeout_find_get_hook)(const char *name);
+extern void (*nf_ct_timeout_put_hook)(struct ctnl_timeout *timeout);
+#endif
+
+#endif /* _NF_CONNTRACK_TIMEOUT_H */
index 0dfb34a5b53c3440469e51873d886a5312ec9615..7e1544e8f70d36599205fd821f1cdc34705d1676 100644 (file)
@@ -6,7 +6,7 @@ struct sbuff {
 };
 static struct sbuff emergency, *emergency_ptr = &emergency;
 
-static int sb_add(struct sbuff *m, const char *f, ...)
+static __printf(2, 3) int sb_add(struct sbuff *m, const char *f, ...)
 {
        va_list args;
        int len;
index 86fee8b5c65c54f05471ad07969596710758487c..feba74027ff8bc18674c68625f8f6e5a9cd6562f 100644 (file)
@@ -141,17 +141,17 @@ struct nci_dev {
 
 /* ----- NCI Devices ----- */
 struct nci_dev *nci_allocate_device(struct nci_ops *ops,
-                               __u32 supported_protocols,
-                               int tx_headroom,
-                               int tx_tailroom);
+                                   __u32 supported_protocols,
+                                   int tx_headroom,
+                                   int tx_tailroom);
 void nci_free_device(struct nci_dev *ndev);
 int nci_register_device(struct nci_dev *ndev);
 void nci_unregister_device(struct nci_dev *ndev);
 int nci_recv_frame(struct sk_buff *skb);
 
 static inline struct sk_buff *nci_skb_alloc(struct nci_dev *ndev,
-                                               unsigned int len,
-                                               gfp_t how)
+                                           unsigned int len,
+                                           gfp_t how)
 {
        struct sk_buff *skb;
 
index d253278e5a96e9af9ca8775b446f8811c807770d..bac070bf3514188c589b1769484abacfa8470ca1 100644 (file)
@@ -53,15 +53,15 @@ struct nfc_ops {
        int (*dev_down)(struct nfc_dev *dev);
        int (*start_poll)(struct nfc_dev *dev, u32 protocols);
        void (*stop_poll)(struct nfc_dev *dev);
-       int (*dep_link_up)(struct nfc_dev *dev, int target_idx,
-                               u8 comm_mode, u8 rf_mode);
+       int (*dep_link_up)(struct nfc_dev *dev, int target_idx, u8 comm_mode,
+                          u8 *gb, size_t gb_len);
        int (*dep_link_down)(struct nfc_dev *dev);
        int (*activate_target)(struct nfc_dev *dev, u32 target_idx,
-                                                       u32 protocol);
+                              u32 protocol);
        void (*deactivate_target)(struct nfc_dev *dev, u32 target_idx);
        int (*data_exchange)(struct nfc_dev *dev, u32 target_idx,
-                               struct sk_buff *skb, data_exchange_cb_t cb,
-                                                       void *cb_context);
+                            struct sk_buff *skb, data_exchange_cb_t cb,
+                            void *cb_context);
 };
 
 #define NFC_TARGET_IDX_ANY -1
@@ -110,9 +110,9 @@ struct nfc_dev {
 extern struct class nfc_class;
 
 struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
-                                       u32 supported_protocols,
-                                       int tx_headroom,
-                                       int tx_tailroom);
+                                   u32 supported_protocols,
+                                   int tx_headroom,
+                                   int tx_tailroom);
 
 /**
  * nfc_free_device - free nfc device
@@ -135,7 +135,7 @@ void nfc_unregister_device(struct nfc_dev *dev);
  * @dev: The parent device
  */
 static inline void nfc_set_parent_dev(struct nfc_dev *nfc_dev,
-                                       struct device *dev)
+                                     struct device *dev)
 {
        nfc_dev->dev.parent = dev;
 }
@@ -172,17 +172,15 @@ static inline const char *nfc_device_name(struct nfc_dev *dev)
 }
 
 struct sk_buff *nfc_alloc_send_skb(struct nfc_dev *dev, struct sock *sk,
-                                       unsigned int flags, unsigned int size,
-                                       unsigned int *err);
+                                  unsigned int flags, unsigned int size,
+                                  unsigned int *err);
 struct sk_buff *nfc_alloc_recv_skb(unsigned int size, gfp_t gfp);
 
 int nfc_set_remote_general_bytes(struct nfc_dev *dev,
-                                       u8 *gt, u8 gt_len);
+                                u8 *gt, u8 gt_len);
 
-u8 *nfc_get_local_general_bytes(struct nfc_dev *dev, u8 *gt_len);
-
-int nfc_targets_found(struct nfc_dev *dev, struct nfc_target *targets,
-                                                       int ntargets);
+int nfc_targets_found(struct nfc_dev *dev,
+                     struct nfc_target *targets, int ntargets);
 
 int nfc_dep_link_is_up(struct nfc_dev *dev, u32 target_idx,
                       u8 comm_mode, u8 rf_mode);
index d3685615a8b0eeff1d0f7ca032fa04c3fd5000c5..6ee44b24864ac96d21e9949ac4c07c258dbce6ad 100644 (file)
@@ -413,6 +413,7 @@ static inline sctp_assoc_t sctp_assoc2id(const struct sctp_association *asoc)
 /* Look up the association by its id.  */
 struct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id);
 
+int sctp_do_peeloff(struct sock *sk, sctp_assoc_t id, struct socket **sockp);
 
 /* A macro to walk a list of skbs.  */
 #define sctp_skb_for_each(pos, head, tmp) \
index 6ba596b07a7236ef0c48cd5b910dc6d6844ba508..e33ed1bfa1138bb6200eda7a213db34094cedf49 100644 (file)
@@ -370,56 +370,6 @@ TRACE_EVENT(sched_stat_runtime,
                        (unsigned long long)__entry->vruntime)
 );
 
-#ifdef CREATE_TRACE_POINTS
-static inline u64 trace_get_sleeptime(struct task_struct *tsk)
-{
-#ifdef CONFIG_SCHEDSTATS
-       u64 block, sleep;
-
-       block = tsk->se.statistics.block_start;
-       sleep = tsk->se.statistics.sleep_start;
-       tsk->se.statistics.block_start = 0;
-       tsk->se.statistics.sleep_start = 0;
-
-       return block ? block : sleep ? sleep : 0;
-#else
-       return 0;
-#endif
-}
-#endif
-
-/*
- * Tracepoint for accounting sleeptime (time the task is sleeping
- * or waiting for I/O).
- */
-TRACE_EVENT(sched_stat_sleeptime,
-
-       TP_PROTO(struct task_struct *tsk, u64 now),
-
-       TP_ARGS(tsk, now),
-
-       TP_STRUCT__entry(
-               __array( char,  comm,   TASK_COMM_LEN   )
-               __field( pid_t, pid                     )
-               __field( u64,   sleeptime               )
-       ),
-
-       TP_fast_assign(
-               memcpy(__entry->comm, tsk->comm, TASK_COMM_LEN);
-               __entry->pid            = tsk->pid;
-               __entry->sleeptime = trace_get_sleeptime(tsk);
-               __entry->sleeptime = __entry->sleeptime ?
-                               now - __entry->sleeptime : 0;
-       )
-       TP_perf_assign(
-               __perf_count(__entry->sleeptime);
-       ),
-
-       TP_printk("comm=%s pid=%d sleeptime=%Lu [ns]",
-                       __entry->comm, __entry->pid,
-                       (unsigned long long)__entry->sleeptime)
-);
-
 /*
  * Tracepoint for showing priority inheritance modifying a tasks
  * priority.
index b7971d6f38bf191d885a821fcce5a0d411869511..ee706ce44aa0232301ae4fbd636f063789689e31 100644 (file)
@@ -651,10 +651,10 @@ int __init init_hw_breakpoint(void)
 
  err_alloc:
        for_each_possible_cpu(err_cpu) {
-               if (err_cpu == cpu)
-                       break;
                for (i = 0; i < TYPE_MAX; i++)
                        kfree(per_cpu(nr_task_bp_pinned[i], cpu));
+               if (err_cpu == cpu)
+                       break;
        }
 
        return -ENOMEM;
index e2cd3e2a5ae8b73dac244bd4ee98fbe70d5d5364..26a7a6707fa738e181a6b397d8ba9bea47269deb 100644 (file)
@@ -668,6 +668,38 @@ struct mm_struct *mm_access(struct task_struct *task, unsigned int mode)
        return mm;
 }
 
+static void complete_vfork_done(struct task_struct *tsk)
+{
+       struct completion *vfork;
+
+       task_lock(tsk);
+       vfork = tsk->vfork_done;
+       if (likely(vfork)) {
+               tsk->vfork_done = NULL;
+               complete(vfork);
+       }
+       task_unlock(tsk);
+}
+
+static int wait_for_vfork_done(struct task_struct *child,
+                               struct completion *vfork)
+{
+       int killed;
+
+       freezer_do_not_count();
+       killed = wait_for_completion_killable(vfork);
+       freezer_count();
+
+       if (killed) {
+               task_lock(child);
+               child->vfork_done = NULL;
+               task_unlock(child);
+       }
+
+       put_task_struct(child);
+       return killed;
+}
+
 /* Please note the differences between mmput and mm_release.
  * mmput is called whenever we stop holding onto a mm_struct,
  * error success whatever.
@@ -683,8 +715,6 @@ struct mm_struct *mm_access(struct task_struct *task, unsigned int mode)
  */
 void mm_release(struct task_struct *tsk, struct mm_struct *mm)
 {
-       struct completion *vfork_done = tsk->vfork_done;
-
        /* Get rid of any futexes when releasing the mm */
 #ifdef CONFIG_FUTEX
        if (unlikely(tsk->robust_list)) {
@@ -704,17 +734,15 @@ void mm_release(struct task_struct *tsk, struct mm_struct *mm)
        /* Get rid of any cached register state */
        deactivate_mm(tsk, mm);
 
-       /* notify parent sleeping on vfork() */
-       if (vfork_done) {
-               tsk->vfork_done = NULL;
-               complete(vfork_done);
-       }
+       if (tsk->vfork_done)
+               complete_vfork_done(tsk);
 
        /*
         * If we're exiting normally, clear a user-space tid field if
         * requested.  We leave this alone when dying by signal, to leave
         * the value intact in a core dump, and to save the unnecessary
-        * trouble otherwise.  Userland only wants this done for a sys_exit.
+        * trouble, say, a killed vfork parent shouldn't touch this mm.
+        * Userland only wants this done for a sys_exit.
         */
        if (tsk->clear_child_tid) {
                if (!(tsk->flags & PF_SIGNALED) &&
@@ -1018,7 +1046,6 @@ static void copy_flags(unsigned long clone_flags, struct task_struct *p)
 
        new_flags &= ~(PF_SUPERPRIV | PF_WQ_WORKER);
        new_flags |= PF_FORKNOEXEC;
-       new_flags |= PF_STARTING;
        p->flags = new_flags;
 }
 
@@ -1548,16 +1575,9 @@ long do_fork(unsigned long clone_flags,
                if (clone_flags & CLONE_VFORK) {
                        p->vfork_done = &vfork;
                        init_completion(&vfork);
+                       get_task_struct(p);
                }
 
-               /*
-                * We set PF_STARTING at creation in case tracing wants to
-                * use this to distinguish a fully live task from one that
-                * hasn't finished SIGSTOP raising yet.  Now we clear it
-                * and set the child going.
-                */
-               p->flags &= ~PF_STARTING;
-
                wake_up_new_task(p);
 
                /* forking complete and child started to run, tell ptracer */
@@ -1565,10 +1585,8 @@ long do_fork(unsigned long clone_flags,
                        ptrace_event(trace, nr);
 
                if (clone_flags & CLONE_VFORK) {
-                       freezer_do_not_count();
-                       wait_for_completion(&vfork);
-                       freezer_count();
-                       ptrace_event(PTRACE_EVENT_VFORK_DONE, nr);
+                       if (!wait_for_vfork_done(p, &vfork))
+                               ptrace_event(PTRACE_EVENT_VFORK_DONE, nr);
                }
        } else {
                nr = PTR_ERR(p);
index 2e48ec0c2e91cf099642f8bf43e90476fb6457a3..c21449f85a2a4061bd9a34fc4844b5a3240850b3 100644 (file)
@@ -119,15 +119,20 @@ static void check_hung_task(struct task_struct *t, unsigned long timeout)
  * For preemptible RCU it is sufficient to call rcu_read_unlock in order
  * to exit the grace period. For classic RCU, a reschedule is required.
  */
-static void rcu_lock_break(struct task_struct *g, struct task_struct *t)
+static bool rcu_lock_break(struct task_struct *g, struct task_struct *t)
 {
+       bool can_cont;
+
        get_task_struct(g);
        get_task_struct(t);
        rcu_read_unlock();
        cond_resched();
        rcu_read_lock();
+       can_cont = pid_alive(g) && pid_alive(t);
        put_task_struct(t);
        put_task_struct(g);
+
+       return can_cont;
 }
 
 /*
@@ -154,9 +159,7 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout)
                        goto unlock;
                if (!--batch_count) {
                        batch_count = HUNG_TASK_BATCHING;
-                       rcu_lock_break(g, t);
-                       /* Exit if t or g was unhashed during refresh. */
-                       if (t->state == TASK_DEAD || g->state == TASK_DEAD)
+                       if (!rcu_lock_break(g, t))
                                goto unlock;
                }
                /* use "==" to skip the TASK_KILLABLE tasks waiting on NFS */
index 342d8f44e4010d13cb03f21b89a57d9dc955497e..0119b9d467ae6dd1d53b9f38bcf9c95d63f7ae9d 100644 (file)
@@ -53,7 +53,7 @@ unsigned long probe_irq_on(void)
                        if (desc->irq_data.chip->irq_set_type)
                                desc->irq_data.chip->irq_set_type(&desc->irq_data,
                                                         IRQ_TYPE_PROBE);
-                       irq_startup(desc);
+                       irq_startup(desc, false);
                }
                raw_spin_unlock_irq(&desc->lock);
        }
@@ -70,7 +70,7 @@ unsigned long probe_irq_on(void)
                raw_spin_lock_irq(&desc->lock);
                if (!desc->action && irq_settings_can_probe(desc)) {
                        desc->istate |= IRQS_AUTODETECT | IRQS_WAITING;
-                       if (irq_startup(desc))
+                       if (irq_startup(desc, false))
                                desc->istate |= IRQS_PENDING;
                }
                raw_spin_unlock_irq(&desc->lock);
index f7c543a801d97a67a2778e2685fa181739a803ac..fb7db75ee0c87884d40ada2cb88e355cb2ca353c 100644 (file)
@@ -157,19 +157,22 @@ static void irq_state_set_masked(struct irq_desc *desc)
        irqd_set(&desc->irq_data, IRQD_IRQ_MASKED);
 }
 
-int irq_startup(struct irq_desc *desc)
+int irq_startup(struct irq_desc *desc, bool resend)
 {
+       int ret = 0;
+
        irq_state_clr_disabled(desc);
        desc->depth = 0;
 
        if (desc->irq_data.chip->irq_startup) {
-               int ret = desc->irq_data.chip->irq_startup(&desc->irq_data);
+               ret = desc->irq_data.chip->irq_startup(&desc->irq_data);
                irq_state_clr_masked(desc);
-               return ret;
+       } else {
+               irq_enable(desc);
        }
-
-       irq_enable(desc);
-       return 0;
+       if (resend)
+               check_irq_resend(desc, desc->irq_data.irq);
+       return ret;
 }
 
 void irq_shutdown(struct irq_desc *desc)
@@ -330,6 +333,24 @@ out_unlock:
 }
 EXPORT_SYMBOL_GPL(handle_simple_irq);
 
+/*
+ * Called unconditionally from handle_level_irq() and only for oneshot
+ * interrupts from handle_fasteoi_irq()
+ */
+static void cond_unmask_irq(struct irq_desc *desc)
+{
+       /*
+        * We need to unmask in the following cases:
+        * - Standard level irq (IRQF_ONESHOT is not set)
+        * - Oneshot irq which did not wake the thread (caused by a
+        *   spurious interrupt or a primary handler handling it
+        *   completely).
+        */
+       if (!irqd_irq_disabled(&desc->irq_data) &&
+           irqd_irq_masked(&desc->irq_data) && !desc->threads_oneshot)
+               unmask_irq(desc);
+}
+
 /**
  *     handle_level_irq - Level type irq handler
  *     @irq:   the interrupt number
@@ -362,8 +383,8 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc)
 
        handle_irq_event(desc);
 
-       if (!irqd_irq_disabled(&desc->irq_data) && !(desc->istate & IRQS_ONESHOT))
-               unmask_irq(desc);
+       cond_unmask_irq(desc);
+
 out_unlock:
        raw_spin_unlock(&desc->lock);
 }
@@ -417,6 +438,9 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)
        preflow_handler(desc);
        handle_irq_event(desc);
 
+       if (desc->istate & IRQS_ONESHOT)
+               cond_unmask_irq(desc);
+
 out_eoi:
        desc->irq_data.chip->irq_eoi(&desc->irq_data);
 out_unlock:
@@ -625,7 +649,7 @@ __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
                irq_settings_set_noprobe(desc);
                irq_settings_set_norequest(desc);
                irq_settings_set_nothread(desc);
-               irq_startup(desc);
+               irq_startup(desc, true);
        }
 out:
        irq_put_desc_busunlock(desc, flags);
index b7952316016aa8175b6149856ed57eba230007eb..40378ff877e738c53f6c5f478898455ebee3454f 100644 (file)
@@ -67,7 +67,7 @@ extern int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,
 extern void __disable_irq(struct irq_desc *desc, unsigned int irq, bool susp);
 extern void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume);
 
-extern int irq_startup(struct irq_desc *desc);
+extern int irq_startup(struct irq_desc *desc, bool resend);
 extern void irq_shutdown(struct irq_desc *desc);
 extern void irq_enable(struct irq_desc *desc);
 extern void irq_disable(struct irq_desc *desc);
index a9a9dbe49fead98c11aa4ea4aa2d3d38cd187494..0f0d4704ddd8a3865d0926067fbf654d48dabbbc 100644 (file)
@@ -985,6 +985,11 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
 
                /* add new interrupt at end of irq queue */
                do {
+                       /*
+                        * Or all existing action->thread_mask bits,
+                        * so we can find the next zero bit for this
+                        * new action.
+                        */
                        thread_mask |= old->thread_mask;
                        old_ptr = &old->next;
                        old = *old_ptr;
@@ -993,14 +998,41 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
        }
 
        /*
-        * Setup the thread mask for this irqaction. Unlikely to have
-        * 32 resp 64 irqs sharing one line, but who knows.
+        * Setup the thread mask for this irqaction for ONESHOT. For
+        * !ONESHOT irqs the thread mask is 0 so we can avoid a
+        * conditional in irq_wake_thread().
         */
-       if (new->flags & IRQF_ONESHOT && thread_mask == ~0UL) {
-               ret = -EBUSY;
-               goto out_mask;
+       if (new->flags & IRQF_ONESHOT) {
+               /*
+                * Unlikely to have 32 resp 64 irqs sharing one line,
+                * but who knows.
+                */
+               if (thread_mask == ~0UL) {
+                       ret = -EBUSY;
+                       goto out_mask;
+               }
+               /*
+                * The thread_mask for the action is or'ed to
+                * desc->thread_active to indicate that the
+                * IRQF_ONESHOT thread handler has been woken, but not
+                * yet finished. The bit is cleared when a thread
+                * completes. When all threads of a shared interrupt
+                * line have completed desc->threads_active becomes
+                * zero and the interrupt line is unmasked. See
+                * handle.c:irq_wake_thread() for further information.
+                *
+                * If no thread is woken by primary (hard irq context)
+                * interrupt handlers, then desc->threads_active is
+                * also checked for zero to unmask the irq line in the
+                * affected hard irq flow handlers
+                * (handle_[fasteoi|level]_irq).
+                *
+                * The new action gets the first zero bit of
+                * thread_mask assigned. See the loop above which or's
+                * all existing action->thread_mask bits.
+                */
+               new->thread_mask = 1 << ffz(thread_mask);
        }
-       new->thread_mask = 1 << ffz(thread_mask);
 
        if (!shared) {
                init_waitqueue_head(&desc->wait_for_threads);
@@ -1027,7 +1059,7 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
                        desc->istate |= IRQS_ONESHOT;
 
                if (irq_settings_can_autoenable(desc))
-                       irq_startup(desc);
+                       irq_startup(desc, true);
                else
                        /* Undo nested disables: */
                        desc->depth = 1;
index 9788c0ec6f4378f19cd80e873d42a0aec7171548..c62b8546cc90e0b39de0e824b0f7ed7179d8ba92 100644 (file)
@@ -1334,8 +1334,10 @@ int __kprobes register_kprobe(struct kprobe *p)
        if (!kernel_text_address((unsigned long) p->addr) ||
            in_kprobes_functions((unsigned long) p->addr) ||
            ftrace_text_reserved(p->addr, p->addr) ||
-           jump_label_text_reserved(p->addr, p->addr))
-               goto fail_with_jump_label;
+           jump_label_text_reserved(p->addr, p->addr)) {
+               ret = -EINVAL;
+               goto cannot_probe;
+       }
 
        /* User can pass only KPROBE_FLAG_DISABLED to register_kprobe */
        p->flags &= KPROBE_FLAG_DISABLED;
@@ -1352,7 +1354,7 @@ int __kprobes register_kprobe(struct kprobe *p)
                 * its code to prohibit unexpected unloading.
                 */
                if (unlikely(!try_module_get(probed_mod)))
-                       goto fail_with_jump_label;
+                       goto cannot_probe;
 
                /*
                 * If the module freed .init.text, we couldn't insert
@@ -1361,7 +1363,7 @@ int __kprobes register_kprobe(struct kprobe *p)
                if (within_module_init((unsigned long)p->addr, probed_mod) &&
                    probed_mod->state != MODULE_STATE_COMING) {
                        module_put(probed_mod);
-                       goto fail_with_jump_label;
+                       goto cannot_probe;
                }
                /* ret will be updated by following code */
        }
@@ -1409,7 +1411,7 @@ out:
 
        return ret;
 
-fail_with_jump_label:
+cannot_probe:
        preempt_enable();
        jump_label_unlock();
        return ret;
index 13c0a1143f49438f7cc97718e61ecf5bc5b23747..32690a0b7a1838e1bd9b8bcf8473654955807dae 100644 (file)
@@ -702,6 +702,9 @@ static bool printk_time = 0;
 #endif
 module_param_named(time, printk_time, bool, S_IRUGO | S_IWUSR);
 
+static bool always_kmsg_dump;
+module_param_named(always_kmsg_dump, always_kmsg_dump, bool, S_IRUGO | S_IWUSR);
+
 /* Check if we have any console registered that can be called early in boot. */
 static int have_callable_console(void)
 {
@@ -1732,6 +1735,9 @@ void kmsg_dump(enum kmsg_dump_reason reason)
        unsigned long l1, l2;
        unsigned long flags;
 
+       if ((reason > KMSG_DUMP_OOPS) && !always_kmsg_dump)
+               return;
+
        /* Theoretically, the log could move on after we do this, but
           there's not a lot we can do about that. The new messages
           will overwrite the start of what we dump. */
index 5255c9d2e053225173dfea134e7e243ad0e80891..b342f57879e693f54c12a5b15d1e4e7c5bdde7e1 100644 (file)
@@ -1932,7 +1932,6 @@ static void finish_task_switch(struct rq *rq, struct task_struct *prev)
        local_irq_enable();
 #endif /* __ARCH_WANT_INTERRUPTS_ON_CTXSW */
        finish_lock_switch(rq, prev);
-       trace_sched_stat_sleeptime(current, rq->clock);
 
        fire_sched_in_preempt_notifiers(current);
        if (mm)
index 7c6414fc669de4f09dc03fc763aaddd8040f98bf..aca16b843b7ee463e005996508b098ea44e01b32 100644 (file)
@@ -1003,6 +1003,7 @@ static void enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se)
                if (unlikely(delta > se->statistics.sleep_max))
                        se->statistics.sleep_max = delta;
 
+               se->statistics.sleep_start = 0;
                se->statistics.sum_sleep_runtime += delta;
 
                if (tsk) {
@@ -1019,6 +1020,7 @@ static void enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se)
                if (unlikely(delta > se->statistics.block_max))
                        se->statistics.block_max = delta;
 
+               se->statistics.block_start = 0;
                se->statistics.sum_sleep_runtime += delta;
 
                if (tsk) {
index 77cb245f8e7bdee634b98f6c275ae221c7c90715..0ab9ae8057f00e8545deba43ff31fab7873a619c 100644 (file)
@@ -818,17 +818,9 @@ static int __init fixup_activate(void *addr, enum debug_obj_state state)
                if (obj->static_init == 1) {
                        debug_object_init(obj, &descr_type_test);
                        debug_object_activate(obj, &descr_type_test);
-                       /*
-                        * Real code should return 0 here ! This is
-                        * not a fixup of some bad behaviour. We
-                        * merily call the debug_init function to keep
-                        * track of the object.
-                        */
-                       return 1;
-               } else {
-                       /* Real code needs to emit a warning here */
+                       return 0;
                }
-               return 0;
+               return 1;
 
        case ODEBUG_STATE_ACTIVE:
                debug_object_deactivate(obj, &descr_type_test);
@@ -967,7 +959,7 @@ static void __init debug_objects_selftest(void)
 
        obj.static_init = 1;
        debug_object_activate(&obj, &descr_type_test);
-       if (check_results(&obj, ODEBUG_STATE_ACTIVE, ++fixups, warnings))
+       if (check_results(&obj, ODEBUG_STATE_ACTIVE, fixups, warnings))
                goto out;
        debug_object_init(&obj, &descr_type_test);
        if (check_results(&obj, ODEBUG_STATE_INIT, ++fixups, ++warnings))
index 8e75003d62f632c52b8c0ea56ca62bdc72e560f0..38e612e66da5993f7b1eb92065ebfec45216d83c 100644 (file)
@@ -891,9 +891,15 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
        case 'U':
                return uuid_string(buf, end, ptr, spec, fmt);
        case 'V':
-               return buf + vsnprintf(buf, end > buf ? end - buf : 0,
-                                      ((struct va_format *)ptr)->fmt,
-                                      *(((struct va_format *)ptr)->va));
+               {
+                       va_list va;
+
+                       va_copy(va, *((struct va_format *)ptr)->va);
+                       buf += vsnprintf(buf, end > buf ? end - buf : 0,
+                                        ((struct va_format *)ptr)->fmt, va);
+                       va_end(va);
+                       return buf;
+               }
        case 'K':
                /*
                 * %pK cannot be used in IRQ context because its test
index 91d3efb25d15472332e1f2d9c382a5732629ce69..8f7fc394f63672954cc4444da0f2158a42470b2c 100644 (file)
@@ -671,6 +671,7 @@ static int __do_huge_pmd_anonymous_page(struct mm_struct *mm,
                set_pmd_at(mm, haddr, pmd, entry);
                prepare_pmd_huge_pte(pgtable, mm);
                add_mm_counter(mm, MM_ANONPAGES, HPAGE_PMD_NR);
+               mm->nr_ptes++;
                spin_unlock(&mm->page_table_lock);
        }
 
@@ -789,6 +790,7 @@ int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm,
        pmd = pmd_mkold(pmd_wrprotect(pmd));
        set_pmd_at(dst_mm, addr, dst_pmd, pmd);
        prepare_pmd_huge_pte(pgtable, dst_mm);
+       dst_mm->nr_ptes++;
 
        ret = 0;
 out_unlock:
@@ -887,7 +889,6 @@ static int do_huge_pmd_wp_page_fallback(struct mm_struct *mm,
        }
        kfree(pages);
 
-       mm->nr_ptes++;
        smp_wmb(); /* make pte visible before pmd */
        pmd_populate(mm, pmd, pgtable);
        page_remove_rmap(page);
@@ -1047,6 +1048,7 @@ int zap_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,
                        VM_BUG_ON(page_mapcount(page) < 0);
                        add_mm_counter(tlb->mm, MM_ANONPAGES, -HPAGE_PMD_NR);
                        VM_BUG_ON(!PageHead(page));
+                       tlb->mm->nr_ptes--;
                        spin_unlock(&tlb->mm->page_table_lock);
                        tlb_remove_page(tlb, page);
                        pte_free(tlb->mm, pgtable);
@@ -1375,7 +1377,6 @@ static int __split_huge_page_map(struct page *page,
                        pte_unmap(pte);
                }
 
-               mm->nr_ptes++;
                smp_wmb(); /* make pte visible before pmd */
                /*
                 * Up to this point the pmd is present and huge and
@@ -1988,7 +1989,6 @@ static void collapse_huge_page(struct mm_struct *mm,
        set_pmd_at(mm, address, pmd, _pmd);
        update_mmu_cache(vma, address, _pmd);
        prepare_pmd_huge_pte(pgtable, mm);
-       mm->nr_ptes--;
        spin_unlock(&mm->page_table_lock);
 
 #ifndef CONFIG_NUMA
index 5f34bd8dda34bbc8224303ad080103f224fa5ad6..a876871f6be56d15b06d1da56a9f3dbbd61cda91 100644 (file)
@@ -2277,8 +2277,8 @@ void __unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start,
                        set_page_dirty(page);
                list_add(&page->lru, &page_list);
        }
-       spin_unlock(&mm->page_table_lock);
        flush_tlb_range(vma, start, end);
+       spin_unlock(&mm->page_table_lock);
        mmu_notifier_invalidate_range_end(mm, start, end);
        list_for_each_entry_safe(page, tmp, &page_list, lru) {
                page_remove_rmap(page);
index 1925ffbfb27f00ac3d3d262ce0ea1c8aaa3a117f..310544a379ae9c7b886b3b50815e5f3d5a991ba8 100644 (file)
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -28,7 +28,6 @@
 #include <linux/kthread.h>
 #include <linux/wait.h>
 #include <linux/slab.h>
-#include <linux/memcontrol.h>
 #include <linux/rbtree.h>
 #include <linux/memory.h>
 #include <linux/mmu_notifier.h>
@@ -1572,16 +1571,6 @@ struct page *ksm_does_need_to_copy(struct page *page,
 
        new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, address);
        if (new_page) {
-               /*
-                * The memcg-specific accounting when moving
-                * pages around the LRU lists relies on the
-                * page's owner (memcg) to be valid.  Usually,
-                * pages are assigned to a new owner before
-                * being put on the LRU list, but since this
-                * is not the case here, the stale owner from
-                * a previous allocation cycle must be reset.
-                */
-               mem_cgroup_reset_owner(new_page);
                copy_user_highpage(new_page, page, address, vma);
 
                SetPageDirty(new_page);
index 77b5f227e1d86d9228ae6a67f52f18418a2beb98..99f285599501482e8b48c77eb768a62981811cf6 100644 (file)
@@ -99,9 +99,6 @@ phys_addr_t __init_memblock memblock_find_in_range_node(phys_addr_t start,
        phys_addr_t this_start, this_end, cand;
        u64 i;
 
-       /* align @size to avoid excessive fragmentation on reserved array */
-       size = round_up(size, align);
-
        /* pump up @end */
        if (end == MEMBLOCK_ALLOC_ACCESSIBLE)
                end = memblock.current_limit;
@@ -731,6 +728,9 @@ static phys_addr_t __init memblock_alloc_base_nid(phys_addr_t size,
 {
        phys_addr_t found;
 
+       /* align @size to avoid excessive fragmentation on reserved array */
+       size = round_up(size, align);
+
        found = memblock_find_in_range_node(0, max_addr, size, align, nid);
        if (found && !memblock_reserve(found, size))
                return found;
index 228d6461c12ade8941b37416ca867d3df3277acd..5585dc3d36466189b0d89adf8e86f424372bdd23 100644 (file)
@@ -1042,6 +1042,19 @@ struct lruvec *mem_cgroup_lru_add_list(struct zone *zone, struct page *page,
 
        pc = lookup_page_cgroup(page);
        memcg = pc->mem_cgroup;
+
+       /*
+        * Surreptitiously switch any uncharged page to root:
+        * an uncharged page off lru does nothing to secure
+        * its former mem_cgroup from sudden removal.
+        *
+        * Our caller holds lru_lock, and PageCgroupUsed is updated
+        * under page_cgroup lock: between them, they make all uses
+        * of pc->mem_cgroup safe.
+        */
+       if (!PageCgroupUsed(pc) && memcg != root_mem_cgroup)
+               pc->mem_cgroup = memcg = root_mem_cgroup;
+
        mz = page_cgroup_zoneinfo(memcg, page);
        /* compound_order() is stabilized through lru_lock */
        MEM_CGROUP_ZSTAT(mz, lru) += 1 << compound_order(page);
@@ -2408,8 +2421,12 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *memcg,
                                       struct page *page,
                                       unsigned int nr_pages,
                                       struct page_cgroup *pc,
-                                      enum charge_type ctype)
+                                      enum charge_type ctype,
+                                      bool lrucare)
 {
+       struct zone *uninitialized_var(zone);
+       bool was_on_lru = false;
+
        lock_page_cgroup(pc);
        if (unlikely(PageCgroupUsed(pc))) {
                unlock_page_cgroup(pc);
@@ -2420,6 +2437,21 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *memcg,
         * we don't need page_cgroup_lock about tail pages, becase they are not
         * accessed by any other context at this point.
         */
+
+       /*
+        * In some cases, SwapCache and FUSE(splice_buf->radixtree), the page
+        * may already be on some other mem_cgroup's LRU.  Take care of it.
+        */
+       if (lrucare) {
+               zone = page_zone(page);
+               spin_lock_irq(&zone->lru_lock);
+               if (PageLRU(page)) {
+                       ClearPageLRU(page);
+                       del_page_from_lru_list(zone, page, page_lru(page));
+                       was_on_lru = true;
+               }
+       }
+
        pc->mem_cgroup = memcg;
        /*
         * We access a page_cgroup asynchronously without lock_page_cgroup().
@@ -2443,9 +2475,18 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *memcg,
                break;
        }
 
+       if (lrucare) {
+               if (was_on_lru) {
+                       VM_BUG_ON(PageLRU(page));
+                       SetPageLRU(page);
+                       add_page_to_lru_list(zone, page, page_lru(page));
+               }
+               spin_unlock_irq(&zone->lru_lock);
+       }
+
        mem_cgroup_charge_statistics(memcg, PageCgroupCache(pc), nr_pages);
        unlock_page_cgroup(pc);
-       WARN_ON_ONCE(PageLRU(page));
+
        /*
         * "charge_statistics" updated event counter. Then, check it.
         * Insert ancestor (and ancestor's ancestors), to softlimit RB-tree.
@@ -2643,7 +2684,7 @@ static int mem_cgroup_charge_common(struct page *page, struct mm_struct *mm,
        ret = __mem_cgroup_try_charge(mm, gfp_mask, nr_pages, &memcg, oom);
        if (ret == -ENOMEM)
                return ret;
-       __mem_cgroup_commit_charge(memcg, page, nr_pages, pc, ctype);
+       __mem_cgroup_commit_charge(memcg, page, nr_pages, pc, ctype, false);
        return 0;
 }
 
@@ -2663,35 +2704,6 @@ static void
 __mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *ptr,
                                        enum charge_type ctype);
 
-static void
-__mem_cgroup_commit_charge_lrucare(struct page *page, struct mem_cgroup *memcg,
-                                       enum charge_type ctype)
-{
-       struct page_cgroup *pc = lookup_page_cgroup(page);
-       struct zone *zone = page_zone(page);
-       unsigned long flags;
-       bool removed = false;
-
-       /*
-        * In some case, SwapCache, FUSE(splice_buf->radixtree), the page
-        * is already on LRU. It means the page may on some other page_cgroup's
-        * LRU. Take care of it.
-        */
-       spin_lock_irqsave(&zone->lru_lock, flags);
-       if (PageLRU(page)) {
-               del_page_from_lru_list(zone, page, page_lru(page));
-               ClearPageLRU(page);
-               removed = true;
-       }
-       __mem_cgroup_commit_charge(memcg, page, 1, pc, ctype);
-       if (removed) {
-               add_page_to_lru_list(zone, page, page_lru(page));
-               SetPageLRU(page);
-       }
-       spin_unlock_irqrestore(&zone->lru_lock, flags);
-       return;
-}
-
 int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm,
                                gfp_t gfp_mask)
 {
@@ -2769,13 +2781,16 @@ static void
 __mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *memcg,
                                        enum charge_type ctype)
 {
+       struct page_cgroup *pc;
+
        if (mem_cgroup_disabled())
                return;
        if (!memcg)
                return;
        cgroup_exclude_rmdir(&memcg->css);
 
-       __mem_cgroup_commit_charge_lrucare(page, memcg, ctype);
+       pc = lookup_page_cgroup(page);
+       __mem_cgroup_commit_charge(memcg, page, 1, pc, ctype, true);
        /*
         * Now swap is on-memory. This means this page may be
         * counted both as mem and swap....double count.
@@ -3027,23 +3042,6 @@ void mem_cgroup_uncharge_end(void)
        batch->memcg = NULL;
 }
 
-/*
- * A function for resetting pc->mem_cgroup for newly allocated pages.
- * This function should be called if the newpage will be added to LRU
- * before start accounting.
- */
-void mem_cgroup_reset_owner(struct page *newpage)
-{
-       struct page_cgroup *pc;
-
-       if (mem_cgroup_disabled())
-               return;
-
-       pc = lookup_page_cgroup(newpage);
-       VM_BUG_ON(PageCgroupUsed(pc));
-       pc->mem_cgroup = root_mem_cgroup;
-}
-
 #ifdef CONFIG_SWAP
 /*
  * called after __delete_from_swap_cache() and drop "page" account.
@@ -3248,7 +3246,7 @@ int mem_cgroup_prepare_migration(struct page *page,
                ctype = MEM_CGROUP_CHARGE_TYPE_CACHE;
        else
                ctype = MEM_CGROUP_CHARGE_TYPE_SHMEM;
-       __mem_cgroup_commit_charge(memcg, newpage, 1, pc, ctype);
+       __mem_cgroup_commit_charge(memcg, newpage, 1, pc, ctype, false);
        return ret;
 }
 
@@ -3332,7 +3330,7 @@ void mem_cgroup_replace_page_cache(struct page *oldpage,
         * the newpage may be on LRU(or pagevec for LRU) already. We lock
         * LRU while we overwrite pc->mem_cgroup.
         */
-       __mem_cgroup_commit_charge_lrucare(newpage, memcg, type);
+       __mem_cgroup_commit_charge(memcg, newpage, 1, pc, type, true);
 }
 
 #ifdef CONFIG_DEBUG_VM
@@ -5077,7 +5075,7 @@ static struct page *mc_handle_present_pte(struct vm_area_struct *vma,
                return NULL;
        if (PageAnon(page)) {
                /* we don't move shared anon */
-               if (!move_anon() || page_mapcount(page) > 2)
+               if (!move_anon() || page_mapcount(page) > 1)
                        return NULL;
        } else if (!move_file())
                /* we ignore mapcount for file pages */
index 06b145fb64ab59a399344bc73ca277be0e39ed7b..47296fee23dbaa67c3408227d7653037a371bcdf 100644 (file)
@@ -640,10 +640,11 @@ static int mbind_range(struct mm_struct *mm, unsigned long start,
        unsigned long vmstart;
        unsigned long vmend;
 
-       vma = find_vma_prev(mm, start, &prev);
+       vma = find_vma(mm, start);
        if (!vma || vma->vm_start > start)
                return -EFAULT;
 
+       prev = vma->vm_prev;
        if (start > vma->vm_start)
                prev = vma;
 
index df141f60289eef61c7d278080e8290c3dfc717b9..1503b6b54ecbd1817e6e92968d40c404a6e90f75 100644 (file)
@@ -839,8 +839,6 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
        if (!newpage)
                return -ENOMEM;
 
-       mem_cgroup_reset_owner(newpage);
-
        if (page_count(page) == 1) {
                /* page was freed from under us. So we are done. */
                goto out;
index 4f4f53bdc65de30d11c637b2bc745aa1333a16bd..ef726e8aa8e9ca56c0713abfa4b621f44a210d4c 100644 (file)
@@ -385,10 +385,11 @@ static int do_mlock(unsigned long start, size_t len, int on)
                return -EINVAL;
        if (end == start)
                return 0;
-       vma = find_vma_prev(current->mm, start, &prev);
+       vma = find_vma(current->mm, start);
        if (!vma || vma->vm_start > start)
                return -ENOMEM;
 
+       prev = vma->vm_prev;
        if (start > vma->vm_start)
                prev = vma;
 
index 3f758c7f4c815c2b0edf494526b2823b41fbc142..da15a79b1441b665b0e4b962eea38a92407018fd 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1266,8 +1266,9 @@ munmap_back:
        vma->vm_pgoff = pgoff;
        INIT_LIST_HEAD(&vma->anon_vma_chain);
 
+       error = -EINVAL;        /* when rejecting VM_GROWSDOWN|VM_GROWSUP */
+
        if (file) {
-               error = -EINVAL;
                if (vm_flags & (VM_GROWSDOWN|VM_GROWSUP))
                        goto free_vma;
                if (vm_flags & VM_DENYWRITE) {
@@ -1293,6 +1294,8 @@ munmap_back:
                pgoff = vma->vm_pgoff;
                vm_flags = vma->vm_flags;
        } else if (vm_flags & VM_SHARED) {
+               if (unlikely(vm_flags & (VM_GROWSDOWN|VM_GROWSUP)))
+                       goto free_vma;
                error = shmem_zero_setup(vma);
                if (error)
                        goto free_vma;
@@ -1605,7 +1608,6 @@ EXPORT_SYMBOL(find_vma);
 
 /*
  * Same as find_vma, but also return a pointer to the previous VMA in *pprev.
- * Note: pprev is set to NULL when return value is NULL.
  */
 struct vm_area_struct *
 find_vma_prev(struct mm_struct *mm, unsigned long addr,
@@ -1614,7 +1616,16 @@ find_vma_prev(struct mm_struct *mm, unsigned long addr,
        struct vm_area_struct *vma;
 
        vma = find_vma(mm, addr);
-       *pprev = vma ? vma->vm_prev : NULL;
+       if (vma) {
+               *pprev = vma->vm_prev;
+       } else {
+               struct rb_node *rb_node = mm->mm_rb.rb_node;
+               *pprev = NULL;
+               while (rb_node) {
+                       *pprev = rb_entry(rb_node, struct vm_area_struct, vm_rb);
+                       rb_node = rb_node->rb_right;
+               }
+       }
        return vma;
 }
 
index 5a688a2756bec54435adbd5f3c13a33fbdd2c11e..f437d054c3bf6884fd5ba6f18338fbf7272c43a4 100644 (file)
@@ -262,10 +262,11 @@ SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len,
 
        down_write(&current->mm->mmap_sem);
 
-       vma = find_vma_prev(current->mm, start, &prev);
+       vma = find_vma(current->mm, start);
        error = -ENOMEM;
        if (!vma)
                goto out;
+       prev = vma->vm_prev;
        if (unlikely(grows & PROT_GROWSDOWN)) {
                if (vma->vm_start >= end)
                        goto out;
index de1616aa9b1e2b3fac054ce4077073cbb05a3c62..1ccbd714059cdd7ddb9d90cb3ca92438f2cb5d34 100644 (file)
@@ -379,13 +379,15 @@ static struct swap_cgroup *lookup_swap_cgroup(swp_entry_t ent,
        pgoff_t offset = swp_offset(ent);
        struct swap_cgroup_ctrl *ctrl;
        struct page *mappage;
+       struct swap_cgroup *sc;
 
        ctrl = &swap_cgroup_ctrl[swp_type(ent)];
        if (ctrlp)
                *ctrlp = ctrl;
 
        mappage = ctrl->map[offset / SC_PER_PAGE];
-       return page_address(mappage) + offset % SC_PER_PAGE;
+       sc = page_address(mappage);
+       return sc + offset % SC_PER_PAGE;
 }
 
 /**
index 12a48a88c0d8cb00dd55b2adcea3e536493dee1a..405d331804c3da95c52347878387a807eb5e6c60 100644 (file)
@@ -184,8 +184,7 @@ static void pcpu_unmap_pages(struct pcpu_chunk *chunk,
                                   page_end - page_start);
        }
 
-       for (i = page_start; i < page_end; i++)
-               __clear_bit(i, populated);
+       bitmap_clear(populated, page_start, page_end - page_start);
 }
 
 /**
index fff1ff7fb9ada36fca1be10d33dec593486f50a6..14380e9fbe3380b927cb58d75c5a950a5ec14f77 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -652,7 +652,7 @@ EXPORT_SYMBOL(__pagevec_release);
 void lru_add_page_tail(struct zone* zone,
                       struct page *page, struct page *page_tail)
 {
-       int active;
+       int uninitialized_var(active);
        enum lru_list lru;
        const int file = 0;
 
@@ -672,7 +672,6 @@ void lru_add_page_tail(struct zone* zone,
                        active = 0;
                        lru = LRU_INACTIVE_ANON;
                }
-               update_page_reclaim_stat(zone, page_tail, file, active);
        } else {
                SetPageUnevictable(page_tail);
                lru = LRU_UNEVICTABLE;
@@ -693,6 +692,9 @@ void lru_add_page_tail(struct zone* zone,
                list_head = page_tail->lru.prev;
                list_move_tail(&page_tail->lru, list_head);
        }
+
+       if (!PageUnevictable(page))
+               update_page_reclaim_stat(zone, page_tail, file, active);
 }
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
@@ -710,8 +712,8 @@ static void __pagevec_lru_add_fn(struct page *page, void *arg)
        SetPageLRU(page);
        if (active)
                SetPageActive(page);
-       update_page_reclaim_stat(zone, page, file, active);
        add_page_to_lru_list(zone, page, lru);
+       update_page_reclaim_stat(zone, page, file, active);
 }
 
 /*
index 470038a9187383790751817cda61a07cb50f9512..ea6b32d61873185f59db1eb9ae303488ec6de471 100644 (file)
@@ -300,16 +300,6 @@ struct page *read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask,
                        new_page = alloc_page_vma(gfp_mask, vma, addr);
                        if (!new_page)
                                break;          /* Out of memory */
-                       /*
-                        * The memcg-specific accounting when moving
-                        * pages around the LRU lists relies on the
-                        * page's owner (memcg) to be valid.  Usually,
-                        * pages are assigned to a new owner before
-                        * being put on the LRU list, but since this
-                        * is not the case here, the stale owner from
-                        * a previous allocation cycle must be reset.
-                        */
-                       mem_cgroup_reset_owner(new_page);
                }
 
                /*
index 9ec85eb8853dc378286e4c482f23b70fc2eeb7c2..3537d385035e61fc090e9094b83850243268f992 100644 (file)
@@ -29,7 +29,6 @@ menuconfig BT
             BNEP Module (Bluetooth Network Encapsulation Protocol)
             CMTP Module (CAPI Message Transport Protocol)
             HIDP Module (Human Interface Device Protocol)
-            SMP Module (Security Manager Protocol)
 
          Say Y here to compile Bluetooth support into the kernel or say M to
          compile it as module (bluetooth).
index 17800b1d28ea33c4d3b36801cdc1092a2930b88f..9f9c8dcd8af01bbae591733a093344126f0b9500 100644 (file)
@@ -143,10 +143,10 @@ static int bnep_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne
 {
        if (cmd == BNEPGETCONNLIST) {
                struct bnep_connlist_req cl;
-               uint32_t uci;
+               u32 uci;
                int err;
 
-               if (get_user(cl.cnum, (uint32_t __user *) arg) ||
+               if (get_user(cl.cnum, (u32 __user *) arg) ||
                                get_user(uci, (u32 __user *) (arg + 4)))
                        return -EFAULT;
 
@@ -157,7 +157,7 @@ static int bnep_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne
 
                err = bnep_get_connlist(&cl);
 
-               if (!err && put_user(cl.cnum, (uint32_t __user *) arg))
+               if (!err && put_user(cl.cnum, (u32 __user *) arg))
                        err = -EFAULT;
 
                return err;
index 3f2dd5c25ae516f3d267f1f038cb151af21c04c8..1230faaac29b01c54abac33a4913851db085ab22 100644 (file)
@@ -137,10 +137,10 @@ static int cmtp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne
 {
        if (cmd == CMTPGETCONNLIST) {
                struct cmtp_connlist_req cl;
-               uint32_t uci;
+               u32 uci;
                int err;
 
-               if (get_user(cl.cnum, (uint32_t __user *) arg) ||
+               if (get_user(cl.cnum, (u32 __user *) arg) ||
                                get_user(uci, (u32 __user *) (arg + 4)))
                        return -EFAULT;
 
@@ -151,7 +151,7 @@ static int cmtp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne
 
                err = cmtp_get_connlist(&cl);
 
-               if (!err && put_user(cl.cnum, (uint32_t __user *) arg))
+               if (!err && put_user(cl.cnum, (u32 __user *) arg))
                        err = -EFAULT;
 
                return err;
index 07bc69ed9498c276e272d9215a3189b0df7beb30..947172bf16219e7d1df1f0efcf9c3c70018c7870 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/init.h>
 #include <linux/skbuff.h>
 #include <linux/interrupt.h>
-#include <linux/notifier.h>
 #include <net/sock.h>
 
 #include <asm/system.h>
@@ -51,7 +50,7 @@ static void hci_le_connect(struct hci_conn *conn)
        struct hci_cp_le_create_conn cp;
 
        conn->state = BT_CONNECT;
-       conn->out = 1;
+       conn->out = true;
        conn->link_mode |= HCI_LM_MASTER;
        conn->sec_level = BT_SECURITY_LOW;
 
@@ -80,10 +79,10 @@ void hci_acl_connect(struct hci_conn *conn)
        struct inquiry_entry *ie;
        struct hci_cp_create_conn cp;
 
-       BT_DBG("%p", conn);
+       BT_DBG("hcon %p", conn);
 
        conn->state = BT_CONNECT;
-       conn->out = 1;
+       conn->out = true;
 
        conn->link_mode = HCI_LM_MASTER;
 
@@ -105,7 +104,8 @@ void hci_acl_connect(struct hci_conn *conn)
                }
 
                memcpy(conn->dev_class, ie->data.dev_class, 3);
-               conn->ssp_mode = ie->data.ssp_mode;
+               if (ie->data.ssp_mode > 0)
+                       set_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
        }
 
        cp.pkt_type = cpu_to_le16(conn->pkt_type);
@@ -151,7 +151,7 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle)
        BT_DBG("%p", conn);
 
        conn->state = BT_CONNECT;
-       conn->out = 1;
+       conn->out = true;
 
        conn->attempt++;
 
@@ -169,7 +169,7 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle)
        BT_DBG("%p", conn);
 
        conn->state = BT_CONNECT;
-       conn->out = 1;
+       conn->out = true;
 
        conn->attempt++;
 
@@ -279,16 +279,13 @@ static void hci_conn_timeout(struct work_struct *work)
 {
        struct hci_conn *conn = container_of(work, struct hci_conn,
                                                        disc_work.work);
-       struct hci_dev *hdev = conn->hdev;
        __u8 reason;
 
-       BT_DBG("conn %p state %d", conn, conn->state);
+       BT_DBG("conn %p state %s", conn, state_to_string(conn->state));
 
        if (atomic_read(&conn->refcnt))
                return;
 
-       hci_dev_lock(hdev);
-
        switch (conn->state) {
        case BT_CONNECT:
        case BT_CONNECT2:
@@ -308,8 +305,6 @@ static void hci_conn_timeout(struct work_struct *work)
                conn->state = BT_CLOSED;
                break;
        }
-
-       hci_dev_unlock(hdev);
 }
 
 /* Enter sniff mode */
@@ -337,7 +332,7 @@ static void hci_conn_enter_sniff_mode(struct hci_conn *conn)
                hci_send_cmd(hdev, HCI_OP_SNIFF_SUBRATE, sizeof(cp), &cp);
        }
 
-       if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
+       if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) {
                struct hci_cp_sniff_mode cp;
                cp.handle       = cpu_to_le16(conn->handle);
                cp.max_interval = cpu_to_le16(hdev->sniff_max_interval);
@@ -372,7 +367,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
 
        BT_DBG("%s dst %s", hdev->name, batostr(dst));
 
-       conn = kzalloc(sizeof(struct hci_conn), GFP_ATOMIC);
+       conn = kzalloc(sizeof(struct hci_conn), GFP_KERNEL);
        if (!conn)
                return NULL;
 
@@ -386,7 +381,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
        conn->remote_auth = 0xff;
        conn->key_type = 0xff;
 
-       conn->power_save = 1;
+       set_bit(HCI_CONN_POWER_SAVE, &conn->flags);
        conn->disc_timeout = HCI_DISCONN_TIMEOUT;
 
        switch (type) {
@@ -407,7 +402,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
 
        skb_queue_head_init(&conn->data_q);
 
-       INIT_LIST_HEAD(&conn->chan_list);;
+       INIT_LIST_HEAD(&conn->chan_list);
 
        INIT_DELAYED_WORK(&conn->disc_work, hci_conn_timeout);
        setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn);
@@ -555,7 +550,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
        if (!acl) {
                acl = hci_conn_add(hdev, ACL_LINK, dst);
                if (!acl)
-                       return NULL;
+                       return ERR_PTR(-ENOMEM);
        }
 
        hci_conn_hold(acl);
@@ -575,7 +570,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
                sco = hci_conn_add(hdev, type, dst);
                if (!sco) {
                        hci_conn_put(acl);
-                       return NULL;
+                       return ERR_PTR(-ENOMEM);
                }
        }
 
@@ -586,12 +581,12 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
 
        if (acl->state == BT_CONNECTED &&
                        (sco->state == BT_OPEN || sco->state == BT_CLOSED)) {
-               acl->power_save = 1;
+               set_bit(HCI_CONN_POWER_SAVE, &acl->flags);
                hci_conn_enter_active_mode(acl, BT_POWER_FORCE_ACTIVE_ON);
 
-               if (test_bit(HCI_CONN_MODE_CHANGE_PEND, &acl->pend)) {
+               if (test_bit(HCI_CONN_MODE_CHANGE_PEND, &acl->flags)) {
                        /* defer SCO setup until mode change completed */
-                       set_bit(HCI_CONN_SCO_SETUP_PEND, &acl->pend);
+                       set_bit(HCI_CONN_SCO_SETUP_PEND, &acl->flags);
                        return sco;
                }
 
@@ -607,8 +602,7 @@ int hci_conn_check_link_mode(struct hci_conn *conn)
 {
        BT_DBG("conn %p", conn);
 
-       if (conn->ssp_mode > 0 && conn->hdev->ssp_mode > 0 &&
-                                       !(conn->link_mode & HCI_LM_ENCRYPT))
+       if (hci_conn_ssp_enabled(conn) && !(conn->link_mode & HCI_LM_ENCRYPT))
                return 0;
 
        return 1;
@@ -633,17 +627,17 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
 
        conn->auth_type = auth_type;
 
-       if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
+       if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) {
                struct hci_cp_auth_requested cp;
 
                /* encrypt must be pending if auth is also pending */
-               set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
+               set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
 
                cp.handle = cpu_to_le16(conn->handle);
                hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED,
                                                        sizeof(cp), &cp);
                if (conn->key_type != 0xff)
-                       set_bit(HCI_CONN_REAUTH_PEND, &conn->pend);
+                       set_bit(HCI_CONN_REAUTH_PEND, &conn->flags);
        }
 
        return 0;
@@ -654,7 +648,7 @@ static void hci_conn_encrypt(struct hci_conn *conn)
 {
        BT_DBG("conn %p", conn);
 
-       if (!test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
+       if (!test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) {
                struct hci_cp_set_conn_encrypt cp;
                cp.handle  = cpu_to_le16(conn->handle);
                cp.encrypt = 0x01;
@@ -674,8 +668,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
 
        /* For non 2.1 devices and low security level we don't need the link
           key. */
-       if (sec_level == BT_SECURITY_LOW &&
-                               (!conn->ssp_mode || !conn->hdev->ssp_mode))
+       if (sec_level == BT_SECURITY_LOW && !hci_conn_ssp_enabled(conn))
                return 1;
 
        /* For other security levels we need the link key. */
@@ -704,7 +697,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_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags))
                return 0;
 
        if (!hci_conn_auth(conn, sec_level, auth_type))
@@ -739,7 +732,7 @@ int hci_conn_change_link_key(struct hci_conn *conn)
 {
        BT_DBG("conn %p", conn);
 
-       if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
+       if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) {
                struct hci_cp_change_conn_link_key cp;
                cp.handle = cpu_to_le16(conn->handle);
                hci_send_cmd(conn->hdev, HCI_OP_CHANGE_CONN_LINK_KEY,
@@ -758,7 +751,7 @@ int hci_conn_switch_role(struct hci_conn *conn, __u8 role)
        if (!role && conn->link_mode & HCI_LM_MASTER)
                return 1;
 
-       if (!test_and_set_bit(HCI_CONN_RSWITCH_PEND, &conn->pend)) {
+       if (!test_and_set_bit(HCI_CONN_RSWITCH_PEND, &conn->flags)) {
                struct hci_cp_switch_role cp;
                bacpy(&cp.bdaddr, &conn->dst);
                cp.role = role;
@@ -782,10 +775,10 @@ void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active)
        if (conn->mode != HCI_CM_SNIFF)
                goto timer;
 
-       if (!conn->power_save && !force_active)
+       if (!test_bit(HCI_CONN_POWER_SAVE, &conn->flags) && !force_active)
                goto timer;
 
-       if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
+       if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) {
                struct hci_cp_exit_sniff_mode cp;
                cp.handle = cpu_to_le16(conn->handle);
                hci_send_cmd(hdev, HCI_OP_EXIT_SNIFF_MODE, sizeof(cp), &cp);
@@ -801,11 +794,11 @@ timer:
 void hci_conn_hash_flush(struct hci_dev *hdev)
 {
        struct hci_conn_hash *h = &hdev->conn_hash;
-       struct hci_conn *c;
+       struct hci_conn *c, *n;
 
        BT_DBG("hdev %s", hdev->name);
 
-       list_for_each_entry_rcu(c, &h->list, list) {
+       list_for_each_entry_safe(c, n, &h->list, list) {
                c->state = BT_CLOSED;
 
                hci_proto_disconn_cfm(c, HCI_ERROR_LOCAL_HOST_TERM);
@@ -950,7 +943,7 @@ struct hci_chan *hci_chan_create(struct hci_conn *conn)
 
        BT_DBG("%s conn %p", hdev->name, conn);
 
-       chan = kzalloc(sizeof(struct hci_chan), GFP_ATOMIC);
+       chan = kzalloc(sizeof(struct hci_chan), GFP_KERNEL);
        if (!chan)
                return NULL;
 
@@ -981,10 +974,10 @@ int hci_chan_del(struct hci_chan *chan)
 
 void hci_chan_list_flush(struct hci_conn *conn)
 {
-       struct hci_chan *chan;
+       struct hci_chan *chan, *n;
 
        BT_DBG("conn %p", conn);
 
-       list_for_each_entry_rcu(chan, &conn->chan_list, list)
+       list_for_each_entry_safe(chan, n, &conn->chan_list, list)
                hci_chan_del(chan);
 }
index 5aeb62491198b193b26e7b5e2c46a90b089bf848..59ec99eb739b2d403ce2a25630d50d195c9b1263 100644 (file)
@@ -40,7 +40,6 @@
 #include <linux/skbuff.h>
 #include <linux/workqueue.h>
 #include <linux/interrupt.h>
-#include <linux/notifier.h>
 #include <linux/rfkill.h>
 #include <linux/timer.h>
 #include <linux/crypto.h>
@@ -55,8 +54,6 @@
 
 #define AUTO_OFF_TIMEOUT 2000
 
-bool enable_hs;
-
 static void hci_rx_work(struct work_struct *work);
 static void hci_cmd_work(struct work_struct *work);
 static void hci_tx_work(struct work_struct *work);
@@ -69,24 +66,11 @@ DEFINE_RWLOCK(hci_dev_list_lock);
 LIST_HEAD(hci_cb_list);
 DEFINE_RWLOCK(hci_cb_list_lock);
 
-/* HCI notifiers list */
-static ATOMIC_NOTIFIER_HEAD(hci_notifier);
-
 /* ---- HCI notifications ---- */
 
-int hci_register_notifier(struct notifier_block *nb)
-{
-       return atomic_notifier_chain_register(&hci_notifier, nb);
-}
-
-int hci_unregister_notifier(struct notifier_block *nb)
-{
-       return atomic_notifier_chain_unregister(&hci_notifier, nb);
-}
-
 static void hci_notify(struct hci_dev *hdev, int event)
 {
-       atomic_notifier_call_chain(&hci_notifier, event, hdev);
+       hci_sock_dev_event(hdev, event);
 }
 
 /* ---- HCI requests ---- */
@@ -98,8 +82,28 @@ void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result)
        /* If this is the init phase check if the completed command matches
         * the last init command, and if not just return.
         */
-       if (test_bit(HCI_INIT, &hdev->flags) && hdev->init_last_cmd != cmd)
+       if (test_bit(HCI_INIT, &hdev->flags) && hdev->init_last_cmd != cmd) {
+               struct hci_command_hdr *sent = (void *) hdev->sent_cmd->data;
+               struct sk_buff *skb;
+
+               /* Some CSR based controllers generate a spontaneous
+                * reset complete event during init and any pending
+                * command will never be completed. In such a case we
+                * need to resend whatever was the last sent
+                * command.
+                */
+
+               if (cmd != HCI_OP_RESET || sent->opcode == HCI_OP_RESET)
+                       return;
+
+               skb = skb_clone(hdev->sent_cmd, GFP_ATOMIC);
+               if (skb) {
+                       skb_queue_head(&hdev->cmd_q, skb);
+                       queue_work(hdev->workqueue, &hdev->cmd_work);
+               }
+
                return;
+       }
 
        if (hdev->req_status == HCI_REQ_PEND) {
                hdev->req_result = result;
@@ -355,72 +359,209 @@ struct hci_dev *hci_dev_get(int index)
 }
 
 /* ---- Inquiry support ---- */
-static void inquiry_cache_flush(struct hci_dev *hdev)
+
+bool hci_discovery_active(struct hci_dev *hdev)
 {
-       struct inquiry_cache *cache = &hdev->inq_cache;
-       struct inquiry_entry *next  = cache->list, *e;
+       struct discovery_state *discov = &hdev->discovery;
+
+       switch (discov->state) {
+       case DISCOVERY_FINDING:
+       case DISCOVERY_RESOLVING:
+               return true;
+
+       default:
+               return false;
+       }
+}
+
+void hci_discovery_set_state(struct hci_dev *hdev, int state)
+{
+       BT_DBG("%s state %u -> %u", hdev->name, hdev->discovery.state, state);
+
+       if (hdev->discovery.state == state)
+               return;
+
+       switch (state) {
+       case DISCOVERY_STOPPED:
+               if (hdev->discovery.state != DISCOVERY_STARTING)
+                       mgmt_discovering(hdev, 0);
+               hdev->discovery.type = 0;
+               break;
+       case DISCOVERY_STARTING:
+               break;
+       case DISCOVERY_FINDING:
+               mgmt_discovering(hdev, 1);
+               break;
+       case DISCOVERY_RESOLVING:
+               break;
+       case DISCOVERY_STOPPING:
+               break;
+       }
+
+       hdev->discovery.state = state;
+}
 
-       BT_DBG("cache %p", cache);
+static void inquiry_cache_flush(struct hci_dev *hdev)
+{
+       struct discovery_state *cache = &hdev->discovery;
+       struct inquiry_entry *p, *n;
 
-       cache->list = NULL;
-       while ((e = next)) {
-               next = e->next;
-               kfree(e);
+       list_for_each_entry_safe(p, n, &cache->all, all) {
+               list_del(&p->all);
+               kfree(p);
        }
+
+       INIT_LIST_HEAD(&cache->unknown);
+       INIT_LIST_HEAD(&cache->resolve);
 }
 
 struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr)
 {
-       struct inquiry_cache *cache = &hdev->inq_cache;
+       struct discovery_state *cache = &hdev->discovery;
        struct inquiry_entry *e;
 
        BT_DBG("cache %p, %s", cache, batostr(bdaddr));
 
-       for (e = cache->list; e; e = e->next)
+       list_for_each_entry(e, &cache->all, all) {
+               if (!bacmp(&e->data.bdaddr, bdaddr))
+                       return e;
+       }
+
+       return NULL;
+}
+
+struct inquiry_entry *hci_inquiry_cache_lookup_unknown(struct hci_dev *hdev,
+                                                      bdaddr_t *bdaddr)
+{
+       struct discovery_state *cache = &hdev->discovery;
+       struct inquiry_entry *e;
+
+       BT_DBG("cache %p, %s", cache, batostr(bdaddr));
+
+       list_for_each_entry(e, &cache->unknown, list) {
+               if (!bacmp(&e->data.bdaddr, bdaddr))
+                       return e;
+       }
+
+       return NULL;
+}
+
+struct inquiry_entry *hci_inquiry_cache_lookup_resolve(struct hci_dev *hdev,
+                                                      bdaddr_t *bdaddr,
+                                                      int state)
+{
+       struct discovery_state *cache = &hdev->discovery;
+       struct inquiry_entry *e;
+
+       BT_DBG("cache %p bdaddr %s state %d", cache, batostr(bdaddr), state);
+
+       list_for_each_entry(e, &cache->resolve, list) {
+               if (!bacmp(bdaddr, BDADDR_ANY) && e->name_state == state)
+                       return e;
                if (!bacmp(&e->data.bdaddr, bdaddr))
+                       return e;
+       }
+
+       return NULL;
+}
+
+void hci_inquiry_cache_update_resolve(struct hci_dev *hdev,
+                                     struct inquiry_entry *ie)
+{
+       struct discovery_state *cache = &hdev->discovery;
+       struct list_head *pos = &cache->resolve;
+       struct inquiry_entry *p;
+
+       list_del(&ie->list);
+
+       list_for_each_entry(p, &cache->resolve, list) {
+               if (p->name_state != NAME_PENDING &&
+                               abs(p->data.rssi) >= abs(ie->data.rssi))
                        break;
-       return e;
+               pos = &p->list;
+       }
+
+       list_add(&ie->list, pos);
 }
 
-void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data)
+bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data,
+                             bool name_known, bool *ssp)
 {
-       struct inquiry_cache *cache = &hdev->inq_cache;
+       struct discovery_state *cache = &hdev->discovery;
        struct inquiry_entry *ie;
 
        BT_DBG("cache %p, %s", cache, batostr(&data->bdaddr));
 
+       if (ssp)
+               *ssp = data->ssp_mode;
+
        ie = hci_inquiry_cache_lookup(hdev, &data->bdaddr);
-       if (!ie) {
-               /* Entry not in the cache. Add new one. */
-               ie = kzalloc(sizeof(struct inquiry_entry), GFP_ATOMIC);
-               if (!ie)
-                       return;
+       if (ie) {
+               if (ie->data.ssp_mode && ssp)
+                       *ssp = true;
+
+               if (ie->name_state == NAME_NEEDED &&
+                                               data->rssi != ie->data.rssi) {
+                       ie->data.rssi = data->rssi;
+                       hci_inquiry_cache_update_resolve(hdev, ie);
+               }
 
-               ie->next = cache->list;
-               cache->list = ie;
+               goto update;
+       }
+
+       /* Entry not in the cache. Add new one. */
+       ie = kzalloc(sizeof(struct inquiry_entry), GFP_ATOMIC);
+       if (!ie)
+               return false;
+
+       list_add(&ie->all, &cache->all);
+
+       if (name_known) {
+               ie->name_state = NAME_KNOWN;
+       } else {
+               ie->name_state = NAME_NOT_KNOWN;
+               list_add(&ie->list, &cache->unknown);
+       }
+
+update:
+       if (name_known && ie->name_state != NAME_KNOWN &&
+                                       ie->name_state != NAME_PENDING) {
+               ie->name_state = NAME_KNOWN;
+               list_del(&ie->list);
        }
 
        memcpy(&ie->data, data, sizeof(*data));
        ie->timestamp = jiffies;
        cache->timestamp = jiffies;
+
+       if (ie->name_state == NAME_NOT_KNOWN)
+               return false;
+
+       return true;
 }
 
 static int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf)
 {
-       struct inquiry_cache *cache = &hdev->inq_cache;
+       struct discovery_state *cache = &hdev->discovery;
        struct inquiry_info *info = (struct inquiry_info *) buf;
        struct inquiry_entry *e;
        int copied = 0;
 
-       for (e = cache->list; e && copied < num; e = e->next, copied++) {
+       list_for_each_entry(e, &cache->all, all) {
                struct inquiry_data *data = &e->data;
+
+               if (copied >= num)
+                       break;
+
                bacpy(&info->bdaddr, &data->bdaddr);
                info->pscan_rep_mode    = data->pscan_rep_mode;
                info->pscan_period_mode = data->pscan_period_mode;
                info->pscan_mode        = data->pscan_mode;
                memcpy(info->dev_class, data->dev_class, 3);
                info->clock_offset      = data->clock_offset;
+
                info++;
+               copied++;
        }
 
        BT_DBG("cache %p, copied %d", cache, copied);
@@ -567,7 +708,7 @@ 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)) {
+               if (!test_bit(HCI_SETUP, &hdev->dev_flags)) {
                        hci_dev_lock(hdev);
                        mgmt_powered(hdev, 1);
                        hci_dev_unlock(hdev);
@@ -603,6 +744,8 @@ static int hci_dev_do_close(struct hci_dev *hdev)
 {
        BT_DBG("%s %p", hdev->name, hdev);
 
+       cancel_work_sync(&hdev->le_scan);
+
        hci_req_cancel(hdev, ENODEV);
        hci_req_lock(hdev);
 
@@ -619,14 +762,14 @@ static int hci_dev_do_close(struct hci_dev *hdev)
        if (hdev->discov_timeout > 0) {
                cancel_delayed_work(&hdev->discov_off);
                hdev->discov_timeout = 0;
+               clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
        }
 
-       if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
-               cancel_delayed_work(&hdev->power_off);
-
-       if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->flags))
+       if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
                cancel_delayed_work(&hdev->service_cache);
 
+       cancel_delayed_work_sync(&hdev->le_scan_disable);
+
        hci_dev_lock(hdev);
        inquiry_cache_flush(hdev);
        hci_conn_hash_flush(hdev);
@@ -667,13 +810,18 @@ static int hci_dev_do_close(struct hci_dev *hdev)
         * and no tasks are scheduled. */
        hdev->close(hdev);
 
-       hci_dev_lock(hdev);
-       mgmt_powered(hdev, 0);
-       hci_dev_unlock(hdev);
+       if (!test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
+               hci_dev_lock(hdev);
+               mgmt_powered(hdev, 0);
+               hci_dev_unlock(hdev);
+       }
 
        /* Clear flags */
        hdev->flags = 0;
 
+       memset(hdev->eir, 0, sizeof(hdev->eir));
+       memset(hdev->dev_class, 0, sizeof(hdev->dev_class));
+
        hci_req_unlock(hdev);
 
        hci_dev_put(hdev);
@@ -688,7 +836,12 @@ int hci_dev_close(__u16 dev)
        hdev = hci_dev_get(dev);
        if (!hdev)
                return -ENODEV;
+
+       if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags))
+               cancel_delayed_work(&hdev->power_off);
+
        err = hci_dev_do_close(hdev);
+
        hci_dev_put(hdev);
        return err;
 }
@@ -847,11 +1000,11 @@ int hci_get_dev_list(void __user *arg)
 
        read_lock(&hci_dev_list_lock);
        list_for_each_entry(hdev, &hci_dev_list, list) {
-               if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
+               if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags))
                        cancel_delayed_work(&hdev->power_off);
 
-               if (!test_bit(HCI_MGMT, &hdev->flags))
-                       set_bit(HCI_PAIRABLE, &hdev->flags);
+               if (!test_bit(HCI_MGMT, &hdev->dev_flags))
+                       set_bit(HCI_PAIRABLE, &hdev->dev_flags);
 
                (dr + n)->dev_id  = hdev->id;
                (dr + n)->dev_opt = hdev->flags;
@@ -883,11 +1036,11 @@ int hci_get_dev_info(void __user *arg)
        if (!hdev)
                return -ENODEV;
 
-       if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
+       if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags))
                cancel_delayed_work_sync(&hdev->power_off);
 
-       if (!test_bit(HCI_MGMT, &hdev->flags))
-               set_bit(HCI_PAIRABLE, &hdev->flags);
+       if (!test_bit(HCI_MGMT, &hdev->dev_flags))
+               set_bit(HCI_PAIRABLE, &hdev->dev_flags);
 
        strcpy(di.name, hdev->name);
        di.bdaddr   = hdev->bdaddr;
@@ -967,11 +1120,11 @@ static void hci_power_on(struct work_struct *work)
        if (hci_dev_open(hdev->id) < 0)
                return;
 
-       if (test_bit(HCI_AUTO_OFF, &hdev->flags))
+       if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
                schedule_delayed_work(&hdev->power_off,
                                        msecs_to_jiffies(AUTO_OFF_TIMEOUT));
 
-       if (test_and_clear_bit(HCI_SETUP, &hdev->flags))
+       if (test_and_clear_bit(HCI_SETUP, &hdev->dev_flags))
                mgmt_index_added(hdev);
 }
 
@@ -982,9 +1135,7 @@ static void hci_power_off(struct work_struct *work)
 
        BT_DBG("%s", hdev->name);
 
-       clear_bit(HCI_AUTO_OFF, &hdev->flags);
-
-       hci_dev_close(hdev->id);
+       hci_dev_do_close(hdev);
 }
 
 static void hci_discov_off(struct work_struct *work)
@@ -1037,6 +1188,18 @@ int hci_link_keys_clear(struct hci_dev *hdev)
        return 0;
 }
 
+int hci_smp_ltks_clear(struct hci_dev *hdev)
+{
+       struct smp_ltk *k, *tmp;
+
+       list_for_each_entry_safe(k, tmp, &hdev->long_term_keys, list) {
+               list_del(&k->list);
+               kfree(k);
+       }
+
+       return 0;
+}
+
 struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
 {
        struct link_key *k;
@@ -1084,44 +1247,38 @@ static int hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn,
        return 0;
 }
 
-struct link_key *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8])
+struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8])
 {
-       struct link_key *k;
+       struct smp_ltk *k;
 
-       list_for_each_entry(k, &hdev->link_keys, list) {
-               struct key_master_id *id;
-
-               if (k->type != HCI_LK_SMP_LTK)
+       list_for_each_entry(k, &hdev->long_term_keys, list) {
+               if (k->ediv != ediv ||
+                               memcmp(rand, k->rand, sizeof(k->rand)))
                        continue;
 
-               if (k->dlen != sizeof(*id))
-                       continue;
-
-               id = (void *) &k->data;
-               if (id->ediv == ediv &&
-                               (memcmp(rand, id->rand, sizeof(id->rand)) == 0))
-                       return k;
+               return k;
        }
 
        return NULL;
 }
 EXPORT_SYMBOL(hci_find_ltk);
 
-struct link_key *hci_find_link_key_type(struct hci_dev *hdev,
-                                       bdaddr_t *bdaddr, u8 type)
+struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                    u8 addr_type)
 {
-       struct link_key *k;
+       struct smp_ltk *k;
 
-       list_for_each_entry(k, &hdev->link_keys, list)
-               if (k->type == type && bacmp(bdaddr, &k->bdaddr) == 0)
+       list_for_each_entry(k, &hdev->long_term_keys, list)
+               if (addr_type == k->bdaddr_type &&
+                                       bacmp(bdaddr, &k->bdaddr) == 0)
                        return k;
 
        return NULL;
 }
-EXPORT_SYMBOL(hci_find_link_key_type);
+EXPORT_SYMBOL(hci_find_ltk_by_addr);
 
 int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
-                               bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len)
+                    bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len)
 {
        struct link_key *key, *old_key;
        u8 old_key_type, persistent;
@@ -1175,40 +1332,39 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
        return 0;
 }
 
-int hci_add_ltk(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
-                       u8 key_size, __le16 ediv, u8 rand[8], u8 ltk[16])
+int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type,
+               int new_key, u8 authenticated, u8 tk[16], u8 enc_size, u16
+               ediv, u8 rand[8])
 {
-       struct link_key *key, *old_key;
-       struct key_master_id *id;
-       u8 old_key_type;
+       struct smp_ltk *key, *old_key;
 
-       BT_DBG("%s addr %s", hdev->name, batostr(bdaddr));
+       if (!(type & HCI_SMP_STK) && !(type & HCI_SMP_LTK))
+               return 0;
 
-       old_key = hci_find_link_key_type(hdev, bdaddr, HCI_LK_SMP_LTK);
-       if (old_key) {
+       old_key = hci_find_ltk_by_addr(hdev, bdaddr, addr_type);
+       if (old_key)
                key = old_key;
-               old_key_type = old_key->type;
-       } else {
-               key = kzalloc(sizeof(*key) + sizeof(*id), GFP_ATOMIC);
+       else {
+               key = kzalloc(sizeof(*key), GFP_ATOMIC);
                if (!key)
                        return -ENOMEM;
-               list_add(&key->list, &hdev->link_keys);
-               old_key_type = 0xff;
+               list_add(&key->list, &hdev->long_term_keys);
        }
 
-       key->dlen = sizeof(*id);
-
        bacpy(&key->bdaddr, bdaddr);
-       memcpy(key->val, ltk, sizeof(key->val));
-       key->type = HCI_LK_SMP_LTK;
-       key->pin_len = key_size;
+       key->bdaddr_type = addr_type;
+       memcpy(key->val, tk, sizeof(key->val));
+       key->authenticated = authenticated;
+       key->ediv = ediv;
+       key->enc_size = enc_size;
+       key->type = type;
+       memcpy(key->rand, rand, sizeof(key->rand));
 
-       id = (void *) &key->data;
-       id->ediv = ediv;
-       memcpy(id->rand, rand, sizeof(id->rand));
+       if (!new_key)
+               return 0;
 
-       if (new_key)
-               mgmt_new_link_key(hdev, key, old_key_type);
+       if (type & HCI_SMP_LTK)
+               mgmt_new_ltk(hdev, key, 1);
 
        return 0;
 }
@@ -1229,6 +1385,23 @@ int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
        return 0;
 }
 
+int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr)
+{
+       struct smp_ltk *k, *tmp;
+
+       list_for_each_entry_safe(k, tmp, &hdev->long_term_keys, list) {
+               if (bacmp(bdaddr, &k->bdaddr))
+                       continue;
+
+               BT_DBG("%s removing %s", hdev->name, batostr(bdaddr));
+
+               list_del(&k->list);
+               kfree(k);
+       }
+
+       return 0;
+}
+
 /* HCI command timer function */
 static void hci_cmd_timer(unsigned long arg)
 {
@@ -1240,7 +1413,7 @@ static void hci_cmd_timer(unsigned long arg)
 }
 
 struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev,
-                                                       bdaddr_t *bdaddr)
+                                         bdaddr_t *bdaddr)
 {
        struct oob_data *data;
 
@@ -1280,7 +1453,7 @@ int hci_remote_oob_data_clear(struct hci_dev *hdev)
 }
 
 int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
-                                                               u8 *randomizer)
+                           u8 *randomizer)
 {
        struct oob_data *data;
 
@@ -1303,8 +1476,7 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
        return 0;
 }
 
-struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev,
-                                               bdaddr_t *bdaddr)
+struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr)
 {
        struct bdaddr_list *b;
 
@@ -1331,7 +1503,7 @@ int hci_blacklist_clear(struct hci_dev *hdev)
        return 0;
 }
 
-int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr)
+int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
 {
        struct bdaddr_list *entry;
 
@@ -1349,10 +1521,10 @@ int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr)
 
        list_add(&entry->list, &hdev->blacklist);
 
-       return mgmt_device_blocked(hdev, bdaddr);
+       return mgmt_device_blocked(hdev, bdaddr, type);
 }
 
-int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr)
+int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
 {
        struct bdaddr_list *entry;
 
@@ -1366,13 +1538,13 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr)
        list_del(&entry->list);
        kfree(entry);
 
-       return mgmt_device_unblocked(hdev, bdaddr);
+       return mgmt_device_unblocked(hdev, bdaddr, type);
 }
 
 static void hci_clear_adv_cache(struct work_struct *work)
 {
        struct hci_dev *hdev = container_of(work, struct hci_dev,
-                                                       adv_work.work);
+                                           adv_work.work);
 
        hci_dev_lock(hdev);
 
@@ -1415,11 +1587,7 @@ static inline int is_connectable_adv(u8 evt_type)
 }
 
 int hci_add_adv_entry(struct hci_dev *hdev,
-                                       struct hci_ev_le_advertising_info *ev)
-{
-       struct adv_entry *entry;
-
-       if (!is_connectable_adv(ev->evt_type))
+                                       struct hci_ev_le_advertising_info *ev) { struct adv_entry *entry; if (!is_connectable_adv(ev->evt_type))
                return -EINVAL;
 
        /* Only new entries should be added to adv_entries. So, if
@@ -1427,7 +1595,7 @@ int hci_add_adv_entry(struct hci_dev *hdev,
        if (hci_find_adv_entry(hdev, &ev->bdaddr))
                return 0;
 
-       entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
+       entry = kzalloc(sizeof(*entry), GFP_KERNEL);
        if (!entry)
                return -ENOMEM;
 
@@ -1442,16 +1610,116 @@ int hci_add_adv_entry(struct hci_dev *hdev,
        return 0;
 }
 
+static void le_scan_param_req(struct hci_dev *hdev, unsigned long opt)
+{
+       struct le_scan_params *param =  (struct le_scan_params *) opt;
+       struct hci_cp_le_set_scan_param cp;
+
+       memset(&cp, 0, sizeof(cp));
+       cp.type = param->type;
+       cp.interval = cpu_to_le16(param->interval);
+       cp.window = cpu_to_le16(param->window);
+
+       hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_PARAM, sizeof(cp), &cp);
+}
+
+static void le_scan_enable_req(struct hci_dev *hdev, unsigned long opt)
+{
+       struct hci_cp_le_set_scan_enable cp;
+
+       memset(&cp, 0, sizeof(cp));
+       cp.enable = 1;
+
+       hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
+}
+
+static int hci_do_le_scan(struct hci_dev *hdev, u8 type, u16 interval,
+                         u16 window, int timeout)
+{
+       long timeo = msecs_to_jiffies(3000);
+       struct le_scan_params param;
+       int err;
+
+       BT_DBG("%s", hdev->name);
+
+       if (test_bit(HCI_LE_SCAN, &hdev->dev_flags))
+               return -EINPROGRESS;
+
+       param.type = type;
+       param.interval = interval;
+       param.window = window;
+
+       hci_req_lock(hdev);
+
+       err = __hci_request(hdev, le_scan_param_req, (unsigned long) &param,
+                           timeo);
+       if (!err)
+               err = __hci_request(hdev, le_scan_enable_req, 0, timeo);
+
+       hci_req_unlock(hdev);
+
+       if (err < 0)
+               return err;
+
+       schedule_delayed_work(&hdev->le_scan_disable,
+                             msecs_to_jiffies(timeout));
+
+       return 0;
+}
+
+static void le_scan_disable_work(struct work_struct *work)
+{
+       struct hci_dev *hdev = container_of(work, struct hci_dev,
+                                           le_scan_disable.work);
+       struct hci_cp_le_set_scan_enable cp;
+
+       BT_DBG("%s", hdev->name);
+
+       memset(&cp, 0, sizeof(cp));
+
+       hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
+}
+
+static void le_scan_work(struct work_struct *work)
+{
+       struct hci_dev *hdev = container_of(work, struct hci_dev, le_scan);
+       struct le_scan_params *param = &hdev->le_scan_params;
+
+       BT_DBG("%s", hdev->name);
+
+       hci_do_le_scan(hdev, param->type, param->interval, param->window,
+                      param->timeout);
+}
+
+int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window,
+               int timeout)
+{
+       struct le_scan_params *param = &hdev->le_scan_params;
+
+       BT_DBG("%s", hdev->name);
+
+       if (work_busy(&hdev->le_scan))
+               return -EINPROGRESS;
+
+       param->type = type;
+       param->interval = interval;
+       param->window = window;
+       param->timeout = timeout;
+
+       queue_work(system_long_wq, &hdev->le_scan);
+
+       return 0;
+}
+
 /* Register HCI device */
 int hci_register_dev(struct hci_dev *hdev)
 {
        struct list_head *head = &hci_dev_list, *p;
        int i, id, error;
 
-       BT_DBG("%p name %s bus %d owner %p", hdev, hdev->name,
-                                               hdev->bus, hdev->owner);
+       BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
 
-       if (!hdev->open || !hdev->close || !hdev->destruct)
+       if (!hdev->open || !hdev->close)
                return -EINVAL;
 
        /* Do not allow HCI_AMP devices to register at index 0,
@@ -1472,7 +1740,6 @@ int hci_register_dev(struct hci_dev *hdev)
        hdev->id = id;
        list_add_tail(&hdev->list, head);
 
-       atomic_set(&hdev->refcnt, 1);
        mutex_init(&hdev->lock);
 
        hdev->flags = 0;
@@ -1503,7 +1770,7 @@ int hci_register_dev(struct hci_dev *hdev)
        init_waitqueue_head(&hdev->req_wait_q);
        mutex_init(&hdev->req_lock);
 
-       inquiry_cache_init(hdev);
+       discovery_init(hdev);
 
        hci_conn_hash_init(hdev);
 
@@ -1514,6 +1781,7 @@ int hci_register_dev(struct hci_dev *hdev)
        INIT_LIST_HEAD(&hdev->uuids);
 
        INIT_LIST_HEAD(&hdev->link_keys);
+       INIT_LIST_HEAD(&hdev->long_term_keys);
 
        INIT_LIST_HEAD(&hdev->remote_oob_data);
 
@@ -1529,6 +1797,10 @@ int hci_register_dev(struct hci_dev *hdev)
 
        atomic_set(&hdev->promisc, 0);
 
+       INIT_WORK(&hdev->le_scan, le_scan_work);
+
+       INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work);
+
        write_unlock(&hci_dev_list_lock);
 
        hdev->workqueue = alloc_workqueue(hdev->name, WQ_HIGHPRI | WQ_UNBOUND |
@@ -1551,11 +1823,12 @@ int hci_register_dev(struct hci_dev *hdev)
                }
        }
 
-       set_bit(HCI_AUTO_OFF, &hdev->flags);
-       set_bit(HCI_SETUP, &hdev->flags);
+       set_bit(HCI_AUTO_OFF, &hdev->dev_flags);
+       set_bit(HCI_SETUP, &hdev->dev_flags);
        schedule_work(&hdev->power_on);
 
        hci_notify(hdev, HCI_DEV_REG);
+       hci_dev_hold(hdev);
 
        return id;
 
@@ -1587,7 +1860,7 @@ void 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)) {
+                               !test_bit(HCI_SETUP, &hdev->dev_flags)) {
                hci_dev_lock(hdev);
                mgmt_index_removed(hdev);
                hci_dev_unlock(hdev);
@@ -1614,11 +1887,12 @@ void hci_unregister_dev(struct hci_dev *hdev)
        hci_blacklist_clear(hdev);
        hci_uuids_clear(hdev);
        hci_link_keys_clear(hdev);
+       hci_smp_ltks_clear(hdev);
        hci_remote_oob_data_clear(hdev);
        hci_adv_entries_clear(hdev);
        hci_dev_unlock(hdev);
 
-       __hci_dev_put(hdev);
+       hci_dev_put(hdev);
 }
 EXPORT_SYMBOL(hci_unregister_dev);
 
@@ -1706,7 +1980,7 @@ static int hci_reassembly(struct hci_dev *hdev, int type, void *data,
 
        while (count) {
                scb = (void *) skb->cb;
-               len = min(scb->expect, (__u16)count);
+               len = min_t(uint, scb->expect, count);
 
                memcpy(skb_put(skb, len), data, len);
 
@@ -1862,11 +2136,15 @@ static int hci_send_frame(struct sk_buff *skb)
 
        BT_DBG("%s type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len);
 
-       if (atomic_read(&hdev->promisc)) {
-               /* Time stamp */
-               __net_timestamp(skb);
+       /* Time stamp */
+       __net_timestamp(skb);
+
+       /* Send copy to monitor */
+       hci_send_to_monitor(hdev, skb);
 
-               hci_send_to_sock(hdev, skb, NULL);
+       if (atomic_read(&hdev->promisc)) {
+               /* Send copy to the sockets */
+               hci_send_to_sock(hdev, skb);
        }
 
        /* Get rid of skb owner, prior to sending to the driver. */
@@ -2235,26 +2513,31 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type)
 
 }
 
-static inline void hci_sched_acl(struct hci_dev *hdev)
+static inline int __get_blocks(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       struct hci_chan *chan;
-       struct sk_buff *skb;
-       int quote;
-       unsigned int cnt;
-
-       BT_DBG("%s", hdev->name);
-
-       if (!hci_conn_num(hdev, ACL_LINK))
-               return;
+       /* Calculate count of blocks used by this packet */
+       return DIV_ROUND_UP(skb->len - HCI_ACL_HDR_SIZE, hdev->block_len);
+}
 
+static inline void __check_timeout(struct hci_dev *hdev, unsigned int cnt)
+{
        if (!test_bit(HCI_RAW, &hdev->flags)) {
                /* ACL tx timeout must be longer than maximum
                 * link supervision timeout (40.9 seconds) */
-               if (!hdev->acl_cnt && time_after(jiffies, hdev->acl_last_tx + HZ * 45))
+               if (!cnt && time_after(jiffies, hdev->acl_last_tx +
+                                       msecs_to_jiffies(HCI_ACL_TX_TIMEOUT)))
                        hci_link_tx_to(hdev, ACL_LINK);
        }
+}
+
+static inline void hci_sched_acl_pkt(struct hci_dev *hdev)
+{
+       unsigned int cnt = hdev->acl_cnt;
+       struct hci_chan *chan;
+       struct sk_buff *skb;
+       int quote;
 
-       cnt = hdev->acl_cnt;
+       __check_timeout(hdev, cnt);
 
        while (hdev->acl_cnt &&
                        (chan = hci_chan_sent(hdev, ACL_LINK, &quote))) {
@@ -2270,7 +2553,7 @@ static inline void hci_sched_acl(struct hci_dev *hdev)
                        skb = skb_dequeue(&chan->data_q);
 
                        hci_conn_enter_active_mode(chan->conn,
-                                               bt_cb(skb)->force_active);
+                                                  bt_cb(skb)->force_active);
 
                        hci_send_frame(skb);
                        hdev->acl_last_tx = jiffies;
@@ -2285,6 +2568,70 @@ static inline void hci_sched_acl(struct hci_dev *hdev)
                hci_prio_recalculate(hdev, ACL_LINK);
 }
 
+static inline void hci_sched_acl_blk(struct hci_dev *hdev)
+{
+       unsigned int cnt = hdev->block_cnt;
+       struct hci_chan *chan;
+       struct sk_buff *skb;
+       int quote;
+
+       __check_timeout(hdev, cnt);
+
+       while (hdev->block_cnt > 0 &&
+                       (chan = hci_chan_sent(hdev, ACL_LINK, &quote))) {
+               u32 priority = (skb_peek(&chan->data_q))->priority;
+               while (quote > 0 && (skb = skb_peek(&chan->data_q))) {
+                       int blocks;
+
+                       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);
+
+                       blocks = __get_blocks(hdev, skb);
+                       if (blocks > hdev->block_cnt)
+                               return;
+
+                       hci_conn_enter_active_mode(chan->conn,
+                                               bt_cb(skb)->force_active);
+
+                       hci_send_frame(skb);
+                       hdev->acl_last_tx = jiffies;
+
+                       hdev->block_cnt -= blocks;
+                       quote -= blocks;
+
+                       chan->sent += blocks;
+                       chan->conn->sent += blocks;
+               }
+       }
+
+       if (cnt != hdev->block_cnt)
+               hci_prio_recalculate(hdev, ACL_LINK);
+}
+
+static inline void hci_sched_acl(struct hci_dev *hdev)
+{
+       BT_DBG("%s", hdev->name);
+
+       if (!hci_conn_num(hdev, ACL_LINK))
+               return;
+
+       switch (hdev->flow_ctl_mode) {
+       case HCI_FLOW_CTL_MODE_PACKET_BASED:
+               hci_sched_acl_pkt(hdev);
+               break;
+
+       case HCI_FLOW_CTL_MODE_BLOCK_BASED:
+               hci_sched_acl_blk(hdev);
+               break;
+       }
+}
+
 /* Schedule SCO */
 static inline void hci_sched_sco(struct hci_dev *hdev)
 {
@@ -2482,9 +2829,12 @@ static void hci_rx_work(struct work_struct *work)
        BT_DBG("%s", hdev->name);
 
        while ((skb = skb_dequeue(&hdev->rx_q))) {
+               /* Send copy to monitor */
+               hci_send_to_monitor(hdev, skb);
+
                if (atomic_read(&hdev->promisc)) {
                        /* Send copy to the sockets */
-                       hci_send_to_sock(hdev, skb, NULL);
+                       hci_send_to_sock(hdev, skb);
                }
 
                if (test_bit(HCI_RAW, &hdev->flags)) {
@@ -2568,6 +2918,8 @@ int hci_do_inquiry(struct hci_dev *hdev, u8 length)
        if (test_bit(HCI_INQUIRY, &hdev->flags))
                return -EINPROGRESS;
 
+       inquiry_cache_flush(hdev);
+
        memset(&cp, 0, sizeof(cp));
        memcpy(&cp.lap, lap, sizeof(cp.lap));
        cp.length  = length;
@@ -2584,6 +2936,3 @@ int hci_cancel_inquiry(struct hci_dev *hdev)
 
        return hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
 }
-
-module_param(enable_hs, bool, 0644);
-MODULE_PARM_DESC(enable_hs, "Enable High Speed");
index 001307f810577111d0bbeea9265e0da37574cb5e..badb7851d11669a8da55be315bc77054c5eaf7a3 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/init.h>
 #include <linux/skbuff.h>
 #include <linux/interrupt.h>
-#include <linux/notifier.h>
 #include <net/sock.h>
 
 #include <asm/system.h>
@@ -45,8 +44,6 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
-static bool enable_le;
-
 /* Handle HCI Event packets */
 
 static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
@@ -65,7 +62,7 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
        clear_bit(HCI_INQUIRY, &hdev->flags);
 
        hci_dev_lock(hdev);
-       mgmt_discovering(hdev, 0);
+       hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
        hci_dev_unlock(hdev);
 
        hci_req_complete(hdev, HCI_OP_INQUIRY_CANCEL, status);
@@ -195,7 +192,10 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
 
        hci_req_complete(hdev, HCI_OP_RESET, status);
 
-       hdev->dev_flags = 0;
+       /* Reset all non-persistent flags */
+       hdev->dev_flags &= ~(BIT(HCI_LE_SCAN) | BIT(HCI_PENDING_CLASS));
+
+       hdev->discovery.state = DISCOVERY_STOPPED;
 }
 
 static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
@@ -211,13 +211,14 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
 
        hci_dev_lock(hdev);
 
-       if (test_bit(HCI_MGMT, &hdev->flags))
+       if (test_bit(HCI_MGMT, &hdev->dev_flags))
                mgmt_set_local_name_complete(hdev, sent, status);
-
-       if (status == 0)
+       else if (!status)
                memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH);
 
        hci_dev_unlock(hdev);
+
+       hci_req_complete(hdev, HCI_OP_WRITE_LOCAL_NAME, status);
 }
 
 static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)
@@ -229,7 +230,8 @@ static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)
        if (rp->status)
                return;
 
-       memcpy(hdev->dev_name, rp->name, HCI_MAX_NAME_LENGTH);
+       if (test_bit(HCI_SETUP, &hdev->dev_flags))
+               memcpy(hdev->dev_name, rp->name, HCI_MAX_NAME_LENGTH);
 }
 
 static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb)
@@ -252,6 +254,9 @@ static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb)
                        clear_bit(HCI_AUTH, &hdev->flags);
        }
 
+       if (test_bit(HCI_MGMT, &hdev->dev_flags))
+               mgmt_auth_enable_complete(hdev, status);
+
        hci_req_complete(hdev, HCI_OP_WRITE_AUTH_ENABLE, status);
 }
 
@@ -349,14 +354,19 @@ static void hci_cc_write_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
 
        BT_DBG("%s status 0x%x", hdev->name, status);
 
-       if (status)
-               return;
-
        sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_CLASS_OF_DEV);
        if (!sent)
                return;
 
-       memcpy(hdev->dev_class, sent, 3);
+       hci_dev_lock(hdev);
+
+       if (status == 0)
+               memcpy(hdev->dev_class, sent, 3);
+
+       if (test_bit(HCI_MGMT, &hdev->dev_flags))
+               mgmt_set_class_of_dev_complete(hdev, sent, status);
+
+       hci_dev_unlock(hdev);
 }
 
 static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
@@ -419,18 +429,6 @@ static void hci_cc_host_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
        hci_req_complete(hdev, HCI_OP_HOST_BUFFER_SIZE, status);
 }
 
-static void hci_cc_read_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
-{
-       struct hci_rp_read_ssp_mode *rp = (void *) skb->data;
-
-       BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
-       if (rp->status)
-               return;
-
-       hdev->ssp_mode = rp->mode;
-}
-
 static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
 {
        __u8 status = *((__u8 *) skb->data);
@@ -438,14 +436,18 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
 
        BT_DBG("%s status 0x%x", hdev->name, status);
 
-       if (status)
-               return;
-
        sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SSP_MODE);
        if (!sent)
                return;
 
-       hdev->ssp_mode = *((__u8 *) sent);
+       if (test_bit(HCI_MGMT, &hdev->dev_flags))
+               mgmt_ssp_enable_complete(hdev, *((u8 *) sent), status);
+       else if (!status) {
+               if (*((u8 *) sent))
+                       set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
+               else
+                       clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
+       }
 }
 
 static u8 hci_get_inquiry_mode(struct hci_dev *hdev)
@@ -540,20 +542,6 @@ static void hci_setup_event_mask(struct hci_dev *hdev)
        hci_send_cmd(hdev, HCI_OP_SET_EVENT_MASK, sizeof(events), events);
 }
 
-static void hci_set_le_support(struct hci_dev *hdev)
-{
-       struct hci_cp_write_le_host_supported cp;
-
-       memset(&cp, 0, sizeof(cp));
-
-       if (enable_le) {
-               cp.le = 1;
-               cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
-       }
-
-       hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(cp), &cp);
-}
-
 static void hci_setup(struct hci_dev *hdev)
 {
        if (hdev->dev_type != HCI_BREDR)
@@ -565,8 +553,18 @@ static void hci_setup(struct hci_dev *hdev)
                hci_send_cmd(hdev, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL);
 
        if (hdev->features[6] & LMP_SIMPLE_PAIR) {
-               u8 mode = 0x01;
-               hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(mode), &mode);
+               if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
+                       u8 mode = 0x01;
+                       hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE,
+                                    sizeof(mode), &mode);
+               } else {
+                       struct hci_cp_write_eir cp;
+
+                       memset(hdev->eir, 0, sizeof(hdev->eir));
+                       memset(&cp, 0, sizeof(cp));
+
+                       hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
+               }
        }
 
        if (hdev->features[3] & LMP_RSSI_INQ)
@@ -579,12 +577,15 @@ static void hci_setup(struct hci_dev *hdev)
                struct hci_cp_read_local_ext_features cp;
 
                cp.page = 0x01;
-               hci_send_cmd(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES,
-                                                       sizeof(cp), &cp);
+               hci_send_cmd(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, sizeof(cp),
+                            &cp);
        }
 
-       if (hdev->features[4] & LMP_LE)
-               hci_set_le_support(hdev);
+       if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags)) {
+               u8 enable = 1;
+               hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(enable),
+                            &enable);
+       }
 }
 
 static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
@@ -594,7 +595,7 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
        BT_DBG("%s status 0x%x", hdev->name, rp->status);
 
        if (rp->status)
-               return;
+               goto done;
 
        hdev->hci_ver = rp->hci_ver;
        hdev->hci_rev = __le16_to_cpu(rp->hci_rev);
@@ -608,6 +609,9 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
 
        if (test_bit(HCI_INIT, &hdev->flags))
                hci_setup(hdev);
+
+done:
+       hci_req_complete(hdev, HCI_OP_READ_LOCAL_VERSION, rp->status);
 }
 
 static void hci_setup_link_policy(struct hci_dev *hdev)
@@ -624,8 +628,8 @@ static void hci_setup_link_policy(struct hci_dev *hdev)
                link_policy |= HCI_LP_PARK;
 
        link_policy = cpu_to_le16(link_policy);
-       hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY,
-                                       sizeof(link_policy), &link_policy);
+       hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, sizeof(link_policy),
+                    &link_policy);
 }
 
 static void hci_cc_read_local_commands(struct hci_dev *hdev, struct sk_buff *skb)
@@ -701,6 +705,22 @@ static void hci_cc_read_local_features(struct hci_dev *hdev, struct sk_buff *skb
                                        hdev->features[6], hdev->features[7]);
 }
 
+static void hci_set_le_support(struct hci_dev *hdev)
+{
+       struct hci_cp_write_le_host_supported cp;
+
+       memset(&cp, 0, sizeof(cp));
+
+       if (enable_le && test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
+               cp.le = 1;
+               cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
+       }
+
+       if (cp.le != !!(hdev->host_features[0] & LMP_HOST_LE))
+               hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(cp),
+                            &cp);
+}
+
 static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
                                                        struct sk_buff *skb)
 {
@@ -709,7 +729,7 @@ static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
        BT_DBG("%s status 0x%x", hdev->name, rp->status);
 
        if (rp->status)
-               return;
+               goto done;
 
        switch (rp->page) {
        case 0:
@@ -720,6 +740,10 @@ static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
                break;
        }
 
+       if (test_bit(HCI_INIT, &hdev->flags) && hdev->features[4] & LMP_LE)
+               hci_set_le_support(hdev);
+
+done:
        hci_req_complete(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, rp->status);
 }
 
@@ -890,7 +914,7 @@ static void hci_cc_pin_code_reply(struct hci_dev *hdev, struct sk_buff *skb)
 
        hci_dev_lock(hdev);
 
-       if (test_bit(HCI_MGMT, &hdev->flags))
+       if (test_bit(HCI_MGMT, &hdev->dev_flags))
                mgmt_pin_code_reply_complete(hdev, &rp->bdaddr, rp->status);
 
        if (rp->status != 0)
@@ -916,7 +940,7 @@ static void hci_cc_pin_code_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
 
        hci_dev_lock(hdev);
 
-       if (test_bit(HCI_MGMT, &hdev->flags))
+       if (test_bit(HCI_MGMT, &hdev->dev_flags))
                mgmt_pin_code_neg_reply_complete(hdev, &rp->bdaddr,
                                                                rp->status);
 
@@ -951,9 +975,9 @@ static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb)
 
        hci_dev_lock(hdev);
 
-       if (test_bit(HCI_MGMT, &hdev->flags))
-               mgmt_user_confirm_reply_complete(hdev, &rp->bdaddr,
-                                                               rp->status);
+       if (test_bit(HCI_MGMT, &hdev->dev_flags))
+               mgmt_user_confirm_reply_complete(hdev, &rp->bdaddr, ACL_LINK, 0,
+                                                rp->status);
 
        hci_dev_unlock(hdev);
 }
@@ -967,9 +991,9 @@ static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev,
 
        hci_dev_lock(hdev);
 
-       if (test_bit(HCI_MGMT, &hdev->flags))
+       if (test_bit(HCI_MGMT, &hdev->dev_flags))
                mgmt_user_confirm_neg_reply_complete(hdev, &rp->bdaddr,
-                                                               rp->status);
+                                                    ACL_LINK, 0, rp->status);
 
        hci_dev_unlock(hdev);
 }
@@ -982,9 +1006,9 @@ static void hci_cc_user_passkey_reply(struct hci_dev *hdev, struct sk_buff *skb)
 
        hci_dev_lock(hdev);
 
-       if (test_bit(HCI_MGMT, &hdev->flags))
-               mgmt_user_passkey_reply_complete(hdev, &rp->bdaddr,
-                                                               rp->status);
+       if (test_bit(HCI_MGMT, &hdev->dev_flags))
+               mgmt_user_passkey_reply_complete(hdev, &rp->bdaddr, ACL_LINK,
+                                                0, rp->status);
 
        hci_dev_unlock(hdev);
 }
@@ -998,9 +1022,9 @@ static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev,
 
        hci_dev_lock(hdev);
 
-       if (test_bit(HCI_MGMT, &hdev->flags))
+       if (test_bit(HCI_MGMT, &hdev->dev_flags))
                mgmt_user_passkey_neg_reply_complete(hdev, &rp->bdaddr,
-                                                               rp->status);
+                                                    ACL_LINK, 0, rp->status);
 
        hci_dev_unlock(hdev);
 }
@@ -1023,6 +1047,15 @@ static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb)
        __u8 status = *((__u8 *) skb->data);
 
        BT_DBG("%s status 0x%x", hdev->name, status);
+
+       hci_req_complete(hdev, HCI_OP_LE_SET_SCAN_PARAM, status);
+
+       if (status) {
+               hci_dev_lock(hdev);
+               mgmt_start_discovery_failed(hdev, status);
+               hci_dev_unlock(hdev);
+               return;
+       }
 }
 
 static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
@@ -1033,28 +1066,47 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
 
        BT_DBG("%s status 0x%x", hdev->name, status);
 
-       if (status)
-               return;
-
        cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_SCAN_ENABLE);
        if (!cp)
                return;
 
        switch (cp->enable) {
        case LE_SCANNING_ENABLED:
+               hci_req_complete(hdev, HCI_OP_LE_SET_SCAN_ENABLE, status);
+
+               if (status) {
+                       hci_dev_lock(hdev);
+                       mgmt_start_discovery_failed(hdev, status);
+                       hci_dev_unlock(hdev);
+                       return;
+               }
+
                set_bit(HCI_LE_SCAN, &hdev->dev_flags);
 
                cancel_delayed_work_sync(&hdev->adv_work);
 
                hci_dev_lock(hdev);
                hci_adv_entries_clear(hdev);
+               hci_discovery_set_state(hdev, DISCOVERY_FINDING);
                hci_dev_unlock(hdev);
                break;
 
        case LE_SCANNING_DISABLED:
+               if (status)
+                       return;
+
                clear_bit(HCI_LE_SCAN, &hdev->dev_flags);
 
                schedule_delayed_work(&hdev->adv_work, ADV_CLEAR_TIMEOUT);
+
+               if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED) {
+                       mgmt_interleaved_discovery(hdev);
+               } else {
+                       hci_dev_lock(hdev);
+                       hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+                       hci_dev_unlock(hdev);
+               }
+
                break;
 
        default:
@@ -1090,16 +1142,27 @@ static void hci_cc_le_ltk_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
 static inline void hci_cc_write_le_host_supported(struct hci_dev *hdev,
                                                        struct sk_buff *skb)
 {
-       struct hci_cp_read_local_ext_features cp;
+       struct hci_cp_write_le_host_supported *sent;
        __u8 status = *((__u8 *) skb->data);
 
        BT_DBG("%s status 0x%x", hdev->name, status);
 
-       if (status)
+       sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED);
+       if (!sent)
                return;
 
-       cp.page = 0x01;
-       hci_send_cmd(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, sizeof(cp), &cp);
+       if (!status) {
+               if (sent->le)
+                       hdev->host_features[0] |= LMP_HOST_LE;
+               else
+                       hdev->host_features[0] &= ~LMP_HOST_LE;
+       }
+
+       if (test_bit(HCI_MGMT, &hdev->dev_flags) &&
+                                       !test_bit(HCI_INIT, &hdev->flags))
+               mgmt_le_enable_complete(hdev, sent->le, status);
+
+       hci_req_complete(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, status);
 }
 
 static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
@@ -1110,7 +1173,7 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 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))
+               if (test_bit(HCI_MGMT, &hdev->dev_flags))
                        mgmt_start_discovery_failed(hdev, status);
                hci_dev_unlock(hdev);
                return;
@@ -1119,7 +1182,7 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
        set_bit(HCI_INQUIRY, &hdev->flags);
 
        hci_dev_lock(hdev);
-       mgmt_discovering(hdev, 1);
+       hci_discovery_set_state(hdev, DISCOVERY_FINDING);
        hci_dev_unlock(hdev);
 }
 
@@ -1153,7 +1216,7 @@ static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
                if (!conn) {
                        conn = hci_conn_add(hdev, ACL_LINK, &cp->bdaddr);
                        if (conn) {
-                               conn->out = 1;
+                               conn->out = true;
                                conn->link_mode |= HCI_LM_MASTER;
                        } else
                                BT_ERR("No memory for new connection");
@@ -1263,7 +1326,7 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev,
 
        /* Only request authentication for SSP connections or non-SSP
         * devices with sec_level HIGH or if MITM protection is requested */
-       if (!(hdev->ssp_mode > 0 && conn->ssp_mode > 0) &&
+       if (!hci_conn_ssp_enabled(conn) &&
                                conn->pending_sec_level != BT_SECURITY_HIGH &&
                                !(conn->auth_type & 0x01))
                return 0;
@@ -1271,6 +1334,73 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev,
        return 1;
 }
 
+static inline int hci_resolve_name(struct hci_dev *hdev,
+                                  struct inquiry_entry *e)
+{
+       struct hci_cp_remote_name_req cp;
+
+       memset(&cp, 0, sizeof(cp));
+
+       bacpy(&cp.bdaddr, &e->data.bdaddr);
+       cp.pscan_rep_mode = e->data.pscan_rep_mode;
+       cp.pscan_mode = e->data.pscan_mode;
+       cp.clock_offset = e->data.clock_offset;
+
+       return hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp);
+}
+
+static bool hci_resolve_next_name(struct hci_dev *hdev)
+{
+       struct discovery_state *discov = &hdev->discovery;
+       struct inquiry_entry *e;
+
+       if (list_empty(&discov->resolve))
+               return false;
+
+       e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_NEEDED);
+       if (hci_resolve_name(hdev, e) == 0) {
+               e->name_state = NAME_PENDING;
+               return true;
+       }
+
+       return false;
+}
+
+static void hci_check_pending_name(struct hci_dev *hdev, struct hci_conn *conn,
+                                  bdaddr_t *bdaddr, u8 *name, u8 name_len)
+{
+       struct discovery_state *discov = &hdev->discovery;
+       struct inquiry_entry *e;
+
+       if (conn && !test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
+               mgmt_device_connected(hdev, bdaddr, ACL_LINK, 0x00, 0, name,
+                                     name_len, conn->dev_class);
+
+       if (discov->state == DISCOVERY_STOPPED)
+               return;
+
+       if (discov->state == DISCOVERY_STOPPING)
+               goto discov_complete;
+
+       if (discov->state != DISCOVERY_RESOLVING)
+               return;
+
+       e = hci_inquiry_cache_lookup_resolve(hdev, bdaddr, NAME_PENDING);
+       if (e) {
+               e->name_state = NAME_KNOWN;
+               list_del(&e->list);
+               if (name)
+                       mgmt_remote_name(hdev, bdaddr, ACL_LINK, 0x00,
+                                        e->data.rssi, name, name_len);
+       }
+
+       if (hci_resolve_next_name(hdev))
+               return;
+
+discov_complete:
+       hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+}
+
 static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status)
 {
        struct hci_cp_remote_name_req *cp;
@@ -1290,13 +1420,17 @@ static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status)
        hci_dev_lock(hdev);
 
        conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
+
+       if (test_bit(HCI_MGMT, &hdev->dev_flags))
+               hci_check_pending_name(hdev, conn, &cp->bdaddr, NULL, 0);
+
        if (!conn)
                goto unlock;
 
        if (!hci_outgoing_auth_needed(hdev, conn))
                goto unlock;
 
-       if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
+       if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) {
                struct hci_cp_auth_requested cp;
                cp.handle = __cpu_to_le16(conn->handle);
                hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
@@ -1413,9 +1547,9 @@ static void hci_cs_sniff_mode(struct hci_dev *hdev, __u8 status)
 
        conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
        if (conn) {
-               clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend);
+               clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags);
 
-               if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->pend))
+               if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->flags))
                        hci_sco_setup(conn, status);
        }
 
@@ -1440,15 +1574,37 @@ static void hci_cs_exit_sniff_mode(struct hci_dev *hdev, __u8 status)
 
        conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
        if (conn) {
-               clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend);
+               clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags);
 
-               if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->pend))
+               if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->flags))
                        hci_sco_setup(conn, status);
        }
 
        hci_dev_unlock(hdev);
 }
 
+static void hci_cs_disconnect(struct hci_dev *hdev, u8 status)
+{
+       struct hci_cp_disconnect *cp;
+       struct hci_conn *conn;
+
+       if (!status)
+               return;
+
+       cp = hci_sent_cmd_data(hdev, HCI_OP_DISCONNECT);
+       if (!cp)
+               return;
+
+       hci_dev_lock(hdev);
+
+       conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
+       if (conn)
+               mgmt_disconnect_failed(hdev, &conn->dst, conn->type,
+                                      conn->dst_type, status);
+
+       hci_dev_unlock(hdev);
+}
+
 static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status)
 {
        struct hci_cp_le_create_conn *cp;
@@ -1478,7 +1634,7 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status)
                        conn = hci_conn_add(hdev, LE_LINK, &cp->peer_addr);
                        if (conn) {
                                conn->dst_type = cp->peer_addr_type;
-                               conn->out = 1;
+                               conn->out = true;
                        } else {
                                BT_ERR("No memory for new connection");
                        }
@@ -1496,6 +1652,8 @@ static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status)
 static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        __u8 status = *((__u8 *) skb->data);
+       struct discovery_state *discov = &hdev->discovery;
+       struct inquiry_entry *e;
 
        BT_DBG("%s status %d", hdev->name, status);
 
@@ -1506,8 +1664,28 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff
        if (!test_and_clear_bit(HCI_INQUIRY, &hdev->flags))
                return;
 
+       if (!test_bit(HCI_MGMT, &hdev->dev_flags))
+               return;
+
        hci_dev_lock(hdev);
-       mgmt_discovering(hdev, 0);
+
+       if (discov->state != DISCOVERY_FINDING)
+               goto unlock;
+
+       if (list_empty(&discov->resolve)) {
+               hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+               goto unlock;
+       }
+
+       e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_NEEDED);
+       if (e && hci_resolve_name(hdev, e) == 0) {
+               e->name_state = NAME_PENDING;
+               hci_discovery_set_state(hdev, DISCOVERY_RESOLVING);
+       } else {
+               hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+       }
+
+unlock:
        hci_dev_unlock(hdev);
 }
 
@@ -1525,6 +1703,8 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
        hci_dev_lock(hdev);
 
        for (; num_rsp; num_rsp--, info++) {
+               bool name_known, ssp;
+
                bacpy(&data.bdaddr, &info->bdaddr);
                data.pscan_rep_mode     = info->pscan_rep_mode;
                data.pscan_period_mode  = info->pscan_period_mode;
@@ -1533,9 +1713,11 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
                data.clock_offset       = info->clock_offset;
                data.rssi               = 0x00;
                data.ssp_mode           = 0x00;
-               hci_inquiry_cache_update(hdev, &data);
+
+               name_known = hci_inquiry_cache_update(hdev, &data, false, &ssp);
                mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
-                                               info->dev_class, 0, NULL);
+                                 info->dev_class, 0, !name_known, ssp, NULL,
+                                 0);
        }
 
        hci_dev_unlock(hdev);
@@ -1569,8 +1751,6 @@ 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, &ev->bdaddr, conn->type,
-                                                       conn->dst_type);
                } else
                        conn->state = BT_CONNECTED;
 
@@ -1588,7 +1768,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                        struct hci_cp_read_remote_features cp;
                        cp.handle = ev->handle;
                        hci_send_cmd(hdev, HCI_OP_READ_REMOTE_FEATURES,
-                                                       sizeof(cp), &cp);
+                                    sizeof(cp), &cp);
                }
 
                /* Set packet type for incoming connection */
@@ -1596,14 +1776,14 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                        struct hci_cp_change_conn_ptype cp;
                        cp.handle = ev->handle;
                        cp.pkt_type = cpu_to_le16(conn->pkt_type);
-                       hci_send_cmd(hdev, HCI_OP_CHANGE_CONN_PTYPE,
-                                                       sizeof(cp), &cp);
+                       hci_send_cmd(hdev, HCI_OP_CHANGE_CONN_PTYPE, sizeof(cp),
+                                    &cp);
                }
        } else {
                conn->state = BT_CLOSED;
                if (conn->type == ACL_LINK)
                        mgmt_connect_failed(hdev, &ev->bdaddr, conn->type,
-                                               conn->dst_type, ev->status);
+                                           conn->dst_type, ev->status);
        }
 
        if (conn->type == ACL_LINK)
@@ -1668,8 +1848,8 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
                        else
                                cp.role = 0x01; /* Remain slave */
 
-                       hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ,
-                                                       sizeof(cp), &cp);
+                       hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp),
+                                    &cp);
                } else {
                        struct hci_cp_accept_sync_conn_req cp;
 
@@ -1683,7 +1863,7 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
                        cp.retrans_effort = 0xff;
 
                        hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ,
-                                                       sizeof(cp), &cp);
+                                    sizeof(cp), &cp);
                }
        } else {
                /* Connection rejected */
@@ -1711,12 +1891,14 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
        if (ev->status == 0)
                conn->state = BT_CLOSED;
 
-       if (conn->type == ACL_LINK || conn->type == LE_LINK) {
+       if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags) &&
+                       (conn->type == ACL_LINK || conn->type == LE_LINK)) {
                if (ev->status != 0)
-                       mgmt_disconnect_failed(hdev, &conn->dst, ev->status);
+                       mgmt_disconnect_failed(hdev, &conn->dst, conn->type,
+                                               conn->dst_type, ev->status);
                else
-                       mgmt_disconnected(hdev, &conn->dst, conn->type,
-                                                       conn->dst_type);
+                       mgmt_device_disconnected(hdev, &conn->dst, conn->type,
+                                                conn->dst_type);
        }
 
        if (ev->status == 0) {
@@ -1742,22 +1924,23 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                goto unlock;
 
        if (!ev->status) {
-               if (!(conn->ssp_mode > 0 && hdev->ssp_mode > 0) &&
-                               test_bit(HCI_CONN_REAUTH_PEND,  &conn->pend)) {
+               if (!hci_conn_ssp_enabled(conn) &&
+                               test_bit(HCI_CONN_REAUTH_PEND, &conn->flags)) {
                        BT_INFO("re-auth of legacy device is not possible.");
                } else {
                        conn->link_mode |= HCI_LM_AUTH;
                        conn->sec_level = conn->pending_sec_level;
                }
        } else {
-               mgmt_auth_failed(hdev, &conn->dst, ev->status);
+               mgmt_auth_failed(hdev, &conn->dst, conn->type, conn->dst_type,
+                                ev->status);
        }
 
-       clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
-       clear_bit(HCI_CONN_REAUTH_PEND, &conn->pend);
+       clear_bit(HCI_CONN_AUTH_PEND, &conn->flags);
+       clear_bit(HCI_CONN_REAUTH_PEND, &conn->flags);
 
        if (conn->state == BT_CONFIG) {
-               if (!ev->status && hdev->ssp_mode > 0 && conn->ssp_mode > 0) {
+               if (!ev->status && hci_conn_ssp_enabled(conn)) {
                        struct hci_cp_set_conn_encrypt cp;
                        cp.handle  = ev->handle;
                        cp.encrypt = 0x01;
@@ -1776,7 +1959,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                hci_conn_put(conn);
        }
 
-       if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
+       if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) {
                if (!ev->status) {
                        struct hci_cp_set_conn_encrypt cp;
                        cp.handle  = ev->handle;
@@ -1784,7 +1967,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                        hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp),
                                                                        &cp);
                } else {
-                       clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
+                       clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
                        hci_encrypt_cfm(conn, ev->status, 0x00);
                }
        }
@@ -1804,17 +1987,25 @@ 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, &ev->bdaddr, ev->name);
-
        conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
+
+       if (!test_bit(HCI_MGMT, &hdev->dev_flags))
+               goto check_auth;
+
+       if (ev->status == 0)
+               hci_check_pending_name(hdev, conn, &ev->bdaddr, ev->name,
+                                      strnlen(ev->name, HCI_MAX_NAME_LENGTH));
+       else
+               hci_check_pending_name(hdev, conn, &ev->bdaddr, NULL, 0);
+
+check_auth:
        if (!conn)
                goto unlock;
 
        if (!hci_outgoing_auth_needed(hdev, conn))
                goto unlock;
 
-       if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
+       if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) {
                struct hci_cp_auth_requested cp;
                cp.handle = __cpu_to_le16(conn->handle);
                hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
@@ -1845,7 +2036,7 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *
                                conn->link_mode &= ~HCI_LM_ENCRYPT;
                }
 
-               clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
+               clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
 
                if (conn->state == BT_CONFIG) {
                        if (!ev->status)
@@ -1874,7 +2065,7 @@ static inline void hci_change_link_key_complete_evt(struct hci_dev *hdev, struct
                if (!ev->status)
                        conn->link_mode |= HCI_LM_SECURE;
 
-               clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
+               clear_bit(HCI_CONN_AUTH_PEND, &conn->flags);
 
                hci_key_change_cfm(conn, ev->status);
        }
@@ -1916,7 +2107,10 @@ static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff
                bacpy(&cp.bdaddr, &conn->dst);
                cp.pscan_rep_mode = 0x02;
                hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp);
-       }
+       } else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
+               mgmt_device_connected(hdev, &conn->dst, conn->type,
+                                     conn->dst_type, 0, NULL, 0,
+                                     conn->dev_class);
 
        if (!hci_outgoing_auth_needed(hdev, conn)) {
                conn->state = BT_CONNECTED;
@@ -2024,10 +2218,6 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
                hci_cc_host_buffer_size(hdev, skb);
                break;
 
-       case HCI_OP_READ_SSP_MODE:
-               hci_cc_read_ssp_mode(hdev, skb);
-               break;
-
        case HCI_OP_WRITE_SSP_MODE:
                hci_cc_write_ssp_mode(hdev, skb);
                break;
@@ -2213,8 +2403,7 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
                break;
 
        case HCI_OP_DISCONNECT:
-               if (ev->status != 0)
-                       mgmt_disconnect_failed(hdev, NULL, ev->status);
+               hci_cs_disconnect(hdev, ev->status);
                break;
 
        case HCI_OP_LE_CREATE_CONN:
@@ -2258,7 +2447,7 @@ static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb
                                conn->link_mode |= HCI_LM_MASTER;
                }
 
-               clear_bit(HCI_CONN_RSWITCH_PEND, &conn->pend);
+               clear_bit(HCI_CONN_RSWITCH_PEND, &conn->flags);
 
                hci_role_switch_cfm(conn, ev->status, ev->role);
        }
@@ -2332,6 +2521,56 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s
        queue_work(hdev->workqueue, &hdev->tx_work);
 }
 
+static inline void hci_num_comp_blocks_evt(struct hci_dev *hdev,
+                                          struct sk_buff *skb)
+{
+       struct hci_ev_num_comp_blocks *ev = (void *) skb->data;
+       int i;
+
+       if (hdev->flow_ctl_mode != HCI_FLOW_CTL_MODE_BLOCK_BASED) {
+               BT_ERR("Wrong event for mode %d", hdev->flow_ctl_mode);
+               return;
+       }
+
+       if (skb->len < sizeof(*ev) || skb->len < sizeof(*ev) +
+                       ev->num_hndl * sizeof(struct hci_comp_blocks_info)) {
+               BT_DBG("%s bad parameters", hdev->name);
+               return;
+       }
+
+       BT_DBG("%s num_blocks %d num_hndl %d", hdev->name, ev->num_blocks,
+                                                               ev->num_hndl);
+
+       for (i = 0; i < ev->num_hndl; i++) {
+               struct hci_comp_blocks_info *info = &ev->handles[i];
+               struct hci_conn *conn;
+               __u16  handle, block_count;
+
+               handle = __le16_to_cpu(info->handle);
+               block_count = __le16_to_cpu(info->blocks);
+
+               conn = hci_conn_hash_lookup_handle(hdev, handle);
+               if (!conn)
+                       continue;
+
+               conn->sent -= block_count;
+
+               switch (conn->type) {
+               case ACL_LINK:
+                       hdev->block_cnt += block_count;
+                       if (hdev->block_cnt > hdev->num_blocks)
+                               hdev->block_cnt = hdev->num_blocks;
+                       break;
+
+               default:
+                       BT_ERR("Unknown type %d conn %p", conn->type, conn);
+                       break;
+               }
+       }
+
+       queue_work(hdev->workqueue, &hdev->tx_work);
+}
+
 static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_mode_change *ev = (void *) skb->data;
@@ -2346,14 +2585,14 @@ static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb
                conn->mode = ev->mode;
                conn->interval = __le16_to_cpu(ev->interval);
 
-               if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
+               if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) {
                        if (conn->mode == HCI_CM_ACTIVE)
-                               conn->power_save = 1;
+                               set_bit(HCI_CONN_POWER_SAVE, &conn->flags);
                        else
-                               conn->power_save = 0;
+                               clear_bit(HCI_CONN_POWER_SAVE, &conn->flags);
                }
 
-               if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->pend))
+               if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->flags))
                        hci_sco_setup(conn, ev->status);
        }
 
@@ -2379,10 +2618,10 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff
                hci_conn_put(conn);
        }
 
-       if (!test_bit(HCI_PAIRABLE, &hdev->flags))
+       if (!test_bit(HCI_PAIRABLE, &hdev->dev_flags))
                hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
                                        sizeof(ev->bdaddr), &ev->bdaddr);
-       else if (test_bit(HCI_MGMT, &hdev->flags)) {
+       else if (test_bit(HCI_MGMT, &hdev->dev_flags)) {
                u8 secure;
 
                if (conn->pending_sec_level == BT_SECURITY_HIGH)
@@ -2406,7 +2645,7 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff
 
        BT_DBG("%s", hdev->name);
 
-       if (!test_bit(HCI_LINK_KEYS, &hdev->flags))
+       if (!test_bit(HCI_LINK_KEYS, &hdev->dev_flags))
                return;
 
        hci_dev_lock(hdev);
@@ -2421,7 +2660,7 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff
        BT_DBG("%s found key type %u for %s", hdev->name, key->type,
                                                        batostr(&ev->bdaddr));
 
-       if (!test_bit(HCI_DEBUG_KEYS, &hdev->flags) &&
+       if (!test_bit(HCI_DEBUG_KEYS, &hdev->dev_flags) &&
                                key->type == HCI_LK_DEBUG_COMBINATION) {
                BT_DBG("%s ignoring debug key", hdev->name);
                goto not_found;
@@ -2483,7 +2722,7 @@ static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff
                hci_conn_put(conn);
        }
 
-       if (test_bit(HCI_LINK_KEYS, &hdev->flags))
+       if (test_bit(HCI_LINK_KEYS, &hdev->dev_flags))
                hci_add_link_key(hdev, conn, 1, &ev->bdaddr, ev->link_key,
                                                        ev->key_type, pin_len);
 
@@ -2551,6 +2790,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
 {
        struct inquiry_data data;
        int num_rsp = *((__u8 *) skb->data);
+       bool name_known, ssp;
 
        BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
 
@@ -2572,10 +2812,12 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
                        data.clock_offset       = info->clock_offset;
                        data.rssi               = info->rssi;
                        data.ssp_mode           = 0x00;
-                       hci_inquiry_cache_update(hdev, &data);
+
+                       name_known = hci_inquiry_cache_update(hdev, &data,
+                                                             false, &ssp);
                        mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
-                                               info->dev_class, info->rssi,
-                                               NULL);
+                                         info->dev_class, info->rssi,
+                                         !name_known, ssp, NULL, 0);
                }
        } else {
                struct inquiry_info_with_rssi *info = (void *) (skb->data + 1);
@@ -2589,10 +2831,11 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
                        data.clock_offset       = info->clock_offset;
                        data.rssi               = info->rssi;
                        data.ssp_mode           = 0x00;
-                       hci_inquiry_cache_update(hdev, &data);
+                       name_known = hci_inquiry_cache_update(hdev, &data,
+                                                             false, &ssp);
                        mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
-                                               info->dev_class, info->rssi,
-                                               NULL);
+                                         info->dev_class, info->rssi,
+                                         !name_known, ssp, NULL, 0);
                }
        }
 
@@ -2617,9 +2860,10 @@ static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_b
 
                ie = hci_inquiry_cache_lookup(hdev, &conn->dst);
                if (ie)
-                       ie->data.ssp_mode = (ev->features[0] & 0x01);
+                       ie->data.ssp_mode = (ev->features[0] & LMP_HOST_SSP);
 
-               conn->ssp_mode = (ev->features[0] & 0x01);
+               if (ev->features[0] & LMP_HOST_SSP)
+                       set_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
        }
 
        if (conn->state != BT_CONFIG)
@@ -2631,7 +2875,10 @@ static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_b
                bacpy(&cp.bdaddr, &conn->dst);
                cp.pscan_rep_mode = 0x02;
                hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp);
-       }
+       } else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
+               mgmt_device_connected(hdev, &conn->dst, conn->type,
+                                     conn->dst_type, 0, NULL, 0,
+                                     conn->dev_class);
 
        if (!hci_outgoing_auth_needed(hdev, conn)) {
                conn->state = BT_CONNECTED;
@@ -2724,6 +2971,8 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
        hci_dev_lock(hdev);
 
        for (; num_rsp; num_rsp--, info++) {
+               bool name_known, ssp;
+
                bacpy(&data.bdaddr, &info->bdaddr);
                data.pscan_rep_mode     = info->pscan_rep_mode;
                data.pscan_period_mode  = info->pscan_period_mode;
@@ -2732,9 +2981,19 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
                data.clock_offset       = info->clock_offset;
                data.rssi               = info->rssi;
                data.ssp_mode           = 0x01;
-               hci_inquiry_cache_update(hdev, &data);
+
+               if (test_bit(HCI_MGMT, &hdev->dev_flags))
+                       name_known = eir_has_data_type(info->data,
+                                                      sizeof(info->data),
+                                                      EIR_NAME_COMPLETE);
+               else
+                       name_known = true;
+
+               name_known = hci_inquiry_cache_update(hdev, &data, name_known,
+                                                     &ssp);
                mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
-                               info->dev_class, info->rssi, info->data);
+                                 info->dev_class, info->rssi, !name_known,
+                                 ssp, info->data, sizeof(info->data));
        }
 
        hci_dev_unlock(hdev);
@@ -2774,19 +3033,22 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff
 
        hci_conn_hold(conn);
 
-       if (!test_bit(HCI_MGMT, &hdev->flags))
+       if (!test_bit(HCI_MGMT, &hdev->dev_flags))
                goto unlock;
 
-       if (test_bit(HCI_PAIRABLE, &hdev->flags) ||
+       if (test_bit(HCI_PAIRABLE, &hdev->dev_flags) ||
                        (conn->remote_auth & ~0x01) == HCI_AT_NO_BONDING) {
                struct hci_cp_io_capability_reply cp;
 
                bacpy(&cp.bdaddr, &ev->bdaddr);
-               cp.capability = conn->io_capability;
+               /* Change the IO capability from KeyboardDisplay
+                * to DisplayYesNo as it is not supported by BT spec. */
+               cp.capability = (conn->io_capability == 0x04) ?
+                                               0x01 : conn->io_capability;
                conn->auth_type = hci_get_auth_req(conn);
                cp.authentication = conn->auth_type;
 
-               if ((conn->out == 0x01 || conn->remote_oob == 0x01) &&
+               if ((conn->out || test_bit(HCI_CONN_REMOTE_OOB, &conn->flags)) &&
                                hci_find_remote_oob_data(hdev, &conn->dst))
                        cp.oob_data = 0x01;
                else
@@ -2822,8 +3084,9 @@ static inline void hci_io_capa_reply_evt(struct hci_dev *hdev, struct sk_buff *s
                goto unlock;
 
        conn->remote_cap = ev->capability;
-       conn->remote_oob = ev->oob_data;
        conn->remote_auth = ev->authentication;
+       if (ev->oob_data)
+               set_bit(HCI_CONN_REMOTE_OOB, &conn->flags);
 
 unlock:
        hci_dev_unlock(hdev);
@@ -2840,7 +3103,7 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev,
 
        hci_dev_lock(hdev);
 
-       if (!test_bit(HCI_MGMT, &hdev->flags))
+       if (!test_bit(HCI_MGMT, &hdev->dev_flags))
                goto unlock;
 
        conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
@@ -2869,7 +3132,7 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev,
                /* If we're not the initiators request authorization to
                 * proceed from user space (mgmt_user_confirm with
                 * confirm_hint set to 1). */
-               if (!test_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
+               if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags)) {
                        BT_DBG("Confirming auto-accept as acceptor");
                        confirm_hint = 1;
                        goto confirm;
@@ -2890,8 +3153,8 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev,
        }
 
 confirm:
-       mgmt_user_confirm_request(hdev, &ev->bdaddr, ev->passkey,
-                                                               confirm_hint);
+       mgmt_user_confirm_request(hdev, &ev->bdaddr, ACL_LINK, 0, ev->passkey,
+                                 confirm_hint);
 
 unlock:
        hci_dev_unlock(hdev);
@@ -2906,8 +3169,8 @@ static inline void hci_user_passkey_request_evt(struct hci_dev *hdev,
 
        hci_dev_lock(hdev);
 
-       if (test_bit(HCI_MGMT, &hdev->flags))
-               mgmt_user_passkey_request(hdev, &ev->bdaddr);
+       if (test_bit(HCI_MGMT, &hdev->dev_flags))
+               mgmt_user_passkey_request(hdev, &ev->bdaddr, ACL_LINK, 0);
 
        hci_dev_unlock(hdev);
 }
@@ -2930,8 +3193,9 @@ static inline void hci_simple_pair_complete_evt(struct hci_dev *hdev, struct sk_
         * initiated the authentication. A traditional auth_complete
         * 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, &conn->dst, ev->status);
+       if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags) && ev->status != 0)
+               mgmt_auth_failed(hdev, &conn->dst, conn->type, conn->dst_type,
+                                ev->status);
 
        hci_conn_put(conn);
 
@@ -2950,13 +3214,13 @@ static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_
 
        ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr);
        if (ie)
-               ie->data.ssp_mode = (ev->features[0] & 0x01);
+               ie->data.ssp_mode = (ev->features[0] & LMP_HOST_SSP);
 
        hci_dev_unlock(hdev);
 }
 
 static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
-                                                       struct sk_buff *skb)
+                                                  struct sk_buff *skb)
 {
        struct hci_ev_remote_oob_data_request *ev = (void *) skb->data;
        struct oob_data *data;
@@ -2965,7 +3229,7 @@ static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
 
        hci_dev_lock(hdev);
 
-       if (!test_bit(HCI_MGMT, &hdev->flags))
+       if (!test_bit(HCI_MGMT, &hdev->dev_flags))
                goto unlock;
 
        data = hci_find_remote_oob_data(hdev, &ev->bdaddr);
@@ -3020,7 +3284,9 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff
                goto unlock;
        }
 
-       mgmt_connected(hdev, &ev->bdaddr, conn->type, conn->dst_type);
+       if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
+               mgmt_device_connected(hdev, &ev->bdaddr, conn->type,
+                                     conn->dst_type, 0, NULL, 0, NULL);
 
        conn->sec_level = BT_SECURITY_LOW;
        conn->handle = __le16_to_cpu(ev->handle);
@@ -3040,6 +3306,7 @@ static inline void hci_le_adv_report_evt(struct hci_dev *hdev,
 {
        u8 num_reports = skb->data[0];
        void *ptr = &skb->data[1];
+       s8 rssi;
 
        hci_dev_lock(hdev);
 
@@ -3048,6 +3315,10 @@ static inline void hci_le_adv_report_evt(struct hci_dev *hdev,
 
                hci_add_adv_entry(hdev, ev);
 
+               rssi = ev->data[ev->length];
+               mgmt_device_found(hdev, &ev->bdaddr, LE_LINK, ev->bdaddr_type,
+                                 NULL, rssi, 0, 1, ev->data, ev->length);
+
                ptr += sizeof(*ev) + ev->length + 1;
        }
 
@@ -3061,7 +3332,7 @@ static inline void hci_le_ltk_request_evt(struct hci_dev *hdev,
        struct hci_cp_le_ltk_reply cp;
        struct hci_cp_le_ltk_neg_reply neg;
        struct hci_conn *conn;
-       struct link_key *ltk;
+       struct smp_ltk *ltk;
 
        BT_DBG("%s handle %d", hdev->name, cpu_to_le16(ev->handle));
 
@@ -3077,10 +3348,17 @@ static inline void hci_le_ltk_request_evt(struct hci_dev *hdev,
 
        memcpy(cp.ltk, ltk->val, sizeof(ltk->val));
        cp.handle = cpu_to_le16(conn->handle);
-       conn->pin_length = ltk->pin_len;
+
+       if (ltk->authenticated)
+               conn->sec_level = BT_SECURITY_HIGH;
 
        hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp);
 
+       if (ltk->type & HCI_SMP_STK) {
+               list_del(&ltk->list);
+               kfree(ltk);
+       }
+
        hci_dev_unlock(hdev);
 
        return;
@@ -3271,6 +3549,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
                hci_remote_oob_data_request_evt(hdev, skb);
                break;
 
+       case HCI_EV_NUM_COMP_BLOCKS:
+               hci_num_comp_blocks_evt(hdev, skb);
+               break;
+
        default:
                BT_DBG("%s event 0x%x", hdev->name, event);
                break;
@@ -3279,34 +3561,3 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
        kfree_skb(skb);
        hdev->stat.evt_rx++;
 }
-
-/* Generate internal stack event */
-void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data)
-{
-       struct hci_event_hdr *hdr;
-       struct hci_ev_stack_internal *ev;
-       struct sk_buff *skb;
-
-       skb = bt_skb_alloc(HCI_EVENT_HDR_SIZE + sizeof(*ev) + dlen, GFP_ATOMIC);
-       if (!skb)
-               return;
-
-       hdr = (void *) skb_put(skb, HCI_EVENT_HDR_SIZE);
-       hdr->evt  = HCI_EV_STACK_INTERNAL;
-       hdr->plen = sizeof(*ev) + dlen;
-
-       ev  = (void *) skb_put(skb, sizeof(*ev) + dlen);
-       ev->type = type;
-       memcpy(ev->data, data, dlen);
-
-       bt_cb(skb)->incoming = 1;
-       __net_timestamp(skb);
-
-       bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
-       skb->dev = (void *) hdev;
-       hci_send_to_sock(hdev, skb, NULL);
-       kfree_skb(skb);
-}
-
-module_param(enable_le, bool, 0644);
-MODULE_PARM_DESC(enable_le, "Enable LE support");
index 0dcc9626677973d23708b53c7716a126adea107f..63afd234283e1af474dedffc0843caad1ad8d627 100644 (file)
@@ -48,8 +48,9 @@
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/hci_mon.h>
 
-static bool enable_mgmt;
+static atomic_t monitor_promisc = ATOMIC_INIT(0);
 
 /* ----- HCI socket interface ----- */
 
@@ -85,22 +86,20 @@ static struct bt_sock_list hci_sk_list = {
 };
 
 /* Send frame to RAW socket */
-void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb,
-                                                       struct sock *skip_sk)
+void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct sock *sk;
        struct hlist_node *node;
+       struct sk_buff *skb_copy = NULL;
 
        BT_DBG("hdev %p len %d", hdev, skb->len);
 
        read_lock(&hci_sk_list.lock);
+
        sk_for_each(sk, node, &hci_sk_list.head) {
                struct hci_filter *flt;
                struct sk_buff *nskb;
 
-               if (sk == skip_sk)
-                       continue;
-
                if (sk->sk_state != BT_BOUND || hci_pi(sk)->hdev != hdev)
                        continue;
 
@@ -108,12 +107,9 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb,
                if (skb->sk == sk)
                        continue;
 
-               if (bt_cb(skb)->channel != hci_pi(sk)->channel)
+               if (hci_pi(sk)->channel != HCI_CHANNEL_RAW)
                        continue;
 
-               if (bt_cb(skb)->channel == HCI_CHANNEL_CONTROL)
-                       goto clone;
-
                /* Apply filter */
                flt = &hci_pi(sk)->filter;
 
@@ -137,21 +133,303 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb,
                                continue;
                }
 
-clone:
+               if (!skb_copy) {
+                       /* Create a private copy with headroom */
+                       skb_copy = __pskb_copy(skb, 1, GFP_ATOMIC);
+                       if (!skb_copy)
+                               continue;
+
+                       /* Put type byte before the data */
+                       memcpy(skb_push(skb_copy, 1), &bt_cb(skb)->pkt_type, 1);
+               }
+
+               nskb = skb_clone(skb_copy, GFP_ATOMIC);
+               if (!nskb)
+                       continue;
+
+               if (sock_queue_rcv_skb(sk, nskb))
+                       kfree_skb(nskb);
+       }
+
+       read_unlock(&hci_sk_list.lock);
+
+       kfree_skb(skb_copy);
+}
+
+/* Send frame to control socket */
+void hci_send_to_control(struct sk_buff *skb, struct sock *skip_sk)
+{
+       struct sock *sk;
+       struct hlist_node *node;
+
+       BT_DBG("len %d", skb->len);
+
+       read_lock(&hci_sk_list.lock);
+
+       sk_for_each(sk, node, &hci_sk_list.head) {
+               struct sk_buff *nskb;
+
+               /* Skip the original socket */
+               if (sk == skip_sk)
+                       continue;
+
+               if (sk->sk_state != BT_BOUND)
+                       continue;
+
+               if (hci_pi(sk)->channel != HCI_CHANNEL_CONTROL)
+                       continue;
+
                nskb = skb_clone(skb, GFP_ATOMIC);
                if (!nskb)
                        continue;
 
-               /* Put type byte before the data */
-               if (bt_cb(skb)->channel == HCI_CHANNEL_RAW)
-                       memcpy(skb_push(nskb, 1), &bt_cb(nskb)->pkt_type, 1);
+               if (sock_queue_rcv_skb(sk, nskb))
+                       kfree_skb(nskb);
+       }
+
+       read_unlock(&hci_sk_list.lock);
+}
+
+/* Send frame to monitor socket */
+void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct sock *sk;
+       struct hlist_node *node;
+       struct sk_buff *skb_copy = NULL;
+       __le16 opcode;
+
+       if (!atomic_read(&monitor_promisc))
+               return;
+
+       BT_DBG("hdev %p len %d", hdev, skb->len);
+
+       switch (bt_cb(skb)->pkt_type) {
+       case HCI_COMMAND_PKT:
+               opcode = __constant_cpu_to_le16(HCI_MON_COMMAND_PKT);
+               break;
+       case HCI_EVENT_PKT:
+               opcode = __constant_cpu_to_le16(HCI_MON_EVENT_PKT);
+               break;
+       case HCI_ACLDATA_PKT:
+               if (bt_cb(skb)->incoming)
+                       opcode = __constant_cpu_to_le16(HCI_MON_ACL_RX_PKT);
+               else
+                       opcode = __constant_cpu_to_le16(HCI_MON_ACL_TX_PKT);
+               break;
+       case HCI_SCODATA_PKT:
+               if (bt_cb(skb)->incoming)
+                       opcode = __constant_cpu_to_le16(HCI_MON_SCO_RX_PKT);
+               else
+                       opcode = __constant_cpu_to_le16(HCI_MON_SCO_TX_PKT);
+               break;
+       default:
+               return;
+       }
+
+       read_lock(&hci_sk_list.lock);
+
+       sk_for_each(sk, node, &hci_sk_list.head) {
+               struct sk_buff *nskb;
+
+               if (sk->sk_state != BT_BOUND)
+                       continue;
+
+               if (hci_pi(sk)->channel != HCI_CHANNEL_MONITOR)
+                       continue;
+
+               if (!skb_copy) {
+                       struct hci_mon_hdr *hdr;
+
+                       /* Create a private copy with headroom */
+                       skb_copy = __pskb_copy(skb, HCI_MON_HDR_SIZE, GFP_ATOMIC);
+                       if (!skb_copy)
+                               continue;
+
+                       /* Put header before the data */
+                       hdr = (void *) skb_push(skb_copy, HCI_MON_HDR_SIZE);
+                       hdr->opcode = opcode;
+                       hdr->index = cpu_to_le16(hdev->id);
+                       hdr->len = cpu_to_le16(skb->len);
+               }
+
+               nskb = skb_clone(skb_copy, GFP_ATOMIC);
+               if (!nskb)
+                       continue;
+
+               if (sock_queue_rcv_skb(sk, nskb))
+                       kfree_skb(nskb);
+       }
+
+       read_unlock(&hci_sk_list.lock);
+
+       kfree_skb(skb_copy);
+}
+
+static void send_monitor_event(struct sk_buff *skb)
+{
+       struct sock *sk;
+       struct hlist_node *node;
+
+       BT_DBG("len %d", skb->len);
+
+       read_lock(&hci_sk_list.lock);
+
+       sk_for_each(sk, node, &hci_sk_list.head) {
+               struct sk_buff *nskb;
+
+               if (sk->sk_state != BT_BOUND)
+                       continue;
+
+               if (hci_pi(sk)->channel != HCI_CHANNEL_MONITOR)
+                       continue;
+
+               nskb = skb_clone(skb, GFP_ATOMIC);
+               if (!nskb)
+                       continue;
 
                if (sock_queue_rcv_skb(sk, nskb))
                        kfree_skb(nskb);
        }
+
        read_unlock(&hci_sk_list.lock);
 }
 
+static struct sk_buff *create_monitor_event(struct hci_dev *hdev, int event)
+{
+       struct hci_mon_hdr *hdr;
+       struct hci_mon_new_index *ni;
+       struct sk_buff *skb;
+       __le16 opcode;
+
+       switch (event) {
+       case HCI_DEV_REG:
+               skb = bt_skb_alloc(HCI_MON_NEW_INDEX_SIZE, GFP_ATOMIC);
+               if (!skb)
+                       return NULL;
+
+               ni = (void *) skb_put(skb, HCI_MON_NEW_INDEX_SIZE);
+               ni->type = hdev->dev_type;
+               ni->bus = hdev->bus;
+               bacpy(&ni->bdaddr, &hdev->bdaddr);
+               memcpy(ni->name, hdev->name, 8);
+
+               opcode = __constant_cpu_to_le16(HCI_MON_NEW_INDEX);
+               break;
+
+       case HCI_DEV_UNREG:
+               skb = bt_skb_alloc(0, GFP_ATOMIC);
+               if (!skb)
+                       return NULL;
+
+               opcode = __constant_cpu_to_le16(HCI_MON_DEL_INDEX);
+               break;
+
+       default:
+               return NULL;
+       }
+
+       __net_timestamp(skb);
+
+       hdr = (void *) skb_push(skb, HCI_MON_HDR_SIZE);
+       hdr->opcode = opcode;
+       hdr->index = cpu_to_le16(hdev->id);
+       hdr->len = cpu_to_le16(skb->len - HCI_MON_HDR_SIZE);
+
+       return skb;
+}
+
+static void send_monitor_replay(struct sock *sk)
+{
+       struct hci_dev *hdev;
+
+       read_lock(&hci_dev_list_lock);
+
+       list_for_each_entry(hdev, &hci_dev_list, list) {
+               struct sk_buff *skb;
+
+               skb = create_monitor_event(hdev, HCI_DEV_REG);
+               if (!skb)
+                       continue;
+
+               if (sock_queue_rcv_skb(sk, skb))
+                       kfree_skb(skb);
+       }
+
+       read_unlock(&hci_dev_list_lock);
+}
+
+/* Generate internal stack event */
+static void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data)
+{
+       struct hci_event_hdr *hdr;
+       struct hci_ev_stack_internal *ev;
+       struct sk_buff *skb;
+
+       skb = bt_skb_alloc(HCI_EVENT_HDR_SIZE + sizeof(*ev) + dlen, GFP_ATOMIC);
+       if (!skb)
+               return;
+
+       hdr = (void *) skb_put(skb, HCI_EVENT_HDR_SIZE);
+       hdr->evt  = HCI_EV_STACK_INTERNAL;
+       hdr->plen = sizeof(*ev) + dlen;
+
+       ev  = (void *) skb_put(skb, sizeof(*ev) + dlen);
+       ev->type = type;
+       memcpy(ev->data, data, dlen);
+
+       bt_cb(skb)->incoming = 1;
+       __net_timestamp(skb);
+
+       bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
+       skb->dev = (void *) hdev;
+       hci_send_to_sock(hdev, skb);
+       kfree_skb(skb);
+}
+
+void hci_sock_dev_event(struct hci_dev *hdev, int event)
+{
+       struct hci_ev_si_device ev;
+
+       BT_DBG("hdev %s event %d", hdev->name, event);
+
+       /* Send event to monitor */
+       if (atomic_read(&monitor_promisc)) {
+               struct sk_buff *skb;
+
+               skb = create_monitor_event(hdev, event);
+               if (skb) {
+                       send_monitor_event(skb);
+                       kfree_skb(skb);
+               }
+       }
+
+       /* Send event to sockets */
+       ev.event  = event;
+       ev.dev_id = hdev->id;
+       hci_si_event(NULL, HCI_EV_SI_DEVICE, sizeof(ev), &ev);
+
+       if (event == HCI_DEV_UNREG) {
+               struct sock *sk;
+               struct hlist_node *node;
+
+               /* Detach sockets from device */
+               read_lock(&hci_sk_list.lock);
+               sk_for_each(sk, node, &hci_sk_list.head) {
+                       bh_lock_sock_nested(sk);
+                       if (hci_pi(sk)->hdev == hdev) {
+                               hci_pi(sk)->hdev = NULL;
+                               sk->sk_err = EPIPE;
+                               sk->sk_state = BT_OPEN;
+                               sk->sk_state_change(sk);
+
+                               hci_dev_put(hdev);
+                       }
+                       bh_unlock_sock(sk);
+               }
+               read_unlock(&hci_sk_list.lock);
+       }
+}
+
 static int hci_sock_release(struct socket *sock)
 {
        struct sock *sk = sock->sk;
@@ -164,6 +442,9 @@ static int hci_sock_release(struct socket *sock)
 
        hdev = hci_pi(sk)->hdev;
 
+       if (hci_pi(sk)->channel == HCI_CHANNEL_MONITOR)
+               atomic_dec(&monitor_promisc);
+
        bt_sock_unlink(&hci_sk_list, sk);
 
        if (hdev) {
@@ -190,7 +471,7 @@ static int hci_sock_blacklist_add(struct hci_dev *hdev, void __user *arg)
 
        hci_dev_lock(hdev);
 
-       err = hci_blacklist_add(hdev, &bdaddr);
+       err = hci_blacklist_add(hdev, &bdaddr, 0);
 
        hci_dev_unlock(hdev);
 
@@ -207,7 +488,7 @@ static int hci_sock_blacklist_del(struct hci_dev *hdev, void __user *arg)
 
        hci_dev_lock(hdev);
 
-       err = hci_blacklist_del(hdev, &bdaddr);
+       err = hci_blacklist_del(hdev, &bdaddr, 0);
 
        hci_dev_unlock(hdev);
 
@@ -340,34 +621,69 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le
        if (haddr.hci_family != AF_BLUETOOTH)
                return -EINVAL;
 
-       if (haddr.hci_channel > HCI_CHANNEL_CONTROL)
-               return -EINVAL;
-
-       if (haddr.hci_channel == HCI_CHANNEL_CONTROL) {
-               if (!enable_mgmt)
-                       return -EINVAL;
-               set_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags);
-       }
-
        lock_sock(sk);
 
-       if (sk->sk_state == BT_BOUND || hci_pi(sk)->hdev) {
+       if (sk->sk_state == BT_BOUND) {
                err = -EALREADY;
                goto done;
        }
 
-       if (haddr.hci_dev != HCI_DEV_NONE) {
-               hdev = hci_dev_get(haddr.hci_dev);
-               if (!hdev) {
-                       err = -ENODEV;
+       switch (haddr.hci_channel) {
+       case HCI_CHANNEL_RAW:
+               if (hci_pi(sk)->hdev) {
+                       err = -EALREADY;
                        goto done;
                }
 
-               atomic_inc(&hdev->promisc);
+               if (haddr.hci_dev != HCI_DEV_NONE) {
+                       hdev = hci_dev_get(haddr.hci_dev);
+                       if (!hdev) {
+                               err = -ENODEV;
+                               goto done;
+                       }
+
+                       atomic_inc(&hdev->promisc);
+               }
+
+               hci_pi(sk)->hdev = hdev;
+               break;
+
+       case HCI_CHANNEL_CONTROL:
+               if (haddr.hci_dev != HCI_DEV_NONE) {
+                       err = -EINVAL;
+                       goto done;
+               }
+
+               if (!capable(CAP_NET_ADMIN)) {
+                       err = -EPERM;
+                       goto done;
+               }
+
+               break;
+
+       case HCI_CHANNEL_MONITOR:
+               if (haddr.hci_dev != HCI_DEV_NONE) {
+                       err = -EINVAL;
+                       goto done;
+               }
+
+               if (!capable(CAP_NET_RAW)) {
+                       err = -EPERM;
+                       goto done;
+               }
+
+               send_monitor_replay(sk);
+
+               atomic_inc(&monitor_promisc);
+               break;
+
+       default:
+               err = -EINVAL;
+               goto done;
        }
 
+
        hci_pi(sk)->channel = haddr.hci_channel;
-       hci_pi(sk)->hdev = hdev;
        sk->sk_state = BT_BOUND;
 
 done:
@@ -461,7 +777,15 @@ static int hci_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
        skb_reset_transport_header(skb);
        err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
 
-       hci_sock_cmsg(sk, msg, skb);
+       switch (hci_pi(sk)->channel) {
+       case HCI_CHANNEL_RAW:
+               hci_sock_cmsg(sk, msg, skb);
+               break;
+       case HCI_CHANNEL_CONTROL:
+       case HCI_CHANNEL_MONITOR:
+               sock_recv_timestamp(msg, sk, skb);
+               break;
+       }
 
        skb_free_datagram(sk, skb);
 
@@ -495,6 +819,9 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
        case HCI_CHANNEL_CONTROL:
                err = mgmt_control(sk, msg, len);
                goto done;
+       case HCI_CHANNEL_MONITOR:
+               err = -EOPNOTSUPP;
+               goto done;
        default:
                err = -EINVAL;
                goto done;
@@ -574,6 +901,11 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname, char
 
        lock_sock(sk);
 
+       if (hci_pi(sk)->channel != HCI_CHANNEL_RAW) {
+               err = -EINVAL;
+               goto done;
+       }
+
        switch (optname) {
        case HCI_DATA_DIR:
                if (get_user(opt, (int __user *)optval)) {
@@ -636,6 +968,7 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname, char
                break;
        }
 
+done:
        release_sock(sk);
        return err;
 }
@@ -644,11 +977,20 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char
 {
        struct hci_ufilter uf;
        struct sock *sk = sock->sk;
-       int len, opt;
+       int len, opt, err = 0;
+
+       BT_DBG("sk %p, opt %d", sk, optname);
 
        if (get_user(len, optlen))
                return -EFAULT;
 
+       lock_sock(sk);
+
+       if (hci_pi(sk)->channel != HCI_CHANNEL_RAW) {
+               err = -EINVAL;
+               goto done;
+       }
+
        switch (optname) {
        case HCI_DATA_DIR:
                if (hci_pi(sk)->cmsg_mask & HCI_CMSG_DIR)
@@ -657,7 +999,7 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char
                        opt = 0;
 
                if (put_user(opt, optval))
-                       return -EFAULT;
+                       err = -EFAULT;
                break;
 
        case HCI_TIME_STAMP:
@@ -667,7 +1009,7 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char
                        opt = 0;
 
                if (put_user(opt, optval))
-                       return -EFAULT;
+                       err = -EFAULT;
                break;
 
        case HCI_FILTER:
@@ -682,15 +1024,17 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char
 
                len = min_t(unsigned int, len, sizeof(uf));
                if (copy_to_user(optval, &uf, len))
-                       return -EFAULT;
+                       err = -EFAULT;
                break;
 
        default:
-               return -ENOPROTOOPT;
+               err = -ENOPROTOOPT;
                break;
        }
 
-       return 0;
+done:
+       release_sock(sk);
+       return err;
 }
 
 static const struct proto_ops hci_sock_ops = {
@@ -748,52 +1092,12 @@ static int hci_sock_create(struct net *net, struct socket *sock, int protocol,
        return 0;
 }
 
-static int hci_sock_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
-{
-       struct hci_dev *hdev = (struct hci_dev *) ptr;
-       struct hci_ev_si_device ev;
-
-       BT_DBG("hdev %s event %ld", hdev->name, event);
-
-       /* Send event to sockets */
-       ev.event  = event;
-       ev.dev_id = hdev->id;
-       hci_si_event(NULL, HCI_EV_SI_DEVICE, sizeof(ev), &ev);
-
-       if (event == HCI_DEV_UNREG) {
-               struct sock *sk;
-               struct hlist_node *node;
-
-               /* Detach sockets from device */
-               read_lock(&hci_sk_list.lock);
-               sk_for_each(sk, node, &hci_sk_list.head) {
-                       bh_lock_sock_nested(sk);
-                       if (hci_pi(sk)->hdev == hdev) {
-                               hci_pi(sk)->hdev = NULL;
-                               sk->sk_err = EPIPE;
-                               sk->sk_state = BT_OPEN;
-                               sk->sk_state_change(sk);
-
-                               hci_dev_put(hdev);
-                       }
-                       bh_unlock_sock(sk);
-               }
-               read_unlock(&hci_sk_list.lock);
-       }
-
-       return NOTIFY_DONE;
-}
-
 static const struct net_proto_family hci_sock_family_ops = {
        .family = PF_BLUETOOTH,
        .owner  = THIS_MODULE,
        .create = hci_sock_create,
 };
 
-static struct notifier_block hci_sock_nblock = {
-       .notifier_call = hci_sock_dev_event
-};
-
 int __init hci_sock_init(void)
 {
        int err;
@@ -806,8 +1110,6 @@ int __init hci_sock_init(void)
        if (err < 0)
                goto error;
 
-       hci_register_notifier(&hci_sock_nblock);
-
        BT_INFO("HCI socket layer initialized");
 
        return 0;
@@ -823,10 +1125,5 @@ void hci_sock_cleanup(void)
        if (bt_sock_unregister(BTPROTO_HCI) < 0)
                BT_ERR("HCI socket unregistration failed");
 
-       hci_unregister_notifier(&hci_sock_nblock);
-
        proto_unregister(&hci_sk_proto);
 }
-
-module_param(enable_mgmt, bool, 0644);
-MODULE_PARM_DESC(enable_mgmt, "Enable Management interface");
index 52109561423514fcbd16e1c1895d2e9f7ee7a490..bc154298979a8278efa4611309e025d663f056bc 100644 (file)
@@ -33,19 +33,19 @@ static inline char *link_typetostr(int type)
 
 static ssize_t show_link_type(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct hci_conn *conn = dev_get_drvdata(dev);
+       struct hci_conn *conn = to_hci_conn(dev);
        return sprintf(buf, "%s\n", link_typetostr(conn->type));
 }
 
 static ssize_t show_link_address(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct hci_conn *conn = dev_get_drvdata(dev);
+       struct hci_conn *conn = to_hci_conn(dev);
        return sprintf(buf, "%s\n", batostr(&conn->dst));
 }
 
 static ssize_t show_link_features(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct hci_conn *conn = dev_get_drvdata(dev);
+       struct hci_conn *conn = to_hci_conn(dev);
 
        return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
                                conn->features[0], conn->features[1],
@@ -79,8 +79,8 @@ static const struct attribute_group *bt_link_groups[] = {
 
 static void bt_link_release(struct device *dev)
 {
-       void *data = dev_get_drvdata(dev);
-       kfree(data);
+       struct hci_conn *conn = to_hci_conn(dev);
+       kfree(conn);
 }
 
 static struct device_type bt_link = {
@@ -120,8 +120,6 @@ void hci_conn_add_sysfs(struct hci_conn *conn)
 
        dev_set_name(&conn->dev, "%s:%d", hdev->name, conn->handle);
 
-       dev_set_drvdata(&conn->dev, conn);
-
        if (device_add(&conn->dev) < 0) {
                BT_ERR("Failed to register connection device");
                return;
@@ -189,19 +187,19 @@ static inline char *host_typetostr(int type)
 
 static ssize_t show_bus(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct hci_dev *hdev = dev_get_drvdata(dev);
+       struct hci_dev *hdev = to_hci_dev(dev);
        return sprintf(buf, "%s\n", host_bustostr(hdev->bus));
 }
 
 static ssize_t show_type(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct hci_dev *hdev = dev_get_drvdata(dev);
+       struct hci_dev *hdev = to_hci_dev(dev);
        return sprintf(buf, "%s\n", host_typetostr(hdev->dev_type));
 }
 
 static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct hci_dev *hdev = dev_get_drvdata(dev);
+       struct hci_dev *hdev = to_hci_dev(dev);
        char name[HCI_MAX_NAME_LENGTH + 1];
        int i;
 
@@ -214,20 +212,20 @@ static ssize_t show_name(struct device *dev, struct device_attribute *attr, char
 
 static ssize_t show_class(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct hci_dev *hdev = dev_get_drvdata(dev);
+       struct hci_dev *hdev = to_hci_dev(dev);
        return sprintf(buf, "0x%.2x%.2x%.2x\n",
                        hdev->dev_class[2], hdev->dev_class[1], hdev->dev_class[0]);
 }
 
 static ssize_t show_address(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct hci_dev *hdev = dev_get_drvdata(dev);
+       struct hci_dev *hdev = to_hci_dev(dev);
        return sprintf(buf, "%s\n", batostr(&hdev->bdaddr));
 }
 
 static ssize_t show_features(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct hci_dev *hdev = dev_get_drvdata(dev);
+       struct hci_dev *hdev = to_hci_dev(dev);
 
        return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
                                hdev->features[0], hdev->features[1],
@@ -238,31 +236,31 @@ static ssize_t show_features(struct device *dev, struct device_attribute *attr,
 
 static ssize_t show_manufacturer(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct hci_dev *hdev = dev_get_drvdata(dev);
+       struct hci_dev *hdev = to_hci_dev(dev);
        return sprintf(buf, "%d\n", hdev->manufacturer);
 }
 
 static ssize_t show_hci_version(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct hci_dev *hdev = dev_get_drvdata(dev);
+       struct hci_dev *hdev = to_hci_dev(dev);
        return sprintf(buf, "%d\n", hdev->hci_ver);
 }
 
 static ssize_t show_hci_revision(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct hci_dev *hdev = dev_get_drvdata(dev);
+       struct hci_dev *hdev = to_hci_dev(dev);
        return sprintf(buf, "%d\n", hdev->hci_rev);
 }
 
 static ssize_t show_idle_timeout(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct hci_dev *hdev = dev_get_drvdata(dev);
+       struct hci_dev *hdev = to_hci_dev(dev);
        return sprintf(buf, "%d\n", hdev->idle_timeout);
 }
 
 static ssize_t store_idle_timeout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
-       struct hci_dev *hdev = dev_get_drvdata(dev);
+       struct hci_dev *hdev = to_hci_dev(dev);
        unsigned int val;
        int rv;
 
@@ -280,13 +278,13 @@ static ssize_t store_idle_timeout(struct device *dev, struct device_attribute *a
 
 static ssize_t show_sniff_max_interval(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct hci_dev *hdev = dev_get_drvdata(dev);
+       struct hci_dev *hdev = to_hci_dev(dev);
        return sprintf(buf, "%d\n", hdev->sniff_max_interval);
 }
 
 static ssize_t store_sniff_max_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
-       struct hci_dev *hdev = dev_get_drvdata(dev);
+       struct hci_dev *hdev = to_hci_dev(dev);
        u16 val;
        int rv;
 
@@ -304,13 +302,13 @@ static ssize_t store_sniff_max_interval(struct device *dev, struct device_attrib
 
 static ssize_t show_sniff_min_interval(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct hci_dev *hdev = dev_get_drvdata(dev);
+       struct hci_dev *hdev = to_hci_dev(dev);
        return sprintf(buf, "%d\n", hdev->sniff_min_interval);
 }
 
 static ssize_t store_sniff_min_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
-       struct hci_dev *hdev = dev_get_drvdata(dev);
+       struct hci_dev *hdev = to_hci_dev(dev);
        u16 val;
        int rv;
 
@@ -370,8 +368,9 @@ static const struct attribute_group *bt_host_groups[] = {
 
 static void bt_host_release(struct device *dev)
 {
-       void *data = dev_get_drvdata(dev);
-       kfree(data);
+       struct hci_dev *hdev = to_hci_dev(dev);
+       kfree(hdev);
+       module_put(THIS_MODULE);
 }
 
 static struct device_type bt_host = {
@@ -383,12 +382,12 @@ static struct device_type bt_host = {
 static int inquiry_cache_show(struct seq_file *f, void *p)
 {
        struct hci_dev *hdev = f->private;
-       struct inquiry_cache *cache = &hdev->inq_cache;
+       struct discovery_state *cache = &hdev->discovery;
        struct inquiry_entry *e;
 
        hci_dev_lock(hdev);
 
-       for (e = cache->list; e; e = e->next) {
+       list_for_each_entry(e, &cache->all, all) {
                struct inquiry_data *data = &e->data;
                seq_printf(f, "%s %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n",
                           batostr(&data->bdaddr),
@@ -523,7 +522,7 @@ void hci_init_sysfs(struct hci_dev *hdev)
        dev->type = &bt_host;
        dev->class = bt_class;
 
-       dev_set_drvdata(dev, hdev);
+       __module_get(THIS_MODULE);
        device_initialize(dev);
 }
 
index 178ac7f127adcace1c672eddff2a55e10f0be1f1..73a32d705c1fc14f423c5178c367ee4064cd9284 100644 (file)
@@ -160,10 +160,10 @@ static int hidp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne
 {
        if (cmd == HIDPGETCONNLIST) {
                struct hidp_connlist_req cl;
-               uint32_t uci;
+               u32 uci;
                int err;
 
-               if (get_user(cl.cnum, (uint32_t __user *) arg) ||
+               if (get_user(cl.cnum, (u32 __user *) arg) ||
                                get_user(uci, (u32 __user *) (arg + 4)))
                        return -EFAULT;
 
@@ -174,7 +174,7 @@ static int hidp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne
 
                err = hidp_get_connlist(&cl);
 
-               if (!err && put_user(cl.cnum, (uint32_t __user *) arg))
+               if (!err && put_user(cl.cnum, (u32 __user *) arg))
                        err = -EFAULT;
 
                return err;
index 32d338c30e65a034460652579112fb6c9b61f806..3e450f4a3125338c8d38b68d1441d545ec9ad2e3 100644 (file)
@@ -73,42 +73,28 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
 static void l2cap_send_disconn_req(struct l2cap_conn *conn,
                                struct l2cap_chan *chan, int err);
 
-static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb);
-
 /* ---- L2CAP channels ---- */
 
 static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
 {
-       struct l2cap_chan *c, *r = NULL;
-
-       rcu_read_lock();
+       struct l2cap_chan *c;
 
-       list_for_each_entry_rcu(c, &conn->chan_l, list) {
-               if (c->dcid == cid) {
-                       r = c;
-                       break;
-               }
+       list_for_each_entry(c, &conn->chan_l, list) {
+               if (c->dcid == cid)
+                       return c;
        }
-
-       rcu_read_unlock();
-       return r;
+       return NULL;
 }
 
 static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
 {
-       struct l2cap_chan *c, *r = NULL;
-
-       rcu_read_lock();
+       struct l2cap_chan *c;
 
-       list_for_each_entry_rcu(c, &conn->chan_l, list) {
-               if (c->scid == cid) {
-                       r = c;
-                       break;
-               }
+       list_for_each_entry(c, &conn->chan_l, list) {
+               if (c->scid == cid)
+                       return c;
        }
-
-       rcu_read_unlock();
-       return r;
+       return NULL;
 }
 
 /* Find channel with given SCID.
@@ -117,36 +103,32 @@ static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 ci
 {
        struct l2cap_chan *c;
 
+       mutex_lock(&conn->chan_lock);
        c = __l2cap_get_chan_by_scid(conn, cid);
-       if (c)
-               lock_sock(c->sk);
+       mutex_unlock(&conn->chan_lock);
+
        return c;
 }
 
 static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
 {
-       struct l2cap_chan *c, *r = NULL;
-
-       rcu_read_lock();
+       struct l2cap_chan *c;
 
-       list_for_each_entry_rcu(c, &conn->chan_l, list) {
-               if (c->ident == ident) {
-                       r = c;
-                       break;
-               }
+       list_for_each_entry(c, &conn->chan_l, list) {
+               if (c->ident == ident)
+                       return c;
        }
-
-       rcu_read_unlock();
-       return r;
+       return NULL;
 }
 
 static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
 {
        struct l2cap_chan *c;
 
+       mutex_lock(&conn->chan_lock);
        c = __l2cap_get_chan_by_ident(conn, ident);
-       if (c)
-               lock_sock(c->sk);
+       mutex_unlock(&conn->chan_lock);
+
        return c;
 }
 
@@ -217,51 +199,51 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
        return 0;
 }
 
-static char *state_to_string(int state)
+static void __l2cap_state_change(struct l2cap_chan *chan, int state)
 {
-       switch(state) {
-       case BT_CONNECTED:
-               return "BT_CONNECTED";
-       case BT_OPEN:
-               return "BT_OPEN";
-       case BT_BOUND:
-               return "BT_BOUND";
-       case BT_LISTEN:
-               return "BT_LISTEN";
-       case BT_CONNECT:
-               return "BT_CONNECT";
-       case BT_CONNECT2:
-               return "BT_CONNECT2";
-       case BT_CONFIG:
-               return "BT_CONFIG";
-       case BT_DISCONN:
-               return "BT_DISCONN";
-       case BT_CLOSED:
-               return "BT_CLOSED";
-       }
+       BT_DBG("chan %p %s -> %s", chan, state_to_string(chan->state),
+                                               state_to_string(state));
 
-       return "invalid state";
+       chan->state = state;
+       chan->ops->state_change(chan->data, state);
 }
 
 static void l2cap_state_change(struct l2cap_chan *chan, int state)
 {
-       BT_DBG("%p %s -> %s", chan, state_to_string(chan->state),
-                                               state_to_string(state));
+       struct sock *sk = chan->sk;
 
-       chan->state = state;
-       chan->ops->state_change(chan->data, state);
+       lock_sock(sk);
+       __l2cap_state_change(chan, state);
+       release_sock(sk);
+}
+
+static inline void __l2cap_chan_set_err(struct l2cap_chan *chan, int err)
+{
+       struct sock *sk = chan->sk;
+
+       sk->sk_err = err;
+}
+
+static inline void l2cap_chan_set_err(struct l2cap_chan *chan, int err)
+{
+       struct sock *sk = chan->sk;
+
+       lock_sock(sk);
+       __l2cap_chan_set_err(chan, err);
+       release_sock(sk);
 }
 
 static void l2cap_chan_timeout(struct work_struct *work)
 {
        struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
                                                        chan_timer.work);
-       struct sock *sk = chan->sk;
+       struct l2cap_conn *conn = chan->conn;
        int reason;
 
-       BT_DBG("chan %p state %d", chan, chan->state);
+       BT_DBG("chan %p state %s", chan, state_to_string(chan->state));
 
-       lock_sock(sk);
+       mutex_lock(&conn->chan_lock);
+       l2cap_chan_lock(chan);
 
        if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
                reason = ECONNREFUSED;
@@ -273,9 +255,11 @@ static void l2cap_chan_timeout(struct work_struct *work)
 
        l2cap_chan_close(chan, reason);
 
-       release_sock(sk);
+       l2cap_chan_unlock(chan);
 
        chan->ops->close(chan->data);
+       mutex_unlock(&conn->chan_lock);
+
        l2cap_chan_put(chan);
 }
 
@@ -287,6 +271,8 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk)
        if (!chan)
                return NULL;
 
+       mutex_init(&chan->lock);
+
        chan->sk = sk;
 
        write_lock(&chan_list_lock);
@@ -313,7 +299,7 @@ void l2cap_chan_destroy(struct l2cap_chan *chan)
        l2cap_chan_put(chan);
 }
 
-static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
+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);
@@ -322,7 +308,8 @@ static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 
        chan->conn = conn;
 
-       if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED) {
+       switch (chan->chan_type) {
+       case L2CAP_CHAN_CONN_ORIENTED:
                if (conn->hcon->type == LE_LINK) {
                        /* LE connection */
                        chan->omtu = L2CAP_LE_DEFAULT_MTU;
@@ -333,12 +320,16 @@ static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
                        chan->scid = l2cap_alloc_cid(conn);
                        chan->omtu = L2CAP_DEFAULT_MTU;
                }
-       } else if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
+               break;
+
+       case L2CAP_CHAN_CONN_LESS:
                /* Connectionless socket */
                chan->scid = L2CAP_CID_CONN_LESS;
                chan->dcid = L2CAP_CID_CONN_LESS;
                chan->omtu = L2CAP_DEFAULT_MTU;
-       } else {
+               break;
+
+       default:
                /* Raw socket can send/recv signalling messages only */
                chan->scid = L2CAP_CID_SIGNALING;
                chan->dcid = L2CAP_CID_SIGNALING;
@@ -354,11 +345,16 @@ static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 
        l2cap_chan_hold(chan);
 
-       list_add_rcu(&chan->list, &conn->chan_l);
+       list_add(&chan->list, &conn->chan_l);
+}
+
+void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
+{
+       mutex_lock(&conn->chan_lock);
+       __l2cap_chan_add(conn, chan);
+       mutex_unlock(&conn->chan_lock);
 }
 
-/* Delete channel.
- * Must be called on the locked socket. */
 static void l2cap_chan_del(struct l2cap_chan *chan, int err)
 {
        struct sock *sk = chan->sk;
@@ -371,8 +367,7 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
 
        if (conn) {
                /* Delete from channel list */
-               list_del_rcu(&chan->list);
-               synchronize_rcu();
+               list_del(&chan->list);
 
                l2cap_chan_put(chan);
 
@@ -380,11 +375,13 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
                hci_conn_put(conn->hcon);
        }
 
-       l2cap_state_change(chan, BT_CLOSED);
+       lock_sock(sk);
+
+       __l2cap_state_change(chan, BT_CLOSED);
        sock_set_flag(sk, SOCK_ZAPPED);
 
        if (err)
-               sk->sk_err = err;
+               __l2cap_chan_set_err(chan, err);
 
        if (parent) {
                bt_accept_unlink(sk);
@@ -392,6 +389,8 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
        } else
                sk->sk_state_change(sk);
 
+       release_sock(sk);
+
        if (!(test_bit(CONF_OUTPUT_DONE, &chan->conf_state) &&
                        test_bit(CONF_INPUT_DONE, &chan->conf_state)))
                return;
@@ -423,10 +422,12 @@ static void l2cap_chan_cleanup_listen(struct sock *parent)
        /* Close not yet accepted channels */
        while ((sk = bt_accept_dequeue(parent, NULL))) {
                struct l2cap_chan *chan = l2cap_pi(sk)->chan;
+
+               l2cap_chan_lock(chan);
                __clear_chan_timer(chan);
-               lock_sock(sk);
                l2cap_chan_close(chan, ECONNRESET);
-               release_sock(sk);
+               l2cap_chan_unlock(chan);
+
                chan->ops->close(chan->data);
        }
 }
@@ -436,14 +437,17 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
        struct l2cap_conn *conn = chan->conn;
        struct sock *sk = chan->sk;
 
-       BT_DBG("chan %p state %d socket %p", chan, chan->state, sk->sk_socket);
+       BT_DBG("chan %p state %s sk %p", chan,
+                                       state_to_string(chan->state), sk);
 
        switch (chan->state) {
        case BT_LISTEN:
+               lock_sock(sk);
                l2cap_chan_cleanup_listen(sk);
 
-               l2cap_state_change(chan, BT_CLOSED);
+               __l2cap_state_change(chan, BT_CLOSED);
                sock_set_flag(sk, SOCK_ZAPPED);
+               release_sock(sk);
                break;
 
        case BT_CONNECTED:
@@ -486,7 +490,9 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
                break;
 
        default:
+               lock_sock(sk);
                sock_set_flag(sk, SOCK_ZAPPED);
+               release_sock(sk);
                break;
        }
 }
@@ -661,6 +667,21 @@ static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
        return !test_bit(CONF_CONNECT_PEND, &chan->conf_state);
 }
 
+static void l2cap_send_conn_req(struct l2cap_chan *chan)
+{
+       struct l2cap_conn *conn = chan->conn;
+       struct l2cap_conn_req req;
+
+       req.scid = cpu_to_le16(chan->scid);
+       req.psm  = chan->psm;
+
+       chan->ident = l2cap_get_ident(conn);
+
+       set_bit(CONF_CONNECT_PEND, &chan->conf_state);
+
+       l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req);
+}
+
 static void l2cap_do_start(struct l2cap_chan *chan)
 {
        struct l2cap_conn *conn = chan->conn;
@@ -670,17 +691,8 @@ static void l2cap_do_start(struct l2cap_chan *chan)
                        return;
 
                if (l2cap_chan_check_security(chan) &&
-                               __l2cap_no_conn_pending(chan)) {
-                       struct l2cap_conn_req req;
-                       req.scid = cpu_to_le16(chan->scid);
-                       req.psm  = chan->psm;
-
-                       chan->ident = l2cap_get_ident(conn);
-                       set_bit(CONF_CONNECT_PEND, &chan->conf_state);
-
-                       l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
-                                                       sizeof(req), &req);
-               }
+                               __l2cap_no_conn_pending(chan))
+                       l2cap_send_conn_req(chan);
        } else {
                struct l2cap_info_req req;
                req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
@@ -688,8 +700,7 @@ static void l2cap_do_start(struct l2cap_chan *chan)
                conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
                conn->info_ident = l2cap_get_ident(conn);
 
-               schedule_delayed_work(&conn->info_timer,
-                                       msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
+               schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT);
 
                l2cap_send_cmd(conn, conn->info_ident,
                                        L2CAP_INFO_REQ, sizeof(req), &req);
@@ -714,14 +725,12 @@ static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
 
 static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err)
 {
-       struct sock *sk;
+       struct sock *sk = chan->sk;
        struct l2cap_disconn_req req;
 
        if (!conn)
                return;
 
-       sk = chan->sk;
-
        if (chan->mode == L2CAP_MODE_ERTM) {
                __clear_retrans_timer(chan);
                __clear_monitor_timer(chan);
@@ -733,56 +742,47 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *c
        l2cap_send_cmd(conn, l2cap_get_ident(conn),
                        L2CAP_DISCONN_REQ, sizeof(req), &req);
 
-       l2cap_state_change(chan, BT_DISCONN);
-       sk->sk_err = err;
+       lock_sock(sk);
+       __l2cap_state_change(chan, BT_DISCONN);
+       __l2cap_chan_set_err(chan, err);
+       release_sock(sk);
 }
 
 /* ---- L2CAP connections ---- */
 static void l2cap_conn_start(struct l2cap_conn *conn)
 {
-       struct l2cap_chan *chan;
+       struct l2cap_chan *chan, *tmp;
 
        BT_DBG("conn %p", conn);
 
-       rcu_read_lock();
+       mutex_lock(&conn->chan_lock);
 
-       list_for_each_entry_rcu(chan, &conn->chan_l, list) {
+       list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
                struct sock *sk = chan->sk;
 
-               bh_lock_sock(sk);
+               l2cap_chan_lock(chan);
 
                if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
-                       bh_unlock_sock(sk);
+                       l2cap_chan_unlock(chan);
                        continue;
                }
 
                if (chan->state == BT_CONNECT) {
-                       struct l2cap_conn_req req;
-
                        if (!l2cap_chan_check_security(chan) ||
                                        !__l2cap_no_conn_pending(chan)) {
-                               bh_unlock_sock(sk);
+                               l2cap_chan_unlock(chan);
                                continue;
                        }
 
                        if (!l2cap_mode_supported(chan->mode, conn->feat_mask)
                                        && test_bit(CONF_STATE2_DEVICE,
                                        &chan->conf_state)) {
-                               /* l2cap_chan_close() calls list_del(chan)
-                                * so release the lock */
                                l2cap_chan_close(chan, ECONNRESET);
-                               bh_unlock_sock(sk);
+                               l2cap_chan_unlock(chan);
                                continue;
                        }
 
-                       req.scid = cpu_to_le16(chan->scid);
-                       req.psm  = chan->psm;
-
-                       chan->ident = l2cap_get_ident(conn);
-                       set_bit(CONF_CONNECT_PEND, &chan->conf_state);
-
-                       l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
-                                                       sizeof(req), &req);
+                       l2cap_send_conn_req(chan);
 
                } else if (chan->state == BT_CONNECT2) {
                        struct l2cap_conn_rsp rsp;
@@ -791,6 +791,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
                        rsp.dcid = cpu_to_le16(chan->scid);
 
                        if (l2cap_chan_check_security(chan)) {
+                               lock_sock(sk);
                                if (bt_sk(sk)->defer_setup) {
                                        struct sock *parent = bt_sk(sk)->parent;
                                        rsp.result = cpu_to_le16(L2CAP_CR_PEND);
@@ -799,10 +800,11 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
                                                parent->sk_data_ready(parent, 0);
 
                                } else {
-                                       l2cap_state_change(chan, BT_CONFIG);
+                                       __l2cap_state_change(chan, BT_CONFIG);
                                        rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
                                        rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
                                }
+                               release_sock(sk);
                        } else {
                                rsp.result = cpu_to_le16(L2CAP_CR_PEND);
                                rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
@@ -813,7 +815,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
 
                        if (test_bit(CONF_REQ_SENT, &chan->conf_state) ||
                                        rsp.result != L2CAP_CR_SUCCESS) {
-                               bh_unlock_sock(sk);
+                               l2cap_chan_unlock(chan);
                                continue;
                        }
 
@@ -823,10 +825,10 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
                        chan->num_conf_req++;
                }
 
-               bh_unlock_sock(sk);
+               l2cap_chan_unlock(chan);
        }
 
-       rcu_read_unlock();
+       mutex_unlock(&conn->chan_lock);
 }
 
 /* Find socket with cid and source bdaddr.
@@ -902,28 +904,34 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
 
        __set_chan_timer(chan, sk->sk_sndtimeo);
 
-       l2cap_state_change(chan, BT_CONNECTED);
+       __l2cap_state_change(chan, BT_CONNECTED);
        parent->sk_data_ready(parent, 0);
 
 clean:
        release_sock(parent);
 }
 
-static void l2cap_chan_ready(struct sock *sk)
+static void l2cap_chan_ready(struct l2cap_chan *chan)
 {
-       struct l2cap_chan *chan = l2cap_pi(sk)->chan;
-       struct sock *parent = bt_sk(sk)->parent;
+       struct sock *sk = chan->sk;
+       struct sock *parent;
+
+       lock_sock(sk);
+
+       parent = bt_sk(sk)->parent;
 
        BT_DBG("sk %p, parent %p", sk, parent);
 
        chan->conf_state = 0;
        __clear_chan_timer(chan);
 
-       l2cap_state_change(chan, BT_CONNECTED);
+       __l2cap_state_change(chan, BT_CONNECTED);
        sk->sk_state_change(sk);
 
        if (parent)
                parent->sk_data_ready(parent, 0);
+
+       release_sock(sk);
 }
 
 static void l2cap_conn_ready(struct l2cap_conn *conn)
@@ -938,29 +946,31 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
        if (conn->hcon->out && conn->hcon->type == LE_LINK)
                smp_conn_security(conn, conn->hcon->pending_sec_level);
 
-       rcu_read_lock();
+       mutex_lock(&conn->chan_lock);
 
-       list_for_each_entry_rcu(chan, &conn->chan_l, list) {
-               struct sock *sk = chan->sk;
+       list_for_each_entry(chan, &conn->chan_l, list) {
 
-               bh_lock_sock(sk);
+               l2cap_chan_lock(chan);
 
                if (conn->hcon->type == LE_LINK) {
                        if (smp_conn_security(conn, chan->sec_level))
-                               l2cap_chan_ready(sk);
+                               l2cap_chan_ready(chan);
 
                } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
+                       struct sock *sk = chan->sk;
                        __clear_chan_timer(chan);
-                       l2cap_state_change(chan, BT_CONNECTED);
+                       lock_sock(sk);
+                       __l2cap_state_change(chan, BT_CONNECTED);
                        sk->sk_state_change(sk);
+                       release_sock(sk);
 
                } else if (chan->state == BT_CONNECT)
                        l2cap_do_start(chan);
 
-               bh_unlock_sock(sk);
+               l2cap_chan_unlock(chan);
        }
 
-       rcu_read_unlock();
+       mutex_unlock(&conn->chan_lock);
 }
 
 /* Notify sockets that we cannot guaranty reliability anymore */
@@ -970,16 +980,14 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
 
        BT_DBG("conn %p", conn);
 
-       rcu_read_lock();
-
-       list_for_each_entry_rcu(chan, &conn->chan_l, list) {
-               struct sock *sk = chan->sk;
+       mutex_lock(&conn->chan_lock);
 
+       list_for_each_entry(chan, &conn->chan_l, list) {
                if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
-                       sk->sk_err = err;
+                       __l2cap_chan_set_err(chan, err);
        }
 
-       rcu_read_unlock();
+       mutex_unlock(&conn->chan_lock);
 }
 
 static void l2cap_info_timeout(struct work_struct *work)
@@ -997,7 +1005,6 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
 {
        struct l2cap_conn *conn = hcon->l2cap_data;
        struct l2cap_chan *chan, *l;
-       struct sock *sk;
 
        if (!conn)
                return;
@@ -1006,21 +1013,27 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
 
        kfree_skb(conn->rx_skb);
 
+       mutex_lock(&conn->chan_lock);
+
        /* Kill channels */
        list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
-               sk = chan->sk;
-               lock_sock(sk);
+               l2cap_chan_lock(chan);
+
                l2cap_chan_del(chan, err);
-               release_sock(sk);
+
+               l2cap_chan_unlock(chan);
+
                chan->ops->close(chan->data);
        }
 
+       mutex_unlock(&conn->chan_lock);
+
        hci_chan_del(conn->hchan);
 
        if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
                cancel_delayed_work_sync(&conn->info_timer);
 
-       if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) {
+       if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) {
                cancel_delayed_work_sync(&conn->security_timer);
                smp_chan_destroy(conn);
        }
@@ -1072,6 +1085,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
        conn->feat_mask = 0;
 
        spin_lock_init(&conn->lock);
+       mutex_init(&conn->chan_lock);
 
        INIT_LIST_HEAD(&conn->chan_l);
 
@@ -1139,7 +1153,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d
 
        hci_dev_lock(hdev);
 
-       lock_sock(sk);
+       l2cap_chan_lock(chan);
 
        /* PSM must be odd and lsb of upper byte must be 0 */
        if ((__le16_to_cpu(psm) & 0x0101) != 0x0001 && !cid &&
@@ -1166,17 +1180,21 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d
                goto done;
        }
 
+       lock_sock(sk);
+
        switch (sk->sk_state) {
        case BT_CONNECT:
        case BT_CONNECT2:
        case BT_CONFIG:
                /* Already connecting */
                err = 0;
+               release_sock(sk);
                goto done;
 
        case BT_CONNECTED:
                /* Already connected */
                err = -EISCONN;
+               release_sock(sk);
                goto done;
 
        case BT_OPEN:
@@ -1186,11 +1204,15 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d
 
        default:
                err = -EBADFD;
+               release_sock(sk);
                goto done;
        }
 
        /* Set destination address and psm */
        bacpy(&bt_sk(sk)->dst, dst);
+
+       release_sock(sk);
+
        chan->psm = psm;
        chan->dcid = cid;
 
@@ -1218,7 +1240,9 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d
        /* Update source addr of the socket */
        bacpy(src, conn->src);
 
+       l2cap_chan_unlock(chan);
        l2cap_chan_add(conn, chan);
+       l2cap_chan_lock(chan);
 
        l2cap_state_change(chan, BT_CONNECT);
        __set_chan_timer(chan, sk->sk_sndtimeo);
@@ -1235,6 +1259,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d
        err = 0;
 
 done:
+       l2cap_chan_unlock(chan);
        hci_dev_unlock(hdev);
        hci_dev_put(hdev);
        return err;
@@ -1276,14 +1301,14 @@ static void l2cap_monitor_timeout(struct work_struct *work)
 {
        struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
                                                        monitor_timer.work);
-       struct sock *sk = chan->sk;
 
        BT_DBG("chan %p", chan);
 
-       lock_sock(sk);
+       l2cap_chan_lock(chan);
+
        if (chan->retry_count >= chan->remote_max_tx) {
                l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
-               release_sock(sk);
+               l2cap_chan_unlock(chan);
                return;
        }
 
@@ -1291,25 +1316,26 @@ static void l2cap_monitor_timeout(struct work_struct *work)
        __set_monitor_timer(chan);
 
        l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
-       release_sock(sk);
+       l2cap_chan_unlock(chan);
 }
 
 static void l2cap_retrans_timeout(struct work_struct *work)
 {
        struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
                                                        retrans_timer.work);
-       struct sock *sk = chan->sk;
 
        BT_DBG("chan %p", chan);
 
-       lock_sock(sk);
+       l2cap_chan_lock(chan);
+
        chan->retry_count = 1;
        __set_monitor_timer(chan);
 
        set_bit(CONN_WAIT_F, &chan->conn_state);
 
        l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
-       release_sock(sk);
+
+       l2cap_chan_unlock(chan);
 }
 
 static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
@@ -1450,17 +1476,19 @@ static int l2cap_ertm_send(struct l2cap_chan *chan)
 
                chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
 
-               if (bt_cb(skb)->retries == 1)
+               if (bt_cb(skb)->retries == 1) {
                        chan->unacked_frames++;
 
+                       if (!nsent++)
+                               __clear_ack_timer(chan);
+               }
+
                chan->frames_sent++;
 
                if (skb_queue_is_last(&chan->tx_q, skb))
                        chan->tx_send_head = NULL;
                else
                        chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
-
-               nsent++;
        }
 
        return nsent;
@@ -1478,7 +1506,7 @@ static int l2cap_retransmit_frames(struct l2cap_chan *chan)
        return ret;
 }
 
-static void l2cap_send_ack(struct l2cap_chan *chan)
+static void __l2cap_send_ack(struct l2cap_chan *chan)
 {
        u32 control = 0;
 
@@ -1498,6 +1526,12 @@ static void l2cap_send_ack(struct l2cap_chan *chan)
        l2cap_send_sframe(chan, control);
 }
 
+static void l2cap_send_ack(struct l2cap_chan *chan)
+{
+       __clear_ack_timer(chan);
+       __l2cap_send_ack(chan);
+}
+
 static void l2cap_send_srejtail(struct l2cap_chan *chan)
 {
        struct srej_list *tail;
@@ -1512,9 +1546,11 @@ static void l2cap_send_srejtail(struct l2cap_chan *chan)
        l2cap_send_sframe(chan, control);
 }
 
-static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, int len, int count, struct sk_buff *skb)
+static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan,
+                                        struct msghdr *msg, int len,
+                                        int count, struct sk_buff *skb)
 {
-       struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
+       struct l2cap_conn *conn = chan->conn;
        struct sk_buff **frag;
        int err, sent = 0;
 
@@ -1529,7 +1565,10 @@ static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, in
        while (len) {
                count = min_t(unsigned int, conn->mtu, len);
 
-               *frag = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
+               *frag = chan->ops->alloc_skb(chan, count,
+                                            msg->msg_flags & MSG_DONTWAIT,
+                                            &err);
+
                if (!*frag)
                        return err;
                if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
@@ -1550,17 +1589,18 @@ 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 + L2CAP_PSMLEN_SIZE;
        struct l2cap_hdr *lh;
 
-       BT_DBG("sk %p len %d priority %u", sk, (int)len, priority);
+       BT_DBG("chan %p len %d priority %u", chan, (int)len, priority);
 
        count = min_t(unsigned int, (conn->mtu - hlen), len);
-       skb = bt_skb_send_alloc(sk, count + hlen,
-                       msg->msg_flags & MSG_DONTWAIT, &err);
+
+       skb = chan->ops->alloc_skb(chan, count + hlen,
+                                  msg->msg_flags & MSG_DONTWAIT, &err);
+
        if (!skb)
                return ERR_PTR(err);
 
@@ -1572,7 +1612,7 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
        lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
        put_unaligned_le16(chan->psm, skb_put(skb, 2));
 
-       err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
+       err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
        if (unlikely(err < 0)) {
                kfree_skb(skb);
                return ERR_PTR(err);
@@ -1584,17 +1624,18 @@ 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;
        struct sk_buff *skb;
        int err, count, hlen = L2CAP_HDR_SIZE;
        struct l2cap_hdr *lh;
 
-       BT_DBG("sk %p len %d", sk, (int)len);
+       BT_DBG("chan %p len %d", chan, (int)len);
 
        count = min_t(unsigned int, (conn->mtu - hlen), len);
-       skb = bt_skb_send_alloc(sk, count + hlen,
-                       msg->msg_flags & MSG_DONTWAIT, &err);
+
+       skb = chan->ops->alloc_skb(chan, count + hlen,
+                                  msg->msg_flags & MSG_DONTWAIT, &err);
+
        if (!skb)
                return ERR_PTR(err);
 
@@ -1605,7 +1646,7 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
        lh->cid = cpu_to_le16(chan->dcid);
        lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
 
-       err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
+       err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
        if (unlikely(err < 0)) {
                kfree_skb(skb);
                return ERR_PTR(err);
@@ -1617,13 +1658,12 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
                                                struct msghdr *msg, size_t len,
                                                u32 control, u16 sdulen)
 {
-       struct sock *sk = chan->sk;
        struct l2cap_conn *conn = chan->conn;
        struct sk_buff *skb;
        int err, count, hlen;
        struct l2cap_hdr *lh;
 
-       BT_DBG("sk %p len %d", sk, (int)len);
+       BT_DBG("chan %p len %d", chan, (int)len);
 
        if (!conn)
                return ERR_PTR(-ENOTCONN);
@@ -1640,8 +1680,10 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
                hlen += L2CAP_FCS_SIZE;
 
        count = min_t(unsigned int, (conn->mtu - hlen), len);
-       skb = bt_skb_send_alloc(sk, count + hlen,
-                       msg->msg_flags & MSG_DONTWAIT, &err);
+
+       skb = chan->ops->alloc_skb(chan, count + hlen,
+                                       msg->msg_flags & MSG_DONTWAIT, &err);
+
        if (!skb)
                return ERR_PTR(err);
 
@@ -1655,7 +1697,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
        if (sdulen)
                put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
 
-       err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
+       err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
        if (unlikely(err < 0)) {
                kfree_skb(skb);
                return ERR_PTR(err);
@@ -1801,9 +1843,9 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
 
        BT_DBG("conn %p", conn);
 
-       rcu_read_lock();
+       mutex_lock(&conn->chan_lock);
 
-       list_for_each_entry_rcu(chan, &conn->chan_l, list) {
+       list_for_each_entry(chan, &conn->chan_l, list) {
                struct sock *sk = chan->sk;
                if (chan->chan_type != L2CAP_CHAN_RAW)
                        continue;
@@ -1819,7 +1861,7 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
                        kfree_skb(nskb);
        }
 
-       rcu_read_unlock();
+       mutex_unlock(&conn->chan_lock);
 }
 
 /* ---- L2CAP signalling commands ---- */
@@ -1987,9 +2029,13 @@ static void l2cap_ack_timeout(struct work_struct *work)
 
        BT_DBG("chan %p", chan);
 
-       lock_sock(chan->sk);
-       l2cap_send_ack(chan);
-       release_sock(chan->sk);
+       l2cap_chan_lock(chan);
+
+       __l2cap_send_ack(chan);
+
+       l2cap_chan_unlock(chan);
+
+       l2cap_chan_put(chan);
 }
 
 static inline void l2cap_ertm_init(struct l2cap_chan *chan)
@@ -2607,6 +2653,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
 
        parent = pchan->sk;
 
+       mutex_lock(&conn->chan_lock);
        lock_sock(parent);
 
        /* Check if the ACL is secure enough (if not SDP) */
@@ -2647,7 +2694,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
 
        bt_accept_enqueue(parent, sk);
 
-       l2cap_chan_add(conn, chan);
+       __l2cap_chan_add(conn, chan);
 
        dcid = chan->scid;
 
@@ -2658,28 +2705,29 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
        if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
                if (l2cap_chan_check_security(chan)) {
                        if (bt_sk(sk)->defer_setup) {
-                               l2cap_state_change(chan, BT_CONNECT2);
+                               __l2cap_state_change(chan, BT_CONNECT2);
                                result = L2CAP_CR_PEND;
                                status = L2CAP_CS_AUTHOR_PEND;
                                parent->sk_data_ready(parent, 0);
                        } else {
-                               l2cap_state_change(chan, BT_CONFIG);
+                               __l2cap_state_change(chan, BT_CONFIG);
                                result = L2CAP_CR_SUCCESS;
                                status = L2CAP_CS_NO_INFO;
                        }
                } else {
-                       l2cap_state_change(chan, BT_CONNECT2);
+                       __l2cap_state_change(chan, BT_CONNECT2);
                        result = L2CAP_CR_PEND;
                        status = L2CAP_CS_AUTHEN_PEND;
                }
        } else {
-               l2cap_state_change(chan, BT_CONNECT2);
+               __l2cap_state_change(chan, BT_CONNECT2);
                result = L2CAP_CR_PEND;
                status = L2CAP_CS_NO_INFO;
        }
 
 response:
        release_sock(parent);
+       mutex_unlock(&conn->chan_lock);
 
 sendresp:
        rsp.scid   = cpu_to_le16(scid);
@@ -2695,8 +2743,7 @@ sendresp:
                conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
                conn->info_ident = l2cap_get_ident(conn);
 
-               schedule_delayed_work(&conn->info_timer,
-                                       msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
+               schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT);
 
                l2cap_send_cmd(conn, conn->info_ident,
                                        L2CAP_INFO_REQ, sizeof(info), &info);
@@ -2719,27 +2766,36 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
        struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
        u16 scid, dcid, result, status;
        struct l2cap_chan *chan;
-       struct sock *sk;
        u8 req[128];
+       int err;
 
        scid   = __le16_to_cpu(rsp->scid);
        dcid   = __le16_to_cpu(rsp->dcid);
        result = __le16_to_cpu(rsp->result);
        status = __le16_to_cpu(rsp->status);
 
-       BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
+       BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x",
+                                               dcid, scid, result, status);
+
+       mutex_lock(&conn->chan_lock);
 
        if (scid) {
-               chan = l2cap_get_chan_by_scid(conn, scid);
-               if (!chan)
-                       return -EFAULT;
+               chan = __l2cap_get_chan_by_scid(conn, scid);
+               if (!chan) {
+                       err = -EFAULT;
+                       goto unlock;
+               }
        } else {
-               chan = l2cap_get_chan_by_ident(conn, cmd->ident);
-               if (!chan)
-                       return -EFAULT;
+               chan = __l2cap_get_chan_by_ident(conn, cmd->ident);
+               if (!chan) {
+                       err = -EFAULT;
+                       goto unlock;
+               }
        }
 
-       sk = chan->sk;
+       err = 0;
+
+       l2cap_chan_lock(chan);
 
        switch (result) {
        case L2CAP_CR_SUCCESS:
@@ -2765,8 +2821,12 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
                break;
        }
 
-       release_sock(sk);
-       return 0;
+       l2cap_chan_unlock(chan);
+
+unlock:
+       mutex_unlock(&conn->chan_lock);
+
+       return err;
 }
 
 static inline void set_default_fcs(struct l2cap_chan *chan)
@@ -2786,7 +2846,6 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        u16 dcid, flags;
        u8 rsp[64];
        struct l2cap_chan *chan;
-       struct sock *sk;
        int len;
 
        dcid  = __le16_to_cpu(req->dcid);
@@ -2798,7 +2857,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        if (!chan)
                return -ENOENT;
 
-       sk = chan->sk;
+       l2cap_chan_lock(chan);
 
        if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) {
                struct l2cap_cmd_rej_cid rej;
@@ -2860,7 +2919,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
                if (chan->mode == L2CAP_MODE_ERTM)
                        l2cap_ertm_init(chan);
 
-               l2cap_chan_ready(sk);
+               l2cap_chan_ready(chan);
                goto unlock;
        }
 
@@ -2887,7 +2946,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        }
 
 unlock:
-       release_sock(sk);
+       l2cap_chan_unlock(chan);
        return 0;
 }
 
@@ -2896,7 +2955,6 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
        u16 scid, flags, result;
        struct l2cap_chan *chan;
-       struct sock *sk;
        int len = cmd->len - sizeof(*rsp);
 
        scid   = __le16_to_cpu(rsp->scid);
@@ -2910,7 +2968,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        if (!chan)
                return 0;
 
-       sk = chan->sk;
+       l2cap_chan_lock(chan);
 
        switch (result) {
        case L2CAP_CONF_SUCCESS:
@@ -2969,9 +3027,9 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
                }
 
        default:
-               sk->sk_err = ECONNRESET;
-               __set_chan_timer(chan,
-                               msecs_to_jiffies(L2CAP_DISC_REJ_TIMEOUT));
+               l2cap_chan_set_err(chan, ECONNRESET);
+
+               __set_chan_timer(chan, L2CAP_DISC_REJ_TIMEOUT);
                l2cap_send_disconn_req(conn, chan, ECONNRESET);
                goto done;
        }
@@ -2991,11 +3049,11 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
                if (chan->mode ==  L2CAP_MODE_ERTM)
                        l2cap_ertm_init(chan);
 
-               l2cap_chan_ready(sk);
+               l2cap_chan_ready(chan);
        }
 
 done:
-       release_sock(sk);
+       l2cap_chan_unlock(chan);
        return 0;
 }
 
@@ -3012,9 +3070,15 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
 
        BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
 
-       chan = l2cap_get_chan_by_scid(conn, dcid);
-       if (!chan)
+       mutex_lock(&conn->chan_lock);
+
+       chan = __l2cap_get_chan_by_scid(conn, dcid);
+       if (!chan) {
+               mutex_unlock(&conn->chan_lock);
                return 0;
+       }
+
+       l2cap_chan_lock(chan);
 
        sk = chan->sk;
 
@@ -3022,12 +3086,18 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
        rsp.scid = cpu_to_le16(chan->dcid);
        l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
 
+       lock_sock(sk);
        sk->sk_shutdown = SHUTDOWN_MASK;
+       release_sock(sk);
 
        l2cap_chan_del(chan, ECONNRESET);
-       release_sock(sk);
+
+       l2cap_chan_unlock(chan);
 
        chan->ops->close(chan->data);
+
+       mutex_unlock(&conn->chan_lock);
+
        return 0;
 }
 
@@ -3036,23 +3106,30 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
        struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
        u16 dcid, scid;
        struct l2cap_chan *chan;
-       struct sock *sk;
 
        scid = __le16_to_cpu(rsp->scid);
        dcid = __le16_to_cpu(rsp->dcid);
 
        BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
 
-       chan = l2cap_get_chan_by_scid(conn, scid);
-       if (!chan)
+       mutex_lock(&conn->chan_lock);
+
+       chan = __l2cap_get_chan_by_scid(conn, scid);
+       if (!chan) {
+               mutex_unlock(&conn->chan_lock);
                return 0;
+       }
 
-       sk = chan->sk;
+       l2cap_chan_lock(chan);
 
        l2cap_chan_del(chan, 0);
-       release_sock(sk);
+
+       l2cap_chan_unlock(chan);
 
        chan->ops->close(chan->data);
+
+       mutex_unlock(&conn->chan_lock);
+
        return 0;
 }
 
@@ -3132,7 +3209,8 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
                return 0;
        }
 
-       if (type == L2CAP_IT_FEAT_MASK) {
+       switch (type) {
+       case L2CAP_IT_FEAT_MASK:
                conn->feat_mask = get_unaligned_le32(rsp->data);
 
                if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
@@ -3149,11 +3227,15 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
 
                        l2cap_conn_start(conn);
                }
-       } else if (type == L2CAP_IT_FIXED_CHAN) {
+               break;
+
+       case L2CAP_IT_FIXED_CHAN:
+               conn->fixed_chan_mask = rsp->data[0];
                conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
                conn->info_ident = 0;
 
                l2cap_conn_start(conn);
+               break;
        }
 
        return 0;
@@ -3713,19 +3795,11 @@ static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u3
 
 static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
 {
-       u32 control;
-
        BT_DBG("chan %p, Enter local busy", chan);
 
        set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
 
-       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);
-
-       __clear_ack_timer(chan);
+       __set_ack_timer(chan);
 }
 
 static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
@@ -3865,8 +3939,11 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_cont
                goto drop;
        }
 
-       if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state))
+       if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
+               if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
+                       l2cap_send_ack(chan);
                goto drop;
+       }
 
        if (tx_seq == chan->expected_tx_seq)
                goto expected;
@@ -3927,15 +4004,15 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_cont
                __skb_queue_head_init(&chan->srej_q);
                l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
 
-               set_bit(CONN_SEND_PBIT, &chan->conn_state);
+               /* Set P-bit only if there are some I-frames to ack. */
+               if (__clear_ack_timer(chan))
+                       set_bit(CONN_SEND_PBIT, &chan->conn_state);
 
                err = l2cap_send_srejframe(chan, tx_seq);
                if (err < 0) {
                        l2cap_send_disconn_req(chan->conn, chan, -err);
                        return err;
                }
-
-               __clear_ack_timer(chan);
        }
        return 0;
 
@@ -4135,9 +4212,8 @@ static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u32 rx_cont
        return 0;
 }
 
-static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
+static int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
 {
-       struct l2cap_chan *chan = l2cap_pi(sk)->chan;
        u32 control;
        u16 req_seq;
        int len, next_tx_seq_offset, req_seq_offset;
@@ -4205,7 +4281,6 @@ drop:
 static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
 {
        struct l2cap_chan *chan;
-       struct sock *sk = NULL;
        u32 control;
        u16 tx_seq;
        int len;
@@ -4213,10 +4288,12 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
        chan = l2cap_get_chan_by_scid(conn, cid);
        if (!chan) {
                BT_DBG("unknown cid 0x%4.4x", cid);
-               goto drop;
+               /* Drop packet and return */
+               kfree_skb(skb);
+               return 0;
        }
 
-       sk = chan->sk;
+       l2cap_chan_lock(chan);
 
        BT_DBG("chan %p, len %d", chan, skb->len);
 
@@ -4238,7 +4315,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
                break;
 
        case L2CAP_MODE_ERTM:
-               l2cap_ertm_data_rcv(sk, skb);
+               l2cap_ertm_data_rcv(chan, skb);
 
                goto done;
 
@@ -4287,26 +4364,20 @@ drop:
        kfree_skb(skb);
 
 done:
-       if (sk)
-               release_sock(sk);
+       l2cap_chan_unlock(chan);
 
        return 0;
 }
 
 static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
 {
-       struct sock *sk = NULL;
        struct l2cap_chan *chan;
 
        chan = l2cap_global_chan_by_psm(0, psm, conn->src);
        if (!chan)
                goto drop;
 
-       sk = chan->sk;
-
-       lock_sock(sk);
-
-       BT_DBG("sk %p, len %d", sk, skb->len);
+       BT_DBG("chan %p, len %d", chan, skb->len);
 
        if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
                goto drop;
@@ -4315,31 +4386,23 @@ static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, str
                goto drop;
 
        if (!chan->ops->recv(chan->data, skb))
-               goto done;
+               return 0;
 
 drop:
        kfree_skb(skb);
 
-done:
-       if (sk)
-               release_sock(sk);
        return 0;
 }
 
 static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
 {
-       struct sock *sk = NULL;
        struct l2cap_chan *chan;
 
        chan = l2cap_global_chan_by_scid(0, cid, conn->src);
        if (!chan)
                goto drop;
 
-       sk = chan->sk;
-
-       lock_sock(sk);
-
-       BT_DBG("sk %p, len %d", sk, skb->len);
+       BT_DBG("chan %p, len %d", chan, skb->len);
 
        if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
                goto drop;
@@ -4348,14 +4411,11 @@ static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct
                goto drop;
 
        if (!chan->ops->recv(chan->data, skb))
-               goto done;
+               return 0;
 
 drop:
        kfree_skb(skb);
 
-done:
-       if (sk)
-               release_sock(sk);
        return 0;
 }
 
@@ -4479,8 +4539,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,
-                                       msecs_to_jiffies(L2CAP_ENC_TIMEOUT));
+                       __set_chan_timer(chan, L2CAP_ENC_TIMEOUT);
                } else if (chan->sec_level == BT_SECURITY_HIGH)
                        l2cap_chan_close(chan, ECONNREFUSED);
        } else {
@@ -4504,57 +4563,49 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
                cancel_delayed_work(&conn->security_timer);
        }
 
-       rcu_read_lock();
-
-       list_for_each_entry_rcu(chan, &conn->chan_l, list) {
-               struct sock *sk = chan->sk;
+       mutex_lock(&conn->chan_lock);
 
-               bh_lock_sock(sk);
+       list_for_each_entry(chan, &conn->chan_l, list) {
+               l2cap_chan_lock(chan);
 
                BT_DBG("chan->scid %d", chan->scid);
 
                if (chan->scid == L2CAP_CID_LE_DATA) {
                        if (!status && encrypt) {
                                chan->sec_level = hcon->sec_level;
-                               l2cap_chan_ready(sk);
+                               l2cap_chan_ready(chan);
                        }
 
-                       bh_unlock_sock(sk);
+                       l2cap_chan_unlock(chan);
                        continue;
                }
 
                if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) {
-                       bh_unlock_sock(sk);
+                       l2cap_chan_unlock(chan);
                        continue;
                }
 
                if (!status && (chan->state == BT_CONNECTED ||
                                                chan->state == BT_CONFIG)) {
                        l2cap_check_encryption(chan, encrypt);
-                       bh_unlock_sock(sk);
+                       l2cap_chan_unlock(chan);
                        continue;
                }
 
                if (chan->state == BT_CONNECT) {
                        if (!status) {
-                               struct l2cap_conn_req req;
-                               req.scid = cpu_to_le16(chan->scid);
-                               req.psm  = chan->psm;
-
-                               chan->ident = l2cap_get_ident(conn);
-                               set_bit(CONF_CONNECT_PEND, &chan->conf_state);
-
-                               l2cap_send_cmd(conn, chan->ident,
-                                       L2CAP_CONN_REQ, sizeof(req), &req);
+                               l2cap_send_conn_req(chan);
                        } else {
                                __clear_chan_timer(chan);
-                               __set_chan_timer(chan,
-                                       msecs_to_jiffies(L2CAP_DISC_TIMEOUT));
+                               __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
                        }
                } else if (chan->state == BT_CONNECT2) {
+                       struct sock *sk = chan->sk;
                        struct l2cap_conn_rsp rsp;
                        __u16 res, stat;
 
+                       lock_sock(sk);
+
                        if (!status) {
                                if (bt_sk(sk)->defer_setup) {
                                        struct sock *parent = bt_sk(sk)->parent;
@@ -4563,18 +4614,19 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
                                        if (parent)
                                                parent->sk_data_ready(parent, 0);
                                } else {
-                                       l2cap_state_change(chan, BT_CONFIG);
+                                       __l2cap_state_change(chan, BT_CONFIG);
                                        res = L2CAP_CR_SUCCESS;
                                        stat = L2CAP_CS_NO_INFO;
                                }
                        } else {
-                               l2cap_state_change(chan, BT_DISCONN);
-                               __set_chan_timer(chan,
-                                       msecs_to_jiffies(L2CAP_DISC_TIMEOUT));
+                               __l2cap_state_change(chan, BT_DISCONN);
+                               __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
                                res = L2CAP_CR_SEC_BLOCK;
                                stat = L2CAP_CS_NO_INFO;
                        }
 
+                       release_sock(sk);
+
                        rsp.scid   = cpu_to_le16(chan->dcid);
                        rsp.dcid   = cpu_to_le16(chan->scid);
                        rsp.result = cpu_to_le16(res);
@@ -4583,10 +4635,10 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
                                                        sizeof(rsp), &rsp);
                }
 
-               bh_unlock_sock(sk);
+               l2cap_chan_unlock(chan);
        }
 
-       rcu_read_unlock();
+       mutex_unlock(&conn->chan_lock);
 
        return 0;
 }
@@ -4647,6 +4699,7 @@ int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
 
                if (chan && chan->sk) {
                        struct sock *sk = chan->sk;
+                       lock_sock(sk);
 
                        if (chan->imtu < len - L2CAP_HDR_SIZE) {
                                BT_ERR("Frame exceeding recv MTU (len %d, "
@@ -4717,7 +4770,7 @@ static int l2cap_debugfs_show(struct seq_file *f, void *p)
                                        c->state, __le16_to_cpu(c->psm),
                                        c->scid, c->dcid, c->imtu, c->omtu,
                                        c->sec_level, c->mode);
-}
+       }
 
        read_unlock(&chan_list_lock);
 
index 401d9428ae4c824f6dbe2871d77bb6742ba4688c..c4fe583b0af65f0a2bccfa9b3ee6e9d459f1c245 100644 (file)
@@ -125,13 +125,15 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
 
        err = l2cap_chan_connect(chan, la.l2_psm, la.l2_cid, &la.l2_bdaddr);
        if (err)
-               goto done;
+               return err;
+
+       lock_sock(sk);
 
        err = bt_sock_wait_state(sk, BT_CONNECTED,
                        sock_sndtimeo(sk, flags & O_NONBLOCK));
-done:
-       if (sock_owned_by_user(sk))
-               release_sock(sk);
+
+       release_sock(sk);
+
        return err;
 }
 
@@ -783,7 +785,7 @@ static void l2cap_sock_kill(struct sock *sk)
        if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket)
                return;
 
-       BT_DBG("sk %p state %d", sk, sk->sk_state);
+       BT_DBG("sk %p state %s", sk, state_to_string(sk->sk_state));
 
        /* Kill poor orphan */
 
@@ -795,7 +797,8 @@ static void l2cap_sock_kill(struct sock *sk)
 static int l2cap_sock_shutdown(struct socket *sock, int how)
 {
        struct sock *sk = sock->sk;
-       struct l2cap_chan *chan = l2cap_pi(sk)->chan;
+       struct l2cap_chan *chan;
+       struct l2cap_conn *conn;
        int err = 0;
 
        BT_DBG("sock %p, sk %p", sock, sk);
@@ -803,13 +806,24 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
        if (!sk)
                return 0;
 
+       chan = l2cap_pi(sk)->chan;
+       conn = chan->conn;
+
+       if (conn)
+               mutex_lock(&conn->chan_lock);
+
+       l2cap_chan_lock(chan);
        lock_sock(sk);
+
        if (!sk->sk_shutdown) {
                if (chan->mode == L2CAP_MODE_ERTM)
                        err = __l2cap_wait_ack(sk);
 
                sk->sk_shutdown = SHUTDOWN_MASK;
+
+               release_sock(sk);
                l2cap_chan_close(chan, 0);
+               lock_sock(sk);
 
                if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime)
                        err = bt_sock_wait_state(sk, BT_CLOSED,
@@ -820,6 +834,11 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
                err = -sk->sk_err;
 
        release_sock(sk);
+       l2cap_chan_unlock(chan);
+
+       if (conn)
+               mutex_unlock(&conn->chan_lock);
+
        return err;
 }
 
@@ -862,8 +881,12 @@ static int l2cap_sock_recv_cb(void *data, struct sk_buff *skb)
        struct sock *sk = data;
        struct l2cap_pinfo *pi = l2cap_pi(sk);
 
-       if (pi->rx_busy_skb)
-               return -ENOMEM;
+       lock_sock(sk);
+
+       if (pi->rx_busy_skb) {
+               err = -ENOMEM;
+               goto done;
+       }
 
        err = sock_queue_rcv_skb(sk, skb);
 
@@ -882,6 +905,9 @@ static int l2cap_sock_recv_cb(void *data, struct sk_buff *skb)
                err = 0;
        }
 
+done:
+       release_sock(sk);
+
        return err;
 }
 
@@ -899,12 +925,22 @@ static void l2cap_sock_state_change_cb(void *data, int state)
        sk->sk_state = state;
 }
 
+static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan,
+                                              unsigned long len, int nb,
+                                              int *err)
+{
+       struct sock *sk = chan->sk;
+
+       return bt_skb_send_alloc(sk, len, nb, err);
+}
+
 static struct l2cap_ops l2cap_chan_ops = {
        .name           = "L2CAP Socket Interface",
        .new_connection = l2cap_sock_new_connection_cb,
        .recv           = l2cap_sock_recv_cb,
        .close          = l2cap_sock_close_cb,
        .state_change   = l2cap_sock_state_change_cb,
+       .alloc_skb      = l2cap_sock_alloc_skb_cb,
 };
 
 static void l2cap_sock_destruct(struct sock *sk)
@@ -1004,7 +1040,7 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int p
        INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
 
        sk->sk_destruct = l2cap_sock_destruct;
-       sk->sk_sndtimeo = msecs_to_jiffies(L2CAP_CONN_TIMEOUT);
+       sk->sk_sndtimeo = L2CAP_CONN_TIMEOUT;
 
        sock_reset_flag(sk, SOCK_ZAPPED);
 
index 86a6bed229df3af89f8b0b891099a0e305047955..506628876f3604dcdf9530852e6a27095dbf1f21 100644 (file)
@@ -24,6 +24,8 @@
 
 /* Bluetooth kernel library. */
 
+#define pr_fmt(fmt) "Bluetooth: " fmt
+
 #include <linux/module.h>
 
 #include <linux/kernel.h>
@@ -151,7 +153,26 @@ int bt_to_errno(__u16 code)
 }
 EXPORT_SYMBOL(bt_to_errno);
 
-int bt_printk(const char *level, const char *format, ...)
+int bt_info(const char *format, ...)
+{
+       struct va_format vaf;
+       va_list args;
+       int r;
+
+       va_start(args, format);
+
+       vaf.fmt = format;
+       vaf.va = &args;
+
+       r = pr_info("%pV", &vaf);
+
+       va_end(args);
+
+       return r;
+}
+EXPORT_SYMBOL(bt_info);
+
+int bt_err(const char *format, ...)
 {
        struct va_format vaf;
        va_list args;
@@ -162,10 +183,10 @@ int bt_printk(const char *level, const char *format, ...)
        vaf.fmt = format;
        vaf.va = &args;
 
-       r = printk("%sBluetooth: %pV\n", level, &vaf);
+       r = pr_err("%pV", &vaf);
 
        va_end(args);
 
        return r;
 }
-EXPORT_SYMBOL(bt_printk);
+EXPORT_SYMBOL(bt_err);
index bc8e59dda78e2bf72f81c3eeacea748d5cbd78ae..7fcff888713171cb760296726fdcfca19f72aaca 100644 (file)
@@ -1,6 +1,8 @@
 /*
    BlueZ - Bluetooth protocol stack for Linux
+
    Copyright (C) 2010  Nokia Corporation
+   Copyright (C) 2011-2012 Intel Corporation
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License version 2 as
 #include <net/bluetooth/mgmt.h>
 #include <net/bluetooth/smp.h>
 
-#define MGMT_VERSION   0
-#define MGMT_REVISION  1
+bool enable_hs;
+bool enable_le;
+
+#define MGMT_VERSION   1
+#define MGMT_REVISION  0
+
+static const u16 mgmt_commands[] = {
+       MGMT_OP_READ_INDEX_LIST,
+       MGMT_OP_READ_INFO,
+       MGMT_OP_SET_POWERED,
+       MGMT_OP_SET_DISCOVERABLE,
+       MGMT_OP_SET_CONNECTABLE,
+       MGMT_OP_SET_FAST_CONNECTABLE,
+       MGMT_OP_SET_PAIRABLE,
+       MGMT_OP_SET_LINK_SECURITY,
+       MGMT_OP_SET_SSP,
+       MGMT_OP_SET_HS,
+       MGMT_OP_SET_LE,
+       MGMT_OP_SET_DEV_CLASS,
+       MGMT_OP_SET_LOCAL_NAME,
+       MGMT_OP_ADD_UUID,
+       MGMT_OP_REMOVE_UUID,
+       MGMT_OP_LOAD_LINK_KEYS,
+       MGMT_OP_LOAD_LONG_TERM_KEYS,
+       MGMT_OP_DISCONNECT,
+       MGMT_OP_GET_CONNECTIONS,
+       MGMT_OP_PIN_CODE_REPLY,
+       MGMT_OP_PIN_CODE_NEG_REPLY,
+       MGMT_OP_SET_IO_CAPABILITY,
+       MGMT_OP_PAIR_DEVICE,
+       MGMT_OP_CANCEL_PAIR_DEVICE,
+       MGMT_OP_UNPAIR_DEVICE,
+       MGMT_OP_USER_CONFIRM_REPLY,
+       MGMT_OP_USER_CONFIRM_NEG_REPLY,
+       MGMT_OP_USER_PASSKEY_REPLY,
+       MGMT_OP_USER_PASSKEY_NEG_REPLY,
+       MGMT_OP_READ_LOCAL_OOB_DATA,
+       MGMT_OP_ADD_REMOTE_OOB_DATA,
+       MGMT_OP_REMOVE_REMOTE_OOB_DATA,
+       MGMT_OP_START_DISCOVERY,
+       MGMT_OP_STOP_DISCOVERY,
+       MGMT_OP_CONFIRM_NAME,
+       MGMT_OP_BLOCK_DEVICE,
+       MGMT_OP_UNBLOCK_DEVICE,
+};
+
+static const u16 mgmt_events[] = {
+       MGMT_EV_CONTROLLER_ERROR,
+       MGMT_EV_INDEX_ADDED,
+       MGMT_EV_INDEX_REMOVED,
+       MGMT_EV_NEW_SETTINGS,
+       MGMT_EV_CLASS_OF_DEV_CHANGED,
+       MGMT_EV_LOCAL_NAME_CHANGED,
+       MGMT_EV_NEW_LINK_KEY,
+       MGMT_EV_NEW_LONG_TERM_KEY,
+       MGMT_EV_DEVICE_CONNECTED,
+       MGMT_EV_DEVICE_DISCONNECTED,
+       MGMT_EV_CONNECT_FAILED,
+       MGMT_EV_PIN_CODE_REQUEST,
+       MGMT_EV_USER_CONFIRM_REQUEST,
+       MGMT_EV_USER_PASSKEY_REQUEST,
+       MGMT_EV_AUTH_FAILED,
+       MGMT_EV_DEVICE_FOUND,
+       MGMT_EV_DISCOVERING,
+       MGMT_EV_DEVICE_BLOCKED,
+       MGMT_EV_DEVICE_UNBLOCKED,
+       MGMT_EV_DEVICE_UNPAIRED,
+};
+
+/*
+ * These LE scan and inquiry parameters were chosen according to LE General
+ * Discovery Procedure specification.
+ */
+#define LE_SCAN_TYPE                   0x01
+#define LE_SCAN_WIN                    0x12
+#define LE_SCAN_INT                    0x12
+#define LE_SCAN_TIMEOUT_LE_ONLY                10240   /* TGAP(gen_disc_scan_min) */
+#define LE_SCAN_TIMEOUT_BREDR_LE       5120    /* TGAP(100)/2 */
+
+#define INQUIRY_LEN_BREDR              0x08    /* TGAP(100) */
+#define INQUIRY_LEN_BREDR_LE           0x04    /* TGAP(100)/2 */
 
-#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
+#define CACHE_TIMEOUT  msecs_to_jiffies(2 * 1000)
 
-#define SERVICE_CACHE_TIMEOUT (5 * 1000)
+#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
+                               !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
 
 struct pending_cmd {
        struct list_head list;
@@ -151,8 +233,8 @@ static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
        return err;
 }
 
-static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
-                                                               size_t rp_len)
+static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
+                       void *rp, size_t rp_len)
 {
        struct sk_buff *skb;
        struct mgmt_hdr *hdr;
@@ -173,6 +255,7 @@ static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
 
        ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
        put_unaligned_le16(cmd, &ev->opcode);
+       ev->status = status;
 
        if (rp)
                memcpy(ev->data, rp, rp_len);
@@ -181,10 +264,11 @@ static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
        if (err < 0)
                kfree_skb(skb);
 
-       return err;;
+       return err;
 }
 
-static int read_version(struct sock *sk)
+static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
+                       u16 data_len)
 {
        struct mgmt_rp_read_version rp;
 
@@ -193,11 +277,46 @@ static int read_version(struct sock *sk)
        rp.version = MGMT_VERSION;
        put_unaligned_le16(MGMT_REVISION, &rp.revision);
 
-       return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
-                                                               sizeof(rp));
+       return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
+                           sizeof(rp));
+}
+
+static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
+                        u16 data_len)
+{
+       struct mgmt_rp_read_commands *rp;
+       u16 num_commands = ARRAY_SIZE(mgmt_commands);
+       u16 num_events = ARRAY_SIZE(mgmt_events);
+       u16 *opcode;
+       size_t rp_size;
+       int i, err;
+
+       BT_DBG("sock %p", sk);
+
+       rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
+
+       rp = kmalloc(rp_size, GFP_KERNEL);
+       if (!rp)
+               return -ENOMEM;
+
+       put_unaligned_le16(num_commands, &rp->num_commands);
+       put_unaligned_le16(num_events, &rp->num_events);
+
+       for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
+               put_unaligned_le16(mgmt_commands[i], opcode);
+
+       for (i = 0; i < num_events; i++, opcode++)
+               put_unaligned_le16(mgmt_events[i], opcode);
+
+       err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
+                          rp_size);
+       kfree(rp);
+
+       return err;
 }
 
-static int read_index_list(struct sock *sk)
+static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
+                          u16 data_len)
 {
        struct mgmt_rp_read_index_list *rp;
        struct list_head *p;
@@ -226,10 +345,7 @@ static int read_index_list(struct sock *sk)
 
        i = 0;
        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))
+               if (test_bit(HCI_SETUP, &d->dev_flags))
                        continue;
 
                put_unaligned_le16(d->id, &rp->index[i++]);
@@ -238,8 +354,8 @@ static int read_index_list(struct sock *sk)
 
        read_unlock(&hci_dev_list_lock);
 
-       err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
-                                                                       rp_len);
+       err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
+                          rp_len);
 
        kfree(rp);
 
@@ -264,8 +380,13 @@ static u32 get_supported_settings(struct hci_dev *hdev)
                settings |= MGMT_SETTING_LINK_SECURITY;
        }
 
-       if (hdev->features[4] & LMP_LE)
-               settings |= MGMT_SETTING_LE;
+       if (enable_hs)
+               settings |= MGMT_SETTING_HS;
+
+       if (enable_le) {
+               if (hdev->features[4] & LMP_LE)
+                       settings |= MGMT_SETTING_LE;
+       }
 
        return settings;
 }
@@ -274,47 +395,36 @@ static u32 get_current_settings(struct hci_dev *hdev)
 {
        u32 settings = 0;
 
-       if (test_bit(HCI_UP, &hdev->flags))
+       if (hdev_is_powered(hdev))
                settings |= MGMT_SETTING_POWERED;
-       else
-               return settings;
 
-       if (test_bit(HCI_PSCAN, &hdev->flags))
+       if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
                settings |= MGMT_SETTING_CONNECTABLE;
 
-       if (test_bit(HCI_ISCAN, &hdev->flags))
+       if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
                settings |= MGMT_SETTING_DISCOVERABLE;
 
-       if (test_bit(HCI_PAIRABLE, &hdev->flags))
+       if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
                settings |= MGMT_SETTING_PAIRABLE;
 
        if (!(hdev->features[4] & LMP_NO_BREDR))
                settings |= MGMT_SETTING_BREDR;
 
-       if (hdev->host_features[0] & LMP_HOST_LE)
+       if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
                settings |= MGMT_SETTING_LE;
 
-       if (test_bit(HCI_AUTH, &hdev->flags))
+       if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
                settings |= MGMT_SETTING_LINK_SECURITY;
 
-       if (hdev->ssp_mode > 0)
+       if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
                settings |= MGMT_SETTING_SSP;
 
+       if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
+               settings |= MGMT_SETTING_HS;
+
        return settings;
 }
 
-#define EIR_FLAGS              0x01 /* flags */
-#define EIR_UUID16_SOME                0x02 /* 16-bit UUID, more available */
-#define EIR_UUID16_ALL         0x03 /* 16-bit UUID, all listed */
-#define EIR_UUID32_SOME                0x04 /* 32-bit UUID, more available */
-#define EIR_UUID32_ALL         0x05 /* 32-bit UUID, all listed */
-#define EIR_UUID128_SOME       0x06 /* 128-bit UUID, more available */
-#define EIR_UUID128_ALL                0x07 /* 128-bit UUID, all listed */
-#define EIR_NAME_SHORT         0x08 /* shortened local name */
-#define EIR_NAME_COMPLETE      0x09 /* complete local name */
-#define EIR_TX_POWER           0x0A /* transmit power level */
-#define EIR_DEVICE_ID          0x10 /* device ID */
-
 #define PNP_INFO_SVCLASS_ID            0x1200
 
 static u8 bluetooth_base_uuid[] = {
@@ -425,13 +535,16 @@ static int update_eir(struct hci_dev *hdev)
 {
        struct hci_cp_write_eir cp;
 
+       if (!hdev_is_powered(hdev))
+               return 0;
+
        if (!(hdev->features[6] & LMP_EXT_INQ))
                return 0;
 
-       if (hdev->ssp_mode == 0)
+       if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
                return 0;
 
-       if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
+       if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
                return 0;
 
        memset(&cp, 0, sizeof(cp));
@@ -460,10 +573,14 @@ static u8 get_service_classes(struct hci_dev *hdev)
 static int update_class(struct hci_dev *hdev)
 {
        u8 cod[3];
+       int err;
 
        BT_DBG("%s", hdev->name);
 
-       if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
+       if (!hdev_is_powered(hdev))
+               return 0;
+
+       if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
                return 0;
 
        cod[0] = hdev->minor_class;
@@ -473,15 +590,19 @@ static int update_class(struct hci_dev *hdev)
        if (memcmp(cod, hdev->dev_class, 3) == 0)
                return 0;
 
-       return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
+       err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
+       if (err == 0)
+               set_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
+
+       return err;
 }
 
 static void service_cache_off(struct work_struct *work)
 {
        struct hci_dev *hdev = container_of(work, struct hci_dev,
-                                                       service_cache.work);
+                                           service_cache.work);
 
-       if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->flags))
+       if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
                return;
 
        hci_dev_lock(hdev);
@@ -492,36 +613,30 @@ static void service_cache_off(struct work_struct *work)
        hci_dev_unlock(hdev);
 }
 
-static void mgmt_init_hdev(struct hci_dev *hdev)
+static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
 {
-       if (!test_and_set_bit(HCI_MGMT, &hdev->flags))
-               INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
+       if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
+               return;
+
+       INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
 
-       if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->flags))
-               schedule_delayed_work(&hdev->service_cache,
-                               msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
+       /* Non-mgmt controlled devices get this bit set
+        * implicitly so that pairing works for them, however
+        * for mgmt we require user-space to explicitly enable
+        * it
+        */
+       clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
 }
 
-static int read_controller_info(struct sock *sk, u16 index)
+static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
+                               void *data, u16 data_len)
 {
        struct mgmt_rp_read_info rp;
-       struct hci_dev *hdev;
 
-       BT_DBG("sock %p hci%u", sk, index);
-
-       hdev = hci_dev_get(index);
-       if (!hdev)
-               return cmd_status(sk, index, MGMT_OP_READ_INFO,
-                                               MGMT_STATUS_INVALID_PARAMS);
-
-       if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
-               cancel_delayed_work_sync(&hdev->power_off);
+       BT_DBG("sock %p %s", sk, hdev->name);
 
        hci_dev_lock(hdev);
 
-       if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
-               mgmt_init_hdev(hdev);
-
        memset(&rp, 0, sizeof(rp));
 
        bacpy(&rp.bdaddr, &hdev->bdaddr);
@@ -536,11 +651,12 @@ static int read_controller_info(struct sock *sk, u16 index)
        memcpy(rp.dev_class, hdev->dev_class, 3);
 
        memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
+       memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
 
        hci_dev_unlock(hdev);
-       hci_dev_put(hdev);
 
-       return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
+       return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
+                           sizeof(rp));
 }
 
 static void mgmt_pending_free(struct pending_cmd *cmd)
@@ -551,8 +667,8 @@ static void mgmt_pending_free(struct pending_cmd *cmd)
 }
 
 static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
-                                                       struct hci_dev *hdev,
-                                                       void *data, u16 len)
+                                           struct hci_dev *hdev, void *data,
+                                           u16 len)
 {
        struct pending_cmd *cmd;
 
@@ -581,8 +697,8 @@ static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
 }
 
 static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
-                               void (*cb)(struct pending_cmd *cmd, void *data),
-                               void *data)
+                                void (*cb)(struct pending_cmd *cmd, void *data),
+                                void *data)
 {
        struct list_head *p, *n;
 
@@ -620,40 +736,39 @@ static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
 {
        __le32 settings = cpu_to_le32(get_current_settings(hdev));
 
-       return cmd_complete(sk, hdev->id, opcode, &settings, sizeof(settings));
+       return cmd_complete(sk, hdev->id, opcode, 0, &settings,
+                           sizeof(settings));
 }
 
-static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
+static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
+                      u16 len)
 {
-       struct mgmt_mode *cp;
-       struct hci_dev *hdev;
+       struct mgmt_mode *cp = data;
        struct pending_cmd *cmd;
-       int err, up;
-
-       cp = (void *) data;
+       int err;
 
-       BT_DBG("request for hci%u", index);
+       BT_DBG("request for %s", hdev->name);
 
-       if (len != sizeof(*cp))
-               return cmd_status(sk, index, MGMT_OP_SET_POWERED,
-                                               MGMT_STATUS_INVALID_PARAMS);
+       hci_dev_lock(hdev);
 
-       hdev = hci_dev_get(index);
-       if (!hdev)
-               return cmd_status(sk, index, MGMT_OP_SET_POWERED,
-                                               MGMT_STATUS_INVALID_PARAMS);
+       if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
+               cancel_delayed_work(&hdev->power_off);
 
-       hci_dev_lock(hdev);
+               if (cp->val) {
+                       err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
+                       mgmt_powered(hdev, 1);
+                       goto failed;
+               }
+       }
 
-       up = test_bit(HCI_UP, &hdev->flags);
-       if ((cp->val && up) || (!cp->val && !up)) {
+       if (!!cp->val == hdev_is_powered(hdev)) {
                err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
                goto failed;
        }
 
        if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
-               err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
-                                                       MGMT_STATUS_BUSY);
+               err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
+                                MGMT_STATUS_BUSY);
                goto failed;
        }
 
@@ -672,49 +787,115 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
 
 failed:
        hci_dev_unlock(hdev);
-       hci_dev_put(hdev);
        return err;
 }
 
-static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
-                                                                       u16 len)
+static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
+                     struct sock *skip_sk)
 {
-       struct mgmt_cp_set_discoverable *cp;
-       struct hci_dev *hdev;
+       struct sk_buff *skb;
+       struct mgmt_hdr *hdr;
+
+       skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
+       if (!skb)
+               return -ENOMEM;
+
+       hdr = (void *) skb_put(skb, sizeof(*hdr));
+       hdr->opcode = cpu_to_le16(event);
+       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)
+               memcpy(skb_put(skb, data_len), data, data_len);
+
+       /* Time stamp */
+       __net_timestamp(skb);
+
+       hci_send_to_control(skb, skip_sk);
+       kfree_skb(skb);
+
+       return 0;
+}
+
+static int new_settings(struct hci_dev *hdev, struct sock *skip)
+{
+       __le32 ev;
+
+       ev = cpu_to_le32(get_current_settings(hdev));
+
+       return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
+}
+
+static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
+                           u16 len)
+{
+       struct mgmt_cp_set_discoverable *cp = data;
        struct pending_cmd *cmd;
+       u16 timeout;
        u8 scan;
        int err;
 
-       cp = (void *) data;
+       BT_DBG("request for %s", hdev->name);
 
-       BT_DBG("request for hci%u", index);
-
-       if (len != sizeof(*cp))
-               return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
-                                               MGMT_STATUS_INVALID_PARAMS);
-
-       hdev = hci_dev_get(index);
-       if (!hdev)
-               return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
-                                               MGMT_STATUS_INVALID_PARAMS);
+       timeout = get_unaligned_le16(&cp->timeout);
+       if (!cp->val && timeout > 0)
+               return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
+                                 MGMT_STATUS_INVALID_PARAMS);
 
        hci_dev_lock(hdev);
 
-       if (!test_bit(HCI_UP, &hdev->flags)) {
-               err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
-                                               MGMT_STATUS_NOT_POWERED);
+       if (!hdev_is_powered(hdev) && timeout > 0) {
+               err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
+                                MGMT_STATUS_NOT_POWERED);
                goto failed;
        }
 
        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,
-                                                       MGMT_STATUS_BUSY);
+               err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
+                                MGMT_STATUS_BUSY);
+               goto failed;
+       }
+
+       if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
+               err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
+                                MGMT_STATUS_REJECTED);
+               goto failed;
+       }
+
+       if (!hdev_is_powered(hdev)) {
+               bool changed = false;
+
+               if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
+                       change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
+                       changed = true;
+               }
+
+               err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
+               if (err < 0)
+                       goto failed;
+
+               if (changed)
+                       err = new_settings(hdev, sk);
+
                goto failed;
        }
 
-       if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
-                                       test_bit(HCI_PSCAN, &hdev->flags)) {
+       if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
+               if (hdev->discov_timeout > 0) {
+                       cancel_delayed_work(&hdev->discov_off);
+                       hdev->discov_timeout = 0;
+               }
+
+               if (cp->val && timeout > 0) {
+                       hdev->discov_timeout = timeout;
+                       queue_delayed_work(hdev->workqueue, &hdev->discov_off,
+                               msecs_to_jiffies(hdev->discov_timeout * 1000));
+               }
+
                err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
                goto failed;
        }
@@ -737,53 +918,56 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
                mgmt_pending_remove(cmd);
 
        if (cp->val)
-               hdev->discov_timeout = get_unaligned_le16(&cp->timeout);
+               hdev->discov_timeout = timeout;
 
 failed:
        hci_dev_unlock(hdev);
-       hci_dev_put(hdev);
-
        return err;
 }
 
-static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
-                                                                       u16 len)
+static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
+                          u16 len)
 {
-       struct mgmt_mode *cp;
-       struct hci_dev *hdev;
+       struct mgmt_mode *cp = data;
        struct pending_cmd *cmd;
        u8 scan;
        int err;
 
-       cp = (void *) data;
+       BT_DBG("request for %s", hdev->name);
 
-       BT_DBG("request for hci%u", index);
+       hci_dev_lock(hdev);
 
-       if (len != sizeof(*cp))
-               return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
-                                               MGMT_STATUS_INVALID_PARAMS);
+       if (!hdev_is_powered(hdev)) {
+               bool changed = false;
 
-       hdev = hci_dev_get(index);
-       if (!hdev)
-               return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
-                                               MGMT_STATUS_INVALID_PARAMS);
+               if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
+                       changed = true;
 
-       hci_dev_lock(hdev);
+               if (cp->val) {
+                       set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
+               } else {
+                       clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
+                       clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
+               }
+
+               err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
+               if (err < 0)
+                       goto failed;
+
+               if (changed)
+                       err = new_settings(hdev, sk);
 
-       if (!test_bit(HCI_UP, &hdev->flags)) {
-               err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
-                                               MGMT_STATUS_NOT_POWERED);
                goto failed;
        }
 
        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,
-                                                       MGMT_STATUS_BUSY);
+               err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
+                                MGMT_STATUS_BUSY);
                goto failed;
        }
 
-       if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
+       if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
                err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
                goto failed;
        }
@@ -794,233 +978,433 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
                goto failed;
        }
 
-       if (cp->val)
+       if (cp->val) {
                scan = SCAN_PAGE;
-       else
+       } else {
                scan = 0;
 
+               if (test_bit(HCI_ISCAN, &hdev->flags) &&
+                                               hdev->discov_timeout > 0)
+                       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);
 
 failed:
        hci_dev_unlock(hdev);
-       hci_dev_put(hdev);
-
        return err;
 }
 
-static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
-                                       u16 data_len, struct sock *skip_sk)
+static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
+                       u16 len)
 {
-       struct sk_buff *skb;
-       struct mgmt_hdr *hdr;
+       struct mgmt_mode *cp = data;
+       int err;
 
-       skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
-       if (!skb)
-               return -ENOMEM;
+       BT_DBG("request for %s", hdev->name);
 
-       bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
+       hci_dev_lock(hdev);
 
-       hdr = (void *) skb_put(skb, sizeof(*hdr));
-       hdr->opcode = cpu_to_le16(event);
-       if (hdev)
-               hdr->index = cpu_to_le16(hdev->id);
+       if (cp->val)
+               set_bit(HCI_PAIRABLE, &hdev->dev_flags);
        else
-               hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
-       hdr->len = cpu_to_le16(data_len);
+               clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
 
-       if (data)
-               memcpy(skb_put(skb, data_len), data, data_len);
+       err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
+       if (err < 0)
+               goto failed;
 
-       hci_send_to_sock(NULL, skb, skip_sk);
-       kfree_skb(skb);
+       err = new_settings(hdev, sk);
 
-       return 0;
+failed:
+       hci_dev_unlock(hdev);
+       return err;
 }
 
-static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
-                                                                       u16 len)
+static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
+                            u16 len)
 {
-       struct mgmt_mode *cp;
-       struct hci_dev *hdev;
-       __le32 ev;
+       struct mgmt_mode *cp = data;
+       struct pending_cmd *cmd;
+       u8 val;
        int err;
 
-       cp = (void *) data;
+       BT_DBG("request for %s", hdev->name);
 
-       BT_DBG("request for hci%u", index);
+       hci_dev_lock(hdev);
 
-       if (len != sizeof(*cp))
-               return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
-                                               MGMT_STATUS_INVALID_PARAMS);
+       if (!hdev_is_powered(hdev)) {
+               bool changed = false;
 
-       hdev = hci_dev_get(index);
-       if (!hdev)
-               return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
-                                               MGMT_STATUS_INVALID_PARAMS);
+               if (!!cp->val != test_bit(HCI_LINK_SECURITY,
+                                                       &hdev->dev_flags)) {
+                       change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
+                       changed = true;
+               }
 
-       hci_dev_lock(hdev);
+               err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
+               if (err < 0)
+                       goto failed;
 
-       if (cp->val)
-               set_bit(HCI_PAIRABLE, &hdev->flags);
-       else
-               clear_bit(HCI_PAIRABLE, &hdev->flags);
+               if (changed)
+                       err = new_settings(hdev, sk);
 
-       err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
-       if (err < 0)
                goto failed;
+       }
 
-       ev = cpu_to_le32(get_current_settings(hdev));
+       if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
+               err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
+                                MGMT_STATUS_BUSY);
+               goto failed;
+       }
+
+       val = !!cp->val;
+
+       if (test_bit(HCI_AUTH, &hdev->flags) == val) {
+               err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
+               goto failed;
+       }
+
+       cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
+       if (!cmd) {
+               err = -ENOMEM;
+               goto failed;
+       }
 
-       err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), sk);
+       err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
+       if (err < 0) {
+               mgmt_pending_remove(cmd);
+               goto failed;
+       }
 
 failed:
        hci_dev_unlock(hdev);
-       hci_dev_put(hdev);
-
        return err;
 }
 
-static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
+static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
 {
-       struct mgmt_cp_add_uuid *cp;
-       struct hci_dev *hdev;
-       struct bt_uuid *uuid;
+       struct mgmt_mode *cp = data;
+       struct pending_cmd *cmd;
+       u8 val;
        int err;
 
-       cp = (void *) data;
+       BT_DBG("request for %s", hdev->name);
 
-       BT_DBG("request for hci%u", index);
+       hci_dev_lock(hdev);
 
-       if (len != sizeof(*cp))
-               return cmd_status(sk, index, MGMT_OP_ADD_UUID,
-                                               MGMT_STATUS_INVALID_PARAMS);
+       if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
+               err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
+                                MGMT_STATUS_NOT_SUPPORTED);
+               goto failed;
+       }
 
-       hdev = hci_dev_get(index);
-       if (!hdev)
-               return cmd_status(sk, index, MGMT_OP_ADD_UUID,
-                                               MGMT_STATUS_INVALID_PARAMS);
+       val = !!cp->val;
 
-       hci_dev_lock(hdev);
+       if (!hdev_is_powered(hdev)) {
+               bool changed = false;
+
+               if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
+                       change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
+                       changed = true;
+               }
+
+               err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
+               if (err < 0)
+                       goto failed;
+
+               if (changed)
+                       err = new_settings(hdev, sk);
 
-       uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
-       if (!uuid) {
-               err = -ENOMEM;
                goto failed;
        }
 
-       memcpy(uuid->uuid, cp->uuid, 16);
-       uuid->svc_hint = cp->svc_hint;
-
-       list_add(&uuid->list, &hdev->uuids);
+       if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
+            err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
+                             MGMT_STATUS_BUSY);
+               goto failed;
+       }
 
-       err = update_class(hdev);
-       if (err < 0)
+       if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
+               err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
                goto failed;
+       }
 
-       err = update_eir(hdev);
-       if (err < 0)
+       cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
+       if (!cmd) {
+               err = -ENOMEM;
                goto failed;
+       }
 
-       err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
+       err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
+       if (err < 0) {
+               mgmt_pending_remove(cmd);
+               goto failed;
+       }
 
 failed:
        hci_dev_unlock(hdev);
-       hci_dev_put(hdev);
-
        return err;
 }
 
-static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
+static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
 {
-       struct list_head *p, *n;
-       struct mgmt_cp_remove_uuid *cp;
-       struct hci_dev *hdev;
-       u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-       int err, found;
+       struct mgmt_mode *cp = data;
 
-       cp = (void *) data;
+       BT_DBG("request for %s", hdev->name);
 
-       BT_DBG("request for hci%u", index);
+       if (!enable_hs)
+               return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
+                                 MGMT_STATUS_NOT_SUPPORTED);
 
-       if (len != sizeof(*cp))
-               return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
-                                               MGMT_STATUS_INVALID_PARAMS);
+       if (cp->val)
+               set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
+       else
+               clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
+
+       return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
+}
 
-       hdev = hci_dev_get(index);
-       if (!hdev)
-               return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
-                                               MGMT_STATUS_INVALID_PARAMS);
+static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
+{
+       struct mgmt_mode *cp = data;
+       struct hci_cp_write_le_host_supported hci_cp;
+       struct pending_cmd *cmd;
+       int err;
+       u8 val, enabled;
+
+       BT_DBG("request for %s", hdev->name);
 
        hci_dev_lock(hdev);
 
-       if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
-               err = hci_uuids_clear(hdev);
+       if (!enable_le || !(hdev->features[4] & LMP_LE)) {
+               err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
+                                MGMT_STATUS_NOT_SUPPORTED);
                goto unlock;
        }
 
-       found = 0;
+       val = !!cp->val;
+       enabled = !!(hdev->host_features[0] & LMP_HOST_LE);
 
-       list_for_each_safe(p, n, &hdev->uuids) {
-               struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
+       if (!hdev_is_powered(hdev) || val == enabled) {
+               bool changed = false;
 
-               if (memcmp(match->uuid, cp->uuid, 16) != 0)
-                       continue;
+               if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
+                       change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
+                       changed = true;
+               }
 
-               list_del(&match->list);
-               found++;
-       }
+               err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
+               if (err < 0)
+                       goto unlock;
+
+               if (changed)
+                       err = new_settings(hdev, sk);
 
-       if (found == 0) {
-               err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
-                                               MGMT_STATUS_INVALID_PARAMS);
                goto unlock;
        }
 
-       err = update_class(hdev);
-       if (err < 0)
+       if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
+               err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
+                                MGMT_STATUS_BUSY);
                goto unlock;
+       }
 
-       err = update_eir(hdev);
-       if (err < 0)
+       cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
+       if (!cmd) {
+               err = -ENOMEM;
                goto unlock;
+       }
+
+       memset(&hci_cp, 0, sizeof(hci_cp));
+
+       if (val) {
+               hci_cp.le = val;
+               hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
+       }
 
-       err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
+       err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
+                          &hci_cp);
+       if (err < 0) {
+               mgmt_pending_remove(cmd);
+               goto unlock;
+       }
 
 unlock:
        hci_dev_unlock(hdev);
-       hci_dev_put(hdev);
-
        return err;
 }
 
-static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
-                                                                       u16 len)
+static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
 {
-       struct hci_dev *hdev;
-       struct mgmt_cp_set_dev_class *cp;
+       struct mgmt_cp_add_uuid *cp = data;
+       struct pending_cmd *cmd;
+       struct bt_uuid *uuid;
        int err;
 
-       cp = (void *) data;
+       BT_DBG("request for %s", hdev->name);
 
-       BT_DBG("request for hci%u", index);
+       hci_dev_lock(hdev);
 
-       if (len != sizeof(*cp))
-               return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
-                                               MGMT_STATUS_INVALID_PARAMS);
+       if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
+               err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
+                                MGMT_STATUS_BUSY);
+               goto failed;
+       }
+
+       uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
+       if (!uuid) {
+               err = -ENOMEM;
+               goto failed;
+       }
+
+       memcpy(uuid->uuid, cp->uuid, 16);
+       uuid->svc_hint = cp->svc_hint;
+
+       list_add(&uuid->list, &hdev->uuids);
+
+       err = update_class(hdev);
+       if (err < 0)
+               goto failed;
+
+       err = update_eir(hdev);
+       if (err < 0)
+               goto failed;
+
+       if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
+               err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
+                                  hdev->dev_class, 3);
+               goto failed;
+       }
+
+       cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
+       if (!cmd) {
+               err = -ENOMEM;
+               goto failed;
+       }
+
+failed:
+       hci_dev_unlock(hdev);
+       return err;
+}
+
+static bool enable_service_cache(struct hci_dev *hdev)
+{
+       if (!hdev_is_powered(hdev))
+               return false;
+
+       if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
+               schedule_delayed_work(&hdev->service_cache, CACHE_TIMEOUT);
+               return true;
+       }
+
+       return false;
+}
+
+static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
+                                                               u16 len)
+{
+       struct mgmt_cp_remove_uuid *cp = data;
+       struct pending_cmd *cmd;
+       struct list_head *p, *n;
+       u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+       int err, found;
+
+       BT_DBG("request for %s", hdev->name);
+
+       hci_dev_lock(hdev);
+
+       if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
+               err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
+                                MGMT_STATUS_BUSY);
+               goto unlock;
+       }
+
+       if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
+               err = hci_uuids_clear(hdev);
+
+               if (enable_service_cache(hdev)) {
+                       err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
+                                          0, hdev->dev_class, 3);
+                       goto unlock;
+               }
 
-       hdev = hci_dev_get(index);
-       if (!hdev)
-               return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
-                                               MGMT_STATUS_INVALID_PARAMS);
+               goto update_class;
+       }
+
+       found = 0;
+
+       list_for_each_safe(p, n, &hdev->uuids) {
+               struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
+
+               if (memcmp(match->uuid, cp->uuid, 16) != 0)
+                       continue;
+
+               list_del(&match->list);
+               found++;
+       }
+
+       if (found == 0) {
+               err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
+                                MGMT_STATUS_INVALID_PARAMS);
+               goto unlock;
+       }
+
+update_class:
+       err = update_class(hdev);
+       if (err < 0)
+               goto unlock;
+
+       err = update_eir(hdev);
+       if (err < 0)
+               goto unlock;
+
+       if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
+               err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
+                                  hdev->dev_class, 3);
+               goto unlock;
+       }
+
+       cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
+       if (!cmd) {
+               err = -ENOMEM;
+               goto unlock;
+       }
+
+unlock:
+       hci_dev_unlock(hdev);
+       return err;
+}
+
+static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
+                        u16 len)
+{
+       struct mgmt_cp_set_dev_class *cp = data;
+       struct pending_cmd *cmd;
+       int err;
+
+       BT_DBG("request for %s", hdev->name);
 
        hci_dev_lock(hdev);
 
+       if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
+               err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
+                                MGMT_STATUS_BUSY);
+               goto unlock;
+       }
+
        hdev->major_class = cp->major;
        hdev->minor_class = cp->minor;
 
-       if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->flags)) {
+       if (!hdev_is_powered(hdev)) {
+               err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
+                                  hdev->dev_class, 3);
+               goto unlock;
+       }
+
+       if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
                hci_dev_unlock(hdev);
                cancel_delayed_work_sync(&hdev->service_cache);
                hci_dev_lock(hdev);
@@ -1028,30 +1412,33 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
        }
 
        err = update_class(hdev);
+       if (err < 0)
+               goto unlock;
 
-       if (err == 0)
-               err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
+       if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
+               err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
+                                  hdev->dev_class, 3);
+               goto unlock;
+       }
 
-       hci_dev_unlock(hdev);
-       hci_dev_put(hdev);
+       cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
+       if (!cmd) {
+               err = -ENOMEM;
+               goto unlock;
+       }
 
+unlock:
+       hci_dev_unlock(hdev);
        return err;
 }
 
-static int load_link_keys(struct sock *sk, u16 index, unsigned char *data,
+static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
                                                                u16 len)
 {
-       struct hci_dev *hdev;
-       struct mgmt_cp_load_link_keys *cp;
+       struct mgmt_cp_load_link_keys *cp = data;
        u16 key_count, expected_len;
        int i;
 
-       cp = (void *) data;
-
-       if (len < sizeof(*cp))
-               return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
-                                               MGMT_STATUS_INVALID_PARAMS);
-
        key_count = get_unaligned_le16(&cp->key_count);
 
        expected_len = sizeof(*cp) + key_count *
@@ -1059,92 +1446,103 @@ static int load_link_keys(struct sock *sk, u16 index, unsigned char *data,
        if (expected_len != len) {
                BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
                                                        len, expected_len);
-               return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
-                                               MGMT_STATUS_INVALID_PARAMS);
+               return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
+                                 MGMT_STATUS_INVALID_PARAMS);
        }
 
-       hdev = hci_dev_get(index);
-       if (!hdev)
-               return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
-                                               MGMT_STATUS_INVALID_PARAMS);
-
-       BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
+       BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
                                                                key_count);
 
        hci_dev_lock(hdev);
 
        hci_link_keys_clear(hdev);
 
-       set_bit(HCI_LINK_KEYS, &hdev->flags);
+       set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
 
        if (cp->debug_keys)
-               set_bit(HCI_DEBUG_KEYS, &hdev->flags);
+               set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
        else
-               clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
+               clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
 
        for (i = 0; i < key_count; 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);
+               hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
+                                key->type, key->pin_len);
        }
 
-       cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, NULL, 0);
+       cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
 
        hci_dev_unlock(hdev);
-       hci_dev_put(hdev);
 
        return 0;
 }
 
-static int remove_keys(struct sock *sk, u16 index, unsigned char *data,
-                                                               u16 len)
+static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                          u8 addr_type, struct sock *skip_sk)
 {
-       struct hci_dev *hdev;
-       struct mgmt_cp_remove_keys *cp;
-       struct mgmt_rp_remove_keys rp;
+       struct mgmt_ev_device_unpaired ev;
+
+       bacpy(&ev.addr.bdaddr, bdaddr);
+       ev.addr.type = addr_type;
+
+       return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
+                         skip_sk);
+}
+
+static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
+                        u16 len)
+{
+       struct mgmt_cp_unpair_device *cp = data;
+       struct mgmt_rp_unpair_device rp;
        struct hci_cp_disconnect dc;
        struct pending_cmd *cmd;
        struct hci_conn *conn;
        int err;
 
-       cp = (void *) data;
-
-       if (len != sizeof(*cp))
-               return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS,
-                                               MGMT_STATUS_INVALID_PARAMS);
-
-       hdev = hci_dev_get(index);
-       if (!hdev)
-               return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS,
-                                               MGMT_STATUS_INVALID_PARAMS);
-
        hci_dev_lock(hdev);
 
        memset(&rp, 0, sizeof(rp));
-       bacpy(&rp.bdaddr, &cp->bdaddr);
-       rp.status = MGMT_STATUS_FAILED;
+       bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
+       rp.addr.type = cp->addr.type;
 
-       err = hci_remove_link_key(hdev, &cp->bdaddr);
-       if (err < 0) {
-               rp.status = MGMT_STATUS_NOT_PAIRED;
+       if (!hdev_is_powered(hdev)) {
+               err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
+                                  MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
                goto unlock;
        }
 
-       if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
-               err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
-                                                               sizeof(rp));
+       if (cp->addr.type == MGMT_ADDR_BREDR)
+               err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
+       else
+               err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
+
+       if (err < 0) {
+               err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
+                                  MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
                goto unlock;
        }
 
-       conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
+       if (cp->disconnect) {
+               if (cp->addr.type == MGMT_ADDR_BREDR)
+                       conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
+                                                       &cp->addr.bdaddr);
+               else
+                       conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
+                                                       &cp->addr.bdaddr);
+       } else {
+               conn = NULL;
+       }
+
        if (!conn) {
-               err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
-                                                               sizeof(rp));
+               err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
+                                  &rp, sizeof(rp));
+               device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
                goto unlock;
        }
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_KEYS, hdev, cp, sizeof(*cp));
+       cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
+                              sizeof(*cp));
        if (!cmd) {
                err = -ENOMEM;
                goto unlock;
@@ -1157,19 +1555,14 @@ static int remove_keys(struct sock *sk, u16 index, unsigned char *data,
                mgmt_pending_remove(cmd);
 
 unlock:
-       if (err < 0)
-               err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
-                                                               sizeof(rp));
        hci_dev_unlock(hdev);
-       hci_dev_put(hdev);
-
        return err;
 }
 
-static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
+static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
+                     u16 len)
 {
-       struct hci_dev *hdev;
-       struct mgmt_cp_disconnect *cp;
+       struct mgmt_cp_disconnect *cp = data;
        struct hci_cp_disconnect dc;
        struct pending_cmd *cmd;
        struct hci_conn *conn;
@@ -1177,38 +1570,28 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
 
        BT_DBG("");
 
-       cp = (void *) data;
-
-       if (len != sizeof(*cp))
-               return cmd_status(sk, index, MGMT_OP_DISCONNECT,
-                                               MGMT_STATUS_INVALID_PARAMS);
-
-       hdev = hci_dev_get(index);
-       if (!hdev)
-               return cmd_status(sk, index, MGMT_OP_DISCONNECT,
-                                               MGMT_STATUS_INVALID_PARAMS);
-
        hci_dev_lock(hdev);
 
        if (!test_bit(HCI_UP, &hdev->flags)) {
-               err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
-                                               MGMT_STATUS_NOT_POWERED);
+               err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
+                                MGMT_STATUS_NOT_POWERED);
                goto failed;
        }
 
        if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
-               err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
-                                                       MGMT_STATUS_BUSY);
+               err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
+                                MGMT_STATUS_BUSY);
                goto failed;
        }
 
-       conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
-       if (!conn)
-               conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
+       if (cp->addr.type == MGMT_ADDR_BREDR)
+               conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
+       else
+               conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
 
        if (!conn) {
-               err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
-                                               MGMT_STATUS_NOT_CONNECTED);
+               err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
+                                MGMT_STATUS_NOT_CONNECTED);
                goto failed;
        }
 
@@ -1227,8 +1610,6 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
 
 failed:
        hci_dev_unlock(hdev);
-       hci_dev_put(hdev);
-
        return err;
 }
 
@@ -1251,41 +1632,42 @@ static u8 link_to_mgmt(u8 link_type, u8 addr_type)
        }
 }
 
-static int get_connections(struct sock *sk, u16 index)
+static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
+                          u16 data_len)
 {
        struct mgmt_rp_get_connections *rp;
-       struct hci_dev *hdev;
        struct hci_conn *c;
-       struct list_head *p;
        size_t rp_len;
-       u16 count;
-       int i, err;
+       int err;
+       u16 i;
 
        BT_DBG("");
 
-       hdev = hci_dev_get(index);
-       if (!hdev)
-               return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
-                                               MGMT_STATUS_INVALID_PARAMS);
-
        hci_dev_lock(hdev);
 
-       count = 0;
-       list_for_each(p, &hdev->conn_hash.list) {
-               count++;
+       if (!hdev_is_powered(hdev)) {
+               err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
+                                MGMT_STATUS_NOT_POWERED);
+               goto unlock;
+       }
+
+       i = 0;
+       list_for_each_entry(c, &hdev->conn_hash.list, list) {
+               if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
+                       i++;
        }
 
-       rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
+       rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
        rp = kmalloc(rp_len, GFP_ATOMIC);
        if (!rp) {
                err = -ENOMEM;
                goto unlock;
        }
 
-       put_unaligned_le16(count, &rp->conn_count);
-
        i = 0;
        list_for_each_entry(c, &hdev->conn_hash.list, list) {
+               if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
+                       continue;
                bacpy(&rp->addr[i].bdaddr, &c->dst);
                rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
                if (rp->addr[i].type == MGMT_ADDR_INVALID)
@@ -1293,85 +1675,77 @@ static int get_connections(struct sock *sk, u16 index)
                i++;
        }
 
+       put_unaligned_le16(i, &rp->conn_count);
+
        /* 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);
+       err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
+                          rp_len);
 
-unlock:
        kfree(rp);
+
+unlock:
        hci_dev_unlock(hdev);
-       hci_dev_put(hdev);
        return err;
 }
 
-static int send_pin_code_neg_reply(struct sock *sk, u16 index,
-               struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
+static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
+                                  struct mgmt_cp_pin_code_neg_reply *cp)
 {
        struct pending_cmd *cmd;
        int err;
 
        cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
-                                                               sizeof(*cp));
+                              sizeof(*cp));
        if (!cmd)
                return -ENOMEM;
 
-       err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
-                                                               &cp->bdaddr);
+       err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
+                          sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
        if (err < 0)
                mgmt_pending_remove(cmd);
 
        return err;
 }
 
-static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
-                                                                       u16 len)
+static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
+                         u16 len)
 {
-       struct hci_dev *hdev;
        struct hci_conn *conn;
-       struct mgmt_cp_pin_code_reply *cp;
-       struct mgmt_cp_pin_code_neg_reply ncp;
+       struct mgmt_cp_pin_code_reply *cp = data;
        struct hci_cp_pin_code_reply reply;
        struct pending_cmd *cmd;
        int err;
 
        BT_DBG("");
 
-       cp = (void *) data;
-
-       if (len != sizeof(*cp))
-               return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
-                                               MGMT_STATUS_INVALID_PARAMS);
-
-       hdev = hci_dev_get(index);
-       if (!hdev)
-               return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
-                                               MGMT_STATUS_INVALID_PARAMS);
-
        hci_dev_lock(hdev);
 
-       if (!test_bit(HCI_UP, &hdev->flags)) {
-               err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
-                                               MGMT_STATUS_NOT_POWERED);
+       if (!hdev_is_powered(hdev)) {
+               err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
+                                MGMT_STATUS_NOT_POWERED);
                goto failed;
        }
 
-       conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
+       conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
        if (!conn) {
-               err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
-                                               MGMT_STATUS_NOT_CONNECTED);
+               err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
+                                MGMT_STATUS_NOT_CONNECTED);
                goto failed;
        }
 
        if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
-               bacpy(&ncp.bdaddr, &cp->bdaddr);
+               struct mgmt_cp_pin_code_neg_reply ncp;
+
+               memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
 
                BT_ERR("PIN code is not 16 bytes long");
 
-               err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
+               err = send_pin_code_neg_reply(sk, hdev, &ncp);
                if (err >= 0)
-                       err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
-                                               MGMT_STATUS_INVALID_PARAMS);
+                       err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
+                                        MGMT_STATUS_INVALID_PARAMS);
 
                goto failed;
        }
@@ -1382,7 +1756,7 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
                goto failed;
        }
 
-       bacpy(&reply.bdaddr, &cp->bdaddr);
+       bacpy(&reply.bdaddr, &cp->addr.bdaddr);
        reply.pin_len = cp->pin_len;
        memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
 
@@ -1392,67 +1766,39 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
 
 failed:
        hci_dev_unlock(hdev);
-       hci_dev_put(hdev);
-
        return err;
 }
 
-static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
-                                                                       u16 len)
+static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
+                             void *data, u16 len)
 {
-       struct hci_dev *hdev;
-       struct mgmt_cp_pin_code_neg_reply *cp;
+       struct mgmt_cp_pin_code_neg_reply *cp = data;
        int err;
 
        BT_DBG("");
 
-       cp = (void *) data;
-
-       if (len != sizeof(*cp))
-               return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
-                                               MGMT_STATUS_INVALID_PARAMS);
-
-       hdev = hci_dev_get(index);
-       if (!hdev)
-               return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
-                                               MGMT_STATUS_INVALID_PARAMS);
-
        hci_dev_lock(hdev);
 
-       if (!test_bit(HCI_UP, &hdev->flags)) {
-               err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
-                                               MGMT_STATUS_NOT_POWERED);
+       if (!hdev_is_powered(hdev)) {
+               err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
+                                MGMT_STATUS_NOT_POWERED);
                goto failed;
        }
 
-       err = send_pin_code_neg_reply(sk, index, hdev, cp);
+       err = send_pin_code_neg_reply(sk, hdev, cp);
 
 failed:
        hci_dev_unlock(hdev);
-       hci_dev_put(hdev);
-
        return err;
 }
 
-static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
-                                                                       u16 len)
+static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
+                            u16 len)
 {
-       struct hci_dev *hdev;
-       struct mgmt_cp_set_io_capability *cp;
+       struct mgmt_cp_set_io_capability *cp = data;
 
        BT_DBG("");
 
-       cp = (void *) data;
-
-       if (len != sizeof(*cp))
-               return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
-                                               MGMT_STATUS_INVALID_PARAMS);
-
-       hdev = hci_dev_get(index);
-       if (!hdev)
-               return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
-                                               MGMT_STATUS_INVALID_PARAMS);
-
        hci_dev_lock(hdev);
 
        hdev->io_capability = cp->io_capability;
@@ -1461,9 +1807,9 @@ static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
                                                        hdev->io_capability);
 
        hci_dev_unlock(hdev);
-       hci_dev_put(hdev);
 
-       return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
+       return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
+                           0);
 }
 
 static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
@@ -1491,9 +1837,9 @@ static void pairing_complete(struct pending_cmd *cmd, u8 status)
 
        bacpy(&rp.addr.bdaddr, &conn->dst);
        rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
-       rp.status = status;
 
-       cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
+       cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
+                    &rp, sizeof(rp));
 
        /* So we don't get further callbacks for this connection */
        conn->connect_cfm_cb = NULL;
@@ -1515,13 +1861,13 @@ static void pairing_complete_cb(struct hci_conn *conn, u8 status)
        if (!cmd)
                BT_DBG("Unable to find a pending command");
        else
-               pairing_complete(cmd, status);
+               pairing_complete(cmd, mgmt_status(status));
 }
 
-static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
+static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
+                      u16 len)
 {
-       struct hci_dev *hdev;
-       struct mgmt_cp_pair_device *cp;
+       struct mgmt_cp_pair_device *cp = data;
        struct mgmt_rp_pair_device rp;
        struct pending_cmd *cmd;
        u8 sec_level, auth_type;
@@ -1530,19 +1876,14 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
 
        BT_DBG("");
 
-       cp = (void *) data;
-
-       if (len != sizeof(*cp))
-               return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
-                                               MGMT_STATUS_INVALID_PARAMS);
-
-       hdev = hci_dev_get(index);
-       if (!hdev)
-               return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
-                                               MGMT_STATUS_INVALID_PARAMS);
-
        hci_dev_lock(hdev);
 
+       if (!hdev_is_powered(hdev)) {
+               err = cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
+                                MGMT_STATUS_NOT_POWERED);
+               goto unlock;
+       }
+
        sec_level = BT_SECURITY_MEDIUM;
        if (cp->io_cap == 0x03)
                auth_type = HCI_AT_DEDICATED_BONDING;
@@ -1551,27 +1892,26 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
 
        if (cp->addr.type == MGMT_ADDR_BREDR)
                conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
-                                                               auth_type);
+                                  auth_type);
        else
                conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
-                                                               auth_type);
+                                  auth_type);
 
        memset(&rp, 0, sizeof(rp));
        bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
        rp.addr.type = cp->addr.type;
 
        if (IS_ERR(conn)) {
-               rp.status = -PTR_ERR(conn);
-               err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
-                                                       &rp, sizeof(rp));
+               err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
+                                  MGMT_STATUS_CONNECT_FAILED, &rp,
+                                  sizeof(rp));
                goto unlock;
        }
 
        if (conn->connect_cfm_cb) {
                hci_conn_put(conn);
-               rp.status = EBUSY;
-               err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
-                                                       &rp, sizeof(rp));
+               err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
+                                  MGMT_STATUS_BUSY, &rp, sizeof(rp));
                goto unlock;
        }
 
@@ -1599,58 +1939,88 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
 
 unlock:
        hci_dev_unlock(hdev);
-       hci_dev_put(hdev);
-
        return err;
 }
 
-static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
-                                       u16 mgmt_op, u16 hci_op, __le32 passkey)
+static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
+                             u16 len)
 {
+       struct mgmt_addr_info *addr = data;
        struct pending_cmd *cmd;
-       struct hci_dev *hdev;
        struct hci_conn *conn;
        int err;
 
-       hdev = hci_dev_get(index);
-       if (!hdev)
-               return cmd_status(sk, index, mgmt_op,
-                                               MGMT_STATUS_INVALID_PARAMS);
+       BT_DBG("");
 
        hci_dev_lock(hdev);
 
-       if (!test_bit(HCI_UP, &hdev->flags)) {
-               err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
+       if (!hdev_is_powered(hdev)) {
+               err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
+                                MGMT_STATUS_NOT_POWERED);
+               goto unlock;
+       }
+
+       cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
+       if (!cmd) {
+               err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
+                                MGMT_STATUS_INVALID_PARAMS);
+               goto unlock;
+       }
+
+       conn = cmd->user_data;
+
+       if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
+               err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
+                                MGMT_STATUS_INVALID_PARAMS);
+               goto unlock;
+       }
+
+       pairing_complete(cmd, MGMT_STATUS_CANCELLED);
+
+       err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
+                          addr, sizeof(*addr));
+unlock:
+       hci_dev_unlock(hdev);
+       return err;
+}
+
+static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
+                            bdaddr_t *bdaddr, u8 type, u16 mgmt_op,
+                            u16 hci_op, __le32 passkey)
+{
+       struct pending_cmd *cmd;
+       struct hci_conn *conn;
+       int err;
+
+       hci_dev_lock(hdev);
+
+       if (!hdev_is_powered(hdev)) {
+               err = cmd_status(sk, hdev->id, mgmt_op,
+                                MGMT_STATUS_NOT_POWERED);
                goto done;
        }
 
-       /*
-        * Check for an existing ACL link, if present pair via
-        * HCI commands.
-        *
-        * If no ACL link is present, check for an LE link and if
-        * present, pair via the SMP engine.
-        *
-        * If neither ACL nor LE links are present, fail with error.
-        */
-       conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
-       if (!conn) {
+       if (type == MGMT_ADDR_BREDR)
+               conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
+       else
                conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
-               if (!conn) {
-                       err = cmd_status(sk, index, mgmt_op,
-                                               MGMT_STATUS_NOT_CONNECTED);
-                       goto done;
-               }
 
+       if (!conn) {
+               err = cmd_status(sk, hdev->id, mgmt_op,
+                                MGMT_STATUS_NOT_CONNECTED);
+               goto done;
+       }
+
+       if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
                /* Continue with pairing via SMP */
                err = smp_user_confirm_reply(conn, mgmt_op, passkey);
 
                if (!err)
-                       err = cmd_status(sk, index, mgmt_op,
-                                                       MGMT_STATUS_SUCCESS);
+                       err = cmd_status(sk, hdev->id, mgmt_op,
+                                        MGMT_STATUS_SUCCESS);
                else
-                       err = cmd_status(sk, index, mgmt_op,
-                                                       MGMT_STATUS_FAILED);
+                       err = cmd_status(sk, hdev->id, mgmt_op,
+                                        MGMT_STATUS_FAILED);
 
                goto done;
        }
@@ -1676,94 +2046,96 @@ static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
 
 done:
        hci_dev_unlock(hdev);
-       hci_dev_put(hdev);
-
        return err;
 }
 
-static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
+static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
+                             u16 len)
 {
-       struct mgmt_cp_user_confirm_reply *cp = (void *) data;
+       struct mgmt_cp_user_confirm_reply *cp = data;
 
        BT_DBG("");
 
        if (len != sizeof(*cp))
-               return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
-                                               MGMT_STATUS_INVALID_PARAMS);
+               return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
+                                 MGMT_STATUS_INVALID_PARAMS);
 
-       return user_pairing_resp(sk, index, &cp->bdaddr,
-                       MGMT_OP_USER_CONFIRM_REPLY,
-                       HCI_OP_USER_CONFIRM_REPLY, 0);
+       return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
+                                MGMT_OP_USER_CONFIRM_REPLY,
+                                HCI_OP_USER_CONFIRM_REPLY, 0);
 }
 
-static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
-                                                                       u16 len)
+static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
+                                 void *data, u16 len)
 {
        struct mgmt_cp_user_confirm_neg_reply *cp = data;
 
        BT_DBG("");
 
-       if (len != sizeof(*cp))
-               return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
-                                               MGMT_STATUS_INVALID_PARAMS);
-
-       return user_pairing_resp(sk, index, &cp->bdaddr,
-                       MGMT_OP_USER_CONFIRM_NEG_REPLY,
-                       HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
+       return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
+                                MGMT_OP_USER_CONFIRM_NEG_REPLY,
+                                HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
 }
 
-static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
+static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
+                             u16 len)
 {
-       struct mgmt_cp_user_passkey_reply *cp = (void *) data;
+       struct mgmt_cp_user_passkey_reply *cp = data;
 
        BT_DBG("");
 
-       if (len != sizeof(*cp))
-               return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
-                                                                       EINVAL);
-
-       return user_pairing_resp(sk, index, &cp->bdaddr,
-                       MGMT_OP_USER_PASSKEY_REPLY,
-                       HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
+       return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
+                                MGMT_OP_USER_PASSKEY_REPLY,
+                                HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
 }
 
-static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
-                                                                       u16 len)
+static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
+                                 void *data, u16 len)
 {
-       struct mgmt_cp_user_passkey_neg_reply *cp = (void *) data;
+       struct mgmt_cp_user_passkey_neg_reply *cp = data;
 
        BT_DBG("");
 
-       if (len != sizeof(*cp))
-               return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
-                                                                       EINVAL);
-
-       return user_pairing_resp(sk, index, &cp->bdaddr,
-                       MGMT_OP_USER_PASSKEY_NEG_REPLY,
-                       HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
+       return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
+                                MGMT_OP_USER_PASSKEY_NEG_REPLY,
+                                HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
 }
 
-static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
-                                                               u16 len)
+static int update_name(struct hci_dev *hdev, const char *name)
 {
-       struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
-       struct hci_cp_write_local_name hci_cp;
-       struct hci_dev *hdev;
+       struct hci_cp_write_local_name cp;
+
+       memcpy(cp.name, name, sizeof(cp.name));
+
+       return hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
+}
+
+static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
+                         u16 len)
+{
+       struct mgmt_cp_set_local_name *cp = data;
        struct pending_cmd *cmd;
        int err;
 
        BT_DBG("");
 
-       if (len != sizeof(*mgmt_cp))
-               return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
-                                               MGMT_STATUS_INVALID_PARAMS);
+       hci_dev_lock(hdev);
 
-       hdev = hci_dev_get(index);
-       if (!hdev)
-               return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
-                                               MGMT_STATUS_INVALID_PARAMS);
+       memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
 
-       hci_dev_lock(hdev);
+       if (!hdev_is_powered(hdev)) {
+               memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
+
+               err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
+                                  data, len);
+               if (err < 0)
+                       goto failed;
+
+               err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
+                                sk);
+
+               goto failed;
+       }
 
        cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
        if (!cmd) {
@@ -1771,49 +2143,40 @@ static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
                goto failed;
        }
 
-       memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
-       err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
-                                                               &hci_cp);
+       err = update_name(hdev, cp->name);
        if (err < 0)
                mgmt_pending_remove(cmd);
 
 failed:
        hci_dev_unlock(hdev);
-       hci_dev_put(hdev);
-
        return err;
 }
 
-static int read_local_oob_data(struct sock *sk, u16 index)
+static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
+                              void *data, u16 data_len)
 {
-       struct hci_dev *hdev;
        struct pending_cmd *cmd;
        int err;
 
-       BT_DBG("hci%u", index);
-
-       hdev = hci_dev_get(index);
-       if (!hdev)
-               return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
-                                               MGMT_STATUS_INVALID_PARAMS);
+       BT_DBG("%s", hdev->name);
 
        hci_dev_lock(hdev);
 
-       if (!test_bit(HCI_UP, &hdev->flags)) {
-               err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
-                                               MGMT_STATUS_NOT_POWERED);
+       if (!hdev_is_powered(hdev)) {
+               err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
+                                MGMT_STATUS_NOT_POWERED);
                goto unlock;
        }
 
        if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
-               err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
-                                               MGMT_STATUS_NOT_SUPPORTED);
+               err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
+                                MGMT_STATUS_NOT_SUPPORTED);
                goto unlock;
        }
 
        if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
-               err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
-                                                       MGMT_STATUS_BUSY);
+               err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
+                                MGMT_STATUS_BUSY);
                goto unlock;
        }
 
@@ -1829,104 +2192,112 @@ static int read_local_oob_data(struct sock *sk, u16 index)
 
 unlock:
        hci_dev_unlock(hdev);
-       hci_dev_put(hdev);
-
        return err;
 }
 
-static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
-                                                                       u16 len)
+static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
+                              void *data, u16 len)
 {
-       struct hci_dev *hdev;
-       struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
+       struct mgmt_cp_add_remote_oob_data *cp = data;
+       u8 status;
        int err;
 
-       BT_DBG("hci%u ", index);
-
-       if (len != sizeof(*cp))
-               return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
-                                               MGMT_STATUS_INVALID_PARAMS);
-
-       hdev = hci_dev_get(index);
-       if (!hdev)
-               return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
-                                               MGMT_STATUS_INVALID_PARAMS);
+       BT_DBG("%s ", hdev->name);
 
        hci_dev_lock(hdev);
 
-       err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
-                                                               cp->randomizer);
+       if (!hdev_is_powered(hdev)) {
+               err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
+                                  MGMT_STATUS_NOT_POWERED, &cp->addr,
+                                  sizeof(cp->addr));
+               goto unlock;
+       }
+
+       err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
+                                     cp->randomizer);
        if (err < 0)
-               err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
-                                                       MGMT_STATUS_FAILED);
+               status = MGMT_STATUS_FAILED;
        else
-               err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
-                                                                       0);
+               status = 0;
 
-       hci_dev_unlock(hdev);
-       hci_dev_put(hdev);
+       err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
+                          &cp->addr, sizeof(cp->addr));
 
+unlock:
+       hci_dev_unlock(hdev);
        return err;
 }
 
-static int remove_remote_oob_data(struct sock *sk, u16 index,
-                                               unsigned char *data, u16 len)
+static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
+                                               void *data, u16 len)
 {
-       struct hci_dev *hdev;
-       struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
+       struct mgmt_cp_remove_remote_oob_data *cp = data;
+       u8 status;
        int err;
 
-       BT_DBG("hci%u ", index);
+       BT_DBG("%s", hdev->name);
 
-       if (len != sizeof(*cp))
-               return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
-                                               MGMT_STATUS_INVALID_PARAMS);
+       hci_dev_lock(hdev);
+
+       if (!hdev_is_powered(hdev)) {
+               err = cmd_complete(sk, hdev->id,
+                                  MGMT_OP_REMOVE_REMOTE_OOB_DATA,
+                                  MGMT_STATUS_NOT_POWERED, &cp->addr,
+                                  sizeof(cp->addr));
+               goto unlock;
+       }
+
+       err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
+       if (err < 0)
+               status = MGMT_STATUS_INVALID_PARAMS;
+       else
+               status = 0;
+
+       err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
+                          status, &cp->addr, sizeof(cp->addr));
 
-       hdev = hci_dev_get(index);
-       if (!hdev)
-               return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
-                                               MGMT_STATUS_INVALID_PARAMS);
+unlock:
+       hci_dev_unlock(hdev);
+       return err;
+}
+
+int mgmt_interleaved_discovery(struct hci_dev *hdev)
+{
+       int err;
+
+       BT_DBG("%s", hdev->name);
 
        hci_dev_lock(hdev);
 
-       err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
+       err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
        if (err < 0)
-               err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
-                                               MGMT_STATUS_INVALID_PARAMS);
-       else
-               err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
-                                                               NULL, 0);
+               hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
 
        hci_dev_unlock(hdev);
-       hci_dev_put(hdev);
 
        return err;
 }
 
-static int start_discovery(struct sock *sk, u16 index,
-                                               unsigned char *data, u16 len)
+static int start_discovery(struct sock *sk, struct hci_dev *hdev,
+                          void *data, u16 len)
 {
-       struct mgmt_cp_start_discovery *cp = (void *) data;
+       struct mgmt_cp_start_discovery *cp = data;
        struct pending_cmd *cmd;
-       struct hci_dev *hdev;
        int err;
 
-       BT_DBG("hci%u", index);
-
-       if (len != sizeof(*cp))
-               return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
-                                               MGMT_STATUS_INVALID_PARAMS);
-
-       hdev = hci_dev_get(index);
-       if (!hdev)
-               return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
-                                               MGMT_STATUS_INVALID_PARAMS);
+       BT_DBG("%s", hdev->name);
 
        hci_dev_lock(hdev);
 
-       if (!test_bit(HCI_UP, &hdev->flags)) {
-               err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
-                                               MGMT_STATUS_NOT_POWERED);
+       if (!hdev_is_powered(hdev)) {
+               err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
+                                MGMT_STATUS_NOT_POWERED);
+               goto failed;
+       }
+
+       if (hdev->discovery.state != DISCOVERY_STOPPED) {
+               err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
+                                MGMT_STATUS_BUSY);
                goto failed;
        }
 
@@ -1936,137 +2307,217 @@ static int start_discovery(struct sock *sk, u16 index,
                goto failed;
        }
 
-       err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
+       hdev->discovery.type = cp->type;
+
+       switch (hdev->discovery.type) {
+       case DISCOV_TYPE_BREDR:
+               if (lmp_bredr_capable(hdev))
+                       err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
+               else
+                       err = -ENOTSUPP;
+               break;
+
+       case DISCOV_TYPE_LE:
+               if (lmp_host_le_capable(hdev))
+                       err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
+                                         LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
+               else
+                       err = -ENOTSUPP;
+               break;
+
+       case DISCOV_TYPE_INTERLEAVED:
+               if (lmp_host_le_capable(hdev) && lmp_bredr_capable(hdev))
+                       err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
+                                         LE_SCAN_WIN,
+                                         LE_SCAN_TIMEOUT_BREDR_LE);
+               else
+                       err = -ENOTSUPP;
+               break;
+
+       default:
+               err = -EINVAL;
+       }
+
        if (err < 0)
                mgmt_pending_remove(cmd);
+       else
+               hci_discovery_set_state(hdev, DISCOVERY_STARTING);
 
 failed:
        hci_dev_unlock(hdev);
-       hci_dev_put(hdev);
-
        return err;
 }
 
-static int stop_discovery(struct sock *sk, u16 index)
+static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
+                         u16 len)
 {
-       struct hci_dev *hdev;
+       struct mgmt_cp_stop_discovery *mgmt_cp = data;
        struct pending_cmd *cmd;
+       struct hci_cp_remote_name_req_cancel cp;
+       struct inquiry_entry *e;
        int err;
 
-       BT_DBG("hci%u", index);
-
-       hdev = hci_dev_get(index);
-       if (!hdev)
-               return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
-                                               MGMT_STATUS_INVALID_PARAMS);
+       BT_DBG("%s", hdev->name);
 
        hci_dev_lock(hdev);
 
+       if (!hci_discovery_active(hdev)) {
+               err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
+                                  MGMT_STATUS_REJECTED, &mgmt_cp->type,
+                                  sizeof(mgmt_cp->type));
+               goto unlock;
+       }
+
+       if (hdev->discovery.type != mgmt_cp->type) {
+               err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
+                                  MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
+                                  sizeof(mgmt_cp->type));
+               goto unlock;
+       }
+
        cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
        if (!cmd) {
                err = -ENOMEM;
-               goto failed;
+               goto unlock;
        }
 
-       err = hci_cancel_inquiry(hdev);
+       if (hdev->discovery.state == DISCOVERY_FINDING) {
+               err = hci_cancel_inquiry(hdev);
+               if (err < 0)
+                       mgmt_pending_remove(cmd);
+               else
+                       hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
+               goto unlock;
+       }
+
+       e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
+       if (!e) {
+               mgmt_pending_remove(cmd);
+               err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, 0,
+                                  &mgmt_cp->type, sizeof(mgmt_cp->type));
+               hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+               goto unlock;
+       }
+
+       bacpy(&cp.bdaddr, &e->data.bdaddr);
+       err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
+                          &cp);
        if (err < 0)
                mgmt_pending_remove(cmd);
+       else
+               hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
 
-failed:
+unlock:
        hci_dev_unlock(hdev);
-       hci_dev_put(hdev);
-
        return err;
 }
 
-static int block_device(struct sock *sk, u16 index, unsigned char *data,
-                                                               u16 len)
+static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
+                       u16 len)
 {
-       struct hci_dev *hdev;
-       struct mgmt_cp_block_device *cp = (void *) data;
+       struct mgmt_cp_confirm_name *cp = data;
+       struct inquiry_entry *e;
        int err;
 
-       BT_DBG("hci%u", index);
+       BT_DBG("%s", hdev->name);
 
-       if (len != sizeof(*cp))
-               return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
-                                               MGMT_STATUS_INVALID_PARAMS);
+       hci_dev_lock(hdev);
 
-       hdev = hci_dev_get(index);
-       if (!hdev)
-               return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
-                                               MGMT_STATUS_INVALID_PARAMS);
+       if (!hci_discovery_active(hdev)) {
+               err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
+                                MGMT_STATUS_FAILED);
+               goto failed;
+       }
+
+       e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
+       if (!e) {
+               err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
+                                MGMT_STATUS_INVALID_PARAMS);
+               goto failed;
+       }
+
+       if (cp->name_known) {
+               e->name_state = NAME_KNOWN;
+               list_del(&e->list);
+       } else {
+               e->name_state = NAME_NEEDED;
+               hci_inquiry_cache_update_resolve(hdev, e);
+       }
+
+       err = 0;
+
+failed:
+       hci_dev_unlock(hdev);
+       return err;
+}
+
+static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
+                       u16 len)
+{
+       struct mgmt_cp_block_device *cp = data;
+       u8 status;
+       int err;
+
+       BT_DBG("%s", hdev->name);
 
        hci_dev_lock(hdev);
 
-       err = hci_blacklist_add(hdev, &cp->bdaddr);
+       err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
        if (err < 0)
-               err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
-                                                       MGMT_STATUS_FAILED);
+               status = MGMT_STATUS_FAILED;
        else
-               err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
-                                                       NULL, 0);
+               status = 0;
+
+       err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
+                          &cp->addr, sizeof(cp->addr));
 
        hci_dev_unlock(hdev);
-       hci_dev_put(hdev);
 
        return err;
 }
 
-static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
-                                                               u16 len)
+static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
+                         u16 len)
 {
-       struct hci_dev *hdev;
-       struct mgmt_cp_unblock_device *cp = (void *) data;
+       struct mgmt_cp_unblock_device *cp = data;
+       u8 status;
        int err;
 
-       BT_DBG("hci%u", index);
-
-       if (len != sizeof(*cp))
-               return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
-                                               MGMT_STATUS_INVALID_PARAMS);
-
-       hdev = hci_dev_get(index);
-       if (!hdev)
-               return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
-                                               MGMT_STATUS_INVALID_PARAMS);
+       BT_DBG("%s", hdev->name);
 
        hci_dev_lock(hdev);
 
-       err = hci_blacklist_del(hdev, &cp->bdaddr);
-
+       err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
        if (err < 0)
-               err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
-                                               MGMT_STATUS_INVALID_PARAMS);
+               status = MGMT_STATUS_INVALID_PARAMS;
        else
-               err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
-                                                               NULL, 0);
+               status = 0;
+
+       err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
+                          &cp->addr, sizeof(cp->addr));
 
        hci_dev_unlock(hdev);
-       hci_dev_put(hdev);
 
        return err;
 }
 
-static int set_fast_connectable(struct sock *sk, u16 index,
-                                       unsigned char *data, u16 len)
+static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
+                               void *data, u16 len)
 {
-       struct hci_dev *hdev;
-       struct mgmt_mode *cp = (void *) data;
+       struct mgmt_mode *cp = data;
        struct hci_cp_write_page_scan_activity acp;
        u8 type;
        int err;
 
-       BT_DBG("hci%u", index);
+       BT_DBG("%s", hdev->name);
 
-       if (len != sizeof(*cp))
-               return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
-                                               MGMT_STATUS_INVALID_PARAMS);
+       if (!hdev_is_powered(hdev))
+               return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
+                                 MGMT_STATUS_NOT_POWERED);
 
-       hdev = hci_dev_get(index);
-       if (!hdev)
-               return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
-                                               MGMT_STATUS_INVALID_PARAMS);
+       if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
+               return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
+                                 MGMT_STATUS_REJECTED);
 
        hci_dev_lock(hdev);
 
@@ -2080,35 +2531,128 @@ static int set_fast_connectable(struct sock *sk, u16 index,
 
        acp.window = 0x0012;    /* default 11.25 msec page scan window */
 
-       err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
-                                               sizeof(acp), &acp);
+       err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, sizeof(acp),
+                          &acp);
        if (err < 0) {
-               err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
-                                                       MGMT_STATUS_FAILED);
+               err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
+                                MGMT_STATUS_FAILED);
                goto done;
        }
 
        err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
        if (err < 0) {
-               err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
-                                                       MGMT_STATUS_FAILED);
+               err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
+                                MGMT_STATUS_FAILED);
                goto done;
        }
 
-       err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
-                                                       NULL, 0);
+       err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0,
+                          NULL, 0);
 done:
        hci_dev_unlock(hdev);
-       hci_dev_put(hdev);
-
        return err;
 }
 
+static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
+                              void *cp_data, u16 len)
+{
+       struct mgmt_cp_load_long_term_keys *cp = cp_data;
+       u16 key_count, expected_len;
+       int i;
+
+       key_count = get_unaligned_le16(&cp->key_count);
+
+       expected_len = sizeof(*cp) + key_count *
+                                       sizeof(struct mgmt_ltk_info);
+       if (expected_len != len) {
+               BT_ERR("load_keys: expected %u bytes, got %u bytes",
+                                                       len, expected_len);
+               return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
+                                 EINVAL);
+       }
+
+       BT_DBG("%s key_count %u", hdev->name, key_count);
+
+       hci_dev_lock(hdev);
+
+       hci_smp_ltks_clear(hdev);
+
+       for (i = 0; i < key_count; i++) {
+               struct mgmt_ltk_info *key = &cp->keys[i];
+               u8 type;
+
+               if (key->master)
+                       type = HCI_SMP_LTK;
+               else
+                       type = HCI_SMP_LTK_SLAVE;
+
+               hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
+                           type, 0, key->authenticated, key->val,
+                           key->enc_size, key->ediv, key->rand);
+       }
+
+       hci_dev_unlock(hdev);
+
+       return 0;
+}
+
+struct mgmt_handler {
+       int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
+                    u16 data_len);
+       bool var_len;
+       size_t data_len;
+} mgmt_handlers[] = {
+       { NULL }, /* 0x0000 (no command) */
+       { read_version,           false, MGMT_READ_VERSION_SIZE },
+       { read_commands,          false, MGMT_READ_COMMANDS_SIZE },
+       { read_index_list,        false, MGMT_READ_INDEX_LIST_SIZE },
+       { read_controller_info,   false, MGMT_READ_INFO_SIZE },
+       { set_powered,            false, MGMT_SETTING_SIZE },
+       { set_discoverable,       false, MGMT_SET_DISCOVERABLE_SIZE },
+       { set_connectable,        false, MGMT_SETTING_SIZE },
+       { set_fast_connectable,   false, MGMT_SETTING_SIZE },
+       { set_pairable,           false, MGMT_SETTING_SIZE },
+       { set_link_security,      false, MGMT_SETTING_SIZE },
+       { set_ssp,                false, MGMT_SETTING_SIZE },
+       { set_hs,                 false, MGMT_SETTING_SIZE },
+       { set_le,                 false, MGMT_SETTING_SIZE },
+       { set_dev_class,          false, MGMT_SET_DEV_CLASS_SIZE },
+       { set_local_name,         false, MGMT_SET_LOCAL_NAME_SIZE },
+       { add_uuid,               false, MGMT_ADD_UUID_SIZE },
+       { remove_uuid,            false, MGMT_REMOVE_UUID_SIZE },
+       { load_link_keys,         true,  MGMT_LOAD_LINK_KEYS_SIZE },
+       { load_long_term_keys,    true,  MGMT_LOAD_LONG_TERM_KEYS_SIZE },
+       { disconnect,             false, MGMT_DISCONNECT_SIZE },
+       { get_connections,        false, MGMT_GET_CONNECTIONS_SIZE },
+       { pin_code_reply,         false, MGMT_PIN_CODE_REPLY_SIZE },
+       { pin_code_neg_reply,     false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
+       { set_io_capability,      false, MGMT_SET_IO_CAPABILITY_SIZE },
+       { pair_device,            false, MGMT_PAIR_DEVICE_SIZE },
+       { cancel_pair_device,     false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
+       { unpair_device,          false, MGMT_UNPAIR_DEVICE_SIZE },
+       { user_confirm_reply,     false, MGMT_USER_CONFIRM_REPLY_SIZE },
+       { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
+       { user_passkey_reply,     false, MGMT_USER_PASSKEY_REPLY_SIZE },
+       { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
+       { read_local_oob_data,    false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
+       { add_remote_oob_data,    false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
+       { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
+       { start_discovery,        false, MGMT_START_DISCOVERY_SIZE },
+       { stop_discovery,         false, MGMT_STOP_DISCOVERY_SIZE },
+       { confirm_name,           false, MGMT_CONFIRM_NAME_SIZE },
+       { block_device,           false, MGMT_BLOCK_DEVICE_SIZE },
+       { unblock_device,         false, MGMT_UNBLOCK_DEVICE_SIZE },
+};
+
+
 int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
 {
-       unsigned char *buf;
+       void *buf;
+       u8 *cp;
        struct mgmt_hdr *hdr;
        u16 opcode, index, len;
+       struct hci_dev *hdev = NULL;
+       struct mgmt_handler *handler;
        int err;
 
        BT_DBG("got %zu bytes", msglen);
@@ -2125,7 +2669,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
                goto done;
        }
 
-       hdr = (struct mgmt_hdr *) buf;
+       hdr = buf;
        opcode = get_unaligned_le16(&hdr->opcode);
        index = get_unaligned_le16(&hdr->index);
        len = get_unaligned_le16(&hdr->len);
@@ -2135,117 +2679,54 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
                goto done;
        }
 
-       switch (opcode) {
-       case MGMT_OP_READ_VERSION:
-               err = read_version(sk);
-               break;
-       case MGMT_OP_READ_INDEX_LIST:
-               err = read_index_list(sk);
-               break;
-       case MGMT_OP_READ_INFO:
-               err = read_controller_info(sk, index);
-               break;
-       case MGMT_OP_SET_POWERED:
-               err = set_powered(sk, index, buf + sizeof(*hdr), len);
-               break;
-       case MGMT_OP_SET_DISCOVERABLE:
-               err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
-               break;
-       case MGMT_OP_SET_CONNECTABLE:
-               err = set_connectable(sk, index, buf + sizeof(*hdr), len);
-               break;
-       case MGMT_OP_SET_FAST_CONNECTABLE:
-               err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
-                                                               len);
-               break;
-       case MGMT_OP_SET_PAIRABLE:
-               err = set_pairable(sk, index, buf + sizeof(*hdr), len);
-               break;
-       case MGMT_OP_ADD_UUID:
-               err = add_uuid(sk, index, buf + sizeof(*hdr), len);
-               break;
-       case MGMT_OP_REMOVE_UUID:
-               err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
-               break;
-       case MGMT_OP_SET_DEV_CLASS:
-               err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
-               break;
-       case MGMT_OP_LOAD_LINK_KEYS:
-               err = load_link_keys(sk, index, buf + sizeof(*hdr), len);
-               break;
-       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);
-               break;
-       case MGMT_OP_GET_CONNECTIONS:
-               err = get_connections(sk, index);
-               break;
-       case MGMT_OP_PIN_CODE_REPLY:
-               err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
-               break;
-       case MGMT_OP_PIN_CODE_NEG_REPLY:
-               err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
-               break;
-       case MGMT_OP_SET_IO_CAPABILITY:
-               err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
-               break;
-       case MGMT_OP_PAIR_DEVICE:
-               err = pair_device(sk, index, buf + sizeof(*hdr), len);
-               break;
-       case MGMT_OP_USER_CONFIRM_REPLY:
-               err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len);
-               break;
-       case MGMT_OP_USER_CONFIRM_NEG_REPLY:
-               err = user_confirm_neg_reply(sk, index, buf + sizeof(*hdr),
-                                                                       len);
-               break;
-       case MGMT_OP_USER_PASSKEY_REPLY:
-               err = user_passkey_reply(sk, index, buf + sizeof(*hdr), len);
-               break;
-       case MGMT_OP_USER_PASSKEY_NEG_REPLY:
-               err = user_passkey_neg_reply(sk, index, buf + sizeof(*hdr),
-                                                                       len);
-               break;
-       case MGMT_OP_SET_LOCAL_NAME:
-               err = set_local_name(sk, index, buf + sizeof(*hdr), len);
-               break;
-       case MGMT_OP_READ_LOCAL_OOB_DATA:
-               err = read_local_oob_data(sk, index);
-               break;
-       case MGMT_OP_ADD_REMOTE_OOB_DATA:
-               err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
-               break;
-       case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
-               err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
-                                                                       len);
-               break;
-       case MGMT_OP_START_DISCOVERY:
-               err = start_discovery(sk, index, buf + sizeof(*hdr), len);
-               break;
-       case MGMT_OP_STOP_DISCOVERY:
-               err = stop_discovery(sk, index);
-               break;
-       case MGMT_OP_BLOCK_DEVICE:
-               err = block_device(sk, index, buf + sizeof(*hdr), len);
-               break;
-       case MGMT_OP_UNBLOCK_DEVICE:
-               err = unblock_device(sk, index, buf + sizeof(*hdr), len);
-               break;
-       default:
+       if (index != MGMT_INDEX_NONE) {
+               hdev = hci_dev_get(index);
+               if (!hdev) {
+                       err = cmd_status(sk, index, opcode,
+                                        MGMT_STATUS_INVALID_INDEX);
+                       goto done;
+               }
+       }
+
+       if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
+                                       mgmt_handlers[opcode].func == NULL) {
                BT_DBG("Unknown op %u", opcode);
                err = cmd_status(sk, index, opcode,
-                                               MGMT_STATUS_UNKNOWN_COMMAND);
-               break;
+                                MGMT_STATUS_UNKNOWN_COMMAND);
+               goto done;
+       }
+
+       if ((hdev && opcode < MGMT_OP_READ_INFO) ||
+                       (!hdev && opcode >= MGMT_OP_READ_INFO)) {
+               err = cmd_status(sk, index, opcode,
+                                MGMT_STATUS_INVALID_INDEX);
+               goto done;
        }
 
+       handler = &mgmt_handlers[opcode];
+
+       if ((handler->var_len && len < handler->data_len) ||
+                       (!handler->var_len && len != handler->data_len)) {
+               err = cmd_status(sk, index, opcode,
+                                MGMT_STATUS_INVALID_PARAMS);
+               goto done;
+       }
+
+       if (hdev)
+               mgmt_init_hdev(sk, hdev);
+
+       cp = buf + sizeof(*hdr);
+
+       err = handler->func(sk, hdev, cp, len);
        if (err < 0)
                goto done;
 
        err = msglen;
 
 done:
+       if (hdev)
+               hci_dev_put(hdev);
+
        kfree(buf);
        return err;
 }
@@ -2265,7 +2746,7 @@ int mgmt_index_added(struct hci_dev *hdev)
 
 int mgmt_index_removed(struct hci_dev *hdev)
 {
-       u8 status = ENODEV;
+       u8 status = MGMT_STATUS_INVALID_INDEX;
 
        mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
 
@@ -2273,9 +2754,9 @@ int mgmt_index_removed(struct hci_dev *hdev)
 }
 
 struct cmd_lookup {
-       u8 val;
        struct sock *sk;
        struct hci_dev *hdev;
+       u8 mgmt_status;
 };
 
 static void settings_rsp(struct pending_cmd *cmd, void *data)
@@ -2296,63 +2777,91 @@ static void settings_rsp(struct pending_cmd *cmd, void *data)
 
 int mgmt_powered(struct hci_dev *hdev, u8 powered)
 {
-       struct cmd_lookup match = { powered, NULL, hdev };
-       __le32 ev;
-       int ret;
+       struct cmd_lookup match = { NULL, hdev };
+       int err;
+
+       if (!test_bit(HCI_MGMT, &hdev->dev_flags))
+               return 0;
 
        mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
 
-       if (!powered) {
-               u8 status = ENETDOWN;
+       if (powered) {
+               u8 scan = 0;
+
+               if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
+                       scan |= SCAN_PAGE;
+               if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
+                       scan |= SCAN_INQUIRY;
+
+               if (scan)
+                       hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
+
+               update_class(hdev);
+               update_name(hdev, hdev->dev_name);
+               update_eir(hdev);
+       } else {
+               u8 status = MGMT_STATUS_NOT_POWERED;
                mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
        }
 
-       ev = cpu_to_le32(get_current_settings(hdev));
-
-       ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
-                                                               match.sk);
+       err = new_settings(hdev, match.sk);
 
        if (match.sk)
                sock_put(match.sk);
 
-       return ret;
+       return err;
 }
 
 int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
 {
-       struct cmd_lookup match = { discoverable, NULL, hdev };
-       __le32 ev;
-       int ret;
+       struct cmd_lookup match = { NULL, hdev };
+       bool changed = false;
+       int err = 0;
+
+       if (discoverable) {
+               if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
+                       changed = true;
+       } else {
+               if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
+                       changed = true;
+       }
 
-       mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match);
+       mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
+                            &match);
 
-       ev = cpu_to_le32(get_current_settings(hdev));
+       if (changed)
+               err = new_settings(hdev, match.sk);
 
-       ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
-                                                               match.sk);
        if (match.sk)
                sock_put(match.sk);
 
-       return ret;
+       return err;
 }
 
 int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
 {
-       __le32 ev;
-       struct cmd_lookup match = { connectable, NULL, hdev };
-       int ret;
+       struct cmd_lookup match = { NULL, hdev };
+       bool changed = false;
+       int err = 0;
 
-       mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
-                                                               &match);
+       if (connectable) {
+               if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
+                       changed = true;
+       } else {
+               if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
+                       changed = true;
+       }
 
-       ev = cpu_to_le32(get_current_settings(hdev));
+       mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
+                            &match);
 
-       ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
+       if (changed)
+               err = new_settings(hdev, match.sk);
 
        if (match.sk)
                sock_put(match.sk);
 
-       return ret;
+       return err;
 }
 
 int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
@@ -2361,24 +2870,24 @@ 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, &mgmt_err);
+                                    cmd_status_rsp, &mgmt_err);
 
        if (scan & SCAN_INQUIRY)
                mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
-                                               cmd_status_rsp, &mgmt_err);
+                                    cmd_status_rsp, &mgmt_err);
 
        return 0;
 }
 
-int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
-                                                               u8 persistent)
+int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, u8 persistent)
 {
        struct mgmt_ev_new_link_key ev;
 
        memset(&ev, 0, sizeof(ev));
 
        ev.store_hint = persistent;
-       bacpy(&ev.key.bdaddr, &key->bdaddr);
+       bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
+       ev.key.addr.type = MGMT_ADDR_BREDR;
        ev.key.type = key->type;
        memcpy(ev.key.val, key->val, 16);
        ev.key.pin_len = key->pin_len;
@@ -2386,15 +2895,54 @@ int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
        return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
 }
 
-int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
-                                                               u8 addr_type)
+int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
 {
-       struct mgmt_addr_info ev;
+       struct mgmt_ev_new_long_term_key ev;
 
-       bacpy(&ev.bdaddr, bdaddr);
-       ev.type = link_to_mgmt(link_type, addr_type);
+       memset(&ev, 0, sizeof(ev));
+
+       ev.store_hint = persistent;
+       bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
+       ev.key.addr.type = key->bdaddr_type;
+       ev.key.authenticated = key->authenticated;
+       ev.key.enc_size = key->enc_size;
+       ev.key.ediv = key->ediv;
 
-       return mgmt_event(MGMT_EV_CONNECTED, hdev, &ev, sizeof(ev), NULL);
+       if (key->type == HCI_SMP_LTK)
+               ev.key.master = 1;
+
+       memcpy(ev.key.rand, key->rand, sizeof(key->rand));
+       memcpy(ev.key.val, key->val, sizeof(key->val));
+
+       return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
+                         NULL);
+}
+
+int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
+                         u8 addr_type, u32 flags, u8 *name, u8 name_len,
+                         u8 *dev_class)
+{
+       char buf[512];
+       struct mgmt_ev_device_connected *ev = (void *) buf;
+       u16 eir_len = 0;
+
+       bacpy(&ev->addr.bdaddr, bdaddr);
+       ev->addr.type = link_to_mgmt(link_type, addr_type);
+
+       ev->flags = __cpu_to_le32(flags);
+
+       if (name_len > 0)
+               eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
+                                         name, name_len);
+
+       if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
+               eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
+                                         EIR_CLASS_OF_DEV, dev_class, 3);
+
+       put_unaligned_le16(eir_len, &ev->eir_len);
+
+       return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
+                         sizeof(*ev) + eir_len, NULL);
 }
 
 static void disconnect_rsp(struct pending_cmd *cmd, void *data)
@@ -2403,10 +2951,11 @@ static void disconnect_rsp(struct pending_cmd *cmd, void *data)
        struct sock **sk = data;
        struct mgmt_rp_disconnect rp;
 
-       bacpy(&rp.bdaddr, &cp->bdaddr);
-       rp.status = 0;
+       bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
+       rp.addr.type = cp->addr.type;
 
-       cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
+       cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
+                    sizeof(rp));
 
        *sk = cmd->sk;
        sock_hold(*sk);
@@ -2414,25 +2963,25 @@ static void disconnect_rsp(struct pending_cmd *cmd, void *data)
        mgmt_pending_remove(cmd);
 }
 
-static void remove_keys_rsp(struct pending_cmd *cmd, void *data)
+static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
 {
-       u8 *status = data;
-       struct mgmt_cp_remove_keys *cp = cmd->param;
-       struct mgmt_rp_remove_keys rp;
+       struct hci_dev *hdev = data;
+       struct mgmt_cp_unpair_device *cp = cmd->param;
+       struct mgmt_rp_unpair_device rp;
 
        memset(&rp, 0, sizeof(rp));
-       bacpy(&rp.bdaddr, &cp->bdaddr);
-       if (status != NULL)
-               rp.status = *status;
+       bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
+       rp.addr.type = cp->addr.type;
+
+       device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
 
-       cmd_complete(cmd->sk, cmd->index, MGMT_OP_REMOVE_KEYS, &rp,
-                                                               sizeof(rp));
+       cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
 
        mgmt_pending_remove(cmd);
 }
 
-int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
-                                                               u8 addr_type)
+int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                            u8 link_type, u8 addr_type)
 {
        struct mgmt_addr_info ev;
        struct sock *sk = NULL;
@@ -2443,45 +2992,44 @@ int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
        bacpy(&ev.bdaddr, bdaddr);
        ev.type = link_to_mgmt(link_type, addr_type);
 
-       err = mgmt_event(MGMT_EV_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
+       err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
+                        sk);
 
        if (sk)
-               sock_put(sk);
+         sock_put(sk);
 
-       mgmt_pending_foreach(MGMT_OP_REMOVE_KEYS, hdev, remove_keys_rsp, NULL);
+       mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
+                            hdev);
 
        return err;
 }
 
-int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
+int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                          u8 link_type, u8 addr_type, u8 status)
 {
+       struct mgmt_rp_disconnect rp;
        struct pending_cmd *cmd;
-       u8 mgmt_err = mgmt_status(status);
        int err;
 
        cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
        if (!cmd)
                return -ENOENT;
 
-       if (bdaddr) {
-               struct mgmt_rp_disconnect rp;
-
-               bacpy(&rp.bdaddr, bdaddr);
-               rp.status = status;
+       bacpy(&rp.addr.bdaddr, bdaddr);
+       rp.addr.type = link_to_mgmt(link_type, addr_type);
 
-               err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
-                                                       &rp, sizeof(rp));
-       } else
-               err = cmd_status(cmd->sk, hdev->id, MGMT_OP_DISCONNECT,
-                                                               mgmt_err);
+       err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
+                          mgmt_status(status), &rp, sizeof(rp));
 
        mgmt_pending_remove(cmd);
 
+       mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
+                                                                       hdev);
        return err;
 }
 
 int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
-                                               u8 addr_type, u8 status)
+                       u8 addr_type, u8 status)
 {
        struct mgmt_ev_connect_failed ev;
 
@@ -2496,15 +3044,16 @@ 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);
+       bacpy(&ev.addr.bdaddr, bdaddr);
+       ev.addr.type = MGMT_ADDR_BREDR;
        ev.secure = secure;
 
        return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
-                                                                       NULL);
+                         NULL);
 }
 
 int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
-                                                               u8 status)
+                                u8 status)
 {
        struct pending_cmd *cmd;
        struct mgmt_rp_pin_code_reply rp;
@@ -2514,11 +3063,11 @@ int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
        if (!cmd)
                return -ENOENT;
 
-       bacpy(&rp.bdaddr, bdaddr);
-       rp.status = mgmt_status(status);
+       bacpy(&rp.addr.bdaddr, bdaddr);
+       rp.addr.type = MGMT_ADDR_BREDR;
 
-       err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
-                                                               sizeof(rp));
+       err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
+                          mgmt_status(status), &rp, sizeof(rp));
 
        mgmt_pending_remove(cmd);
 
@@ -2526,7 +3075,7 @@ int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
 }
 
 int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
-                                                               u8 status)
+                                    u8 status)
 {
        struct pending_cmd *cmd;
        struct mgmt_rp_pin_code_reply rp;
@@ -2536,11 +3085,11 @@ int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
        if (!cmd)
                return -ENOENT;
 
-       bacpy(&rp.bdaddr, bdaddr);
-       rp.status = mgmt_status(status);
+       bacpy(&rp.addr.bdaddr, bdaddr);
+       rp.addr.type = MGMT_ADDR_BREDR;
 
-       err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
-                                                               sizeof(rp));
+       err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
+                          mgmt_status(status), &rp, sizeof(rp));
 
        mgmt_pending_remove(cmd);
 
@@ -2548,34 +3097,39 @@ int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
 }
 
 int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
-                                               __le32 value, u8 confirm_hint)
+                             u8 link_type, u8 addr_type, __le32 value,
+                             u8 confirm_hint)
 {
        struct mgmt_ev_user_confirm_request ev;
 
        BT_DBG("%s", hdev->name);
 
-       bacpy(&ev.bdaddr, bdaddr);
+       bacpy(&ev.addr.bdaddr, bdaddr);
+       ev.addr.type = link_to_mgmt(link_type, addr_type);
        ev.confirm_hint = confirm_hint;
        put_unaligned_le32(value, &ev.value);
 
        return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
-                                                                       NULL);
+                         NULL);
 }
 
-int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr)
+int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                               u8 link_type, u8 addr_type)
 {
        struct mgmt_ev_user_passkey_request ev;
 
        BT_DBG("%s", hdev->name);
 
-       bacpy(&ev.bdaddr, bdaddr);
+       bacpy(&ev.addr.bdaddr, bdaddr);
+       ev.addr.type = link_to_mgmt(link_type, addr_type);
 
        return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
-                                                                       NULL);
+                         NULL);
 }
 
 static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
-                                                       u8 status, u8 opcode)
+                                       u8 link_type, u8 addr_type, u8 status,
+                                       u8 opcode)
 {
        struct pending_cmd *cmd;
        struct mgmt_rp_user_confirm_reply rp;
@@ -2585,9 +3139,10 @@ static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
        if (!cmd)
                return -ENOENT;
 
-       bacpy(&rp.bdaddr, bdaddr);
-       rp.status = mgmt_status(status);
-       err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
+       bacpy(&rp.addr.bdaddr, bdaddr);
+       rp.addr.type = link_to_mgmt(link_type, addr_type);
+       err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
+                          &rp, sizeof(rp));
 
        mgmt_pending_remove(cmd);
 
@@ -2595,72 +3150,215 @@ static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
 }
 
 int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
-                                                               u8 status)
+                                    u8 link_type, u8 addr_type, u8 status)
 {
-       return user_pairing_resp_complete(hdev, bdaddr, status,
-                                               MGMT_OP_USER_CONFIRM_REPLY);
+       return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
+                                         status, MGMT_OP_USER_CONFIRM_REPLY);
 }
 
-int mgmt_user_confirm_neg_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 link_type, u8 addr_type, u8 status)
 {
-       return user_pairing_resp_complete(hdev, bdaddr, status,
-                                       MGMT_OP_USER_CONFIRM_NEG_REPLY);
+       return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
+                                         status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
 }
 
 int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
-                                                               u8 status)
+                                    u8 link_type, u8 addr_type, u8 status)
 {
-       return user_pairing_resp_complete(hdev, bdaddr, status,
-                                               MGMT_OP_USER_PASSKEY_REPLY);
+       return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
+                                         status, MGMT_OP_USER_PASSKEY_REPLY);
 }
 
-int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev,
-                                               bdaddr_t *bdaddr, u8 status)
+int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                        u8 link_type, u8 addr_type, u8 status)
 {
-       return user_pairing_resp_complete(hdev, bdaddr, status,
-                                       MGMT_OP_USER_PASSKEY_NEG_REPLY);
+       return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
+                                         status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
 }
 
-int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
+int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
+                    u8 addr_type, u8 status)
 {
        struct mgmt_ev_auth_failed ev;
 
-       bacpy(&ev.bdaddr, bdaddr);
+       bacpy(&ev.addr.bdaddr, bdaddr);
+       ev.addr.type = link_to_mgmt(link_type, addr_type);
        ev.status = mgmt_status(status);
 
        return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
 }
 
+int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
+{
+       struct cmd_lookup match = { NULL, hdev };
+       bool changed = false;
+       int err = 0;
+
+       if (status) {
+               u8 mgmt_err = mgmt_status(status);
+               mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
+                                    cmd_status_rsp, &mgmt_err);
+               return 0;
+       }
+
+       if (test_bit(HCI_AUTH, &hdev->flags)) {
+               if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
+                       changed = true;
+       } else {
+               if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
+                       changed = true;
+       }
+
+       mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
+                            &match);
+
+       if (changed)
+               err = new_settings(hdev, match.sk);
+
+       if (match.sk)
+               sock_put(match.sk);
+
+       return err;
+}
+
+static int clear_eir(struct hci_dev *hdev)
+{
+       struct hci_cp_write_eir cp;
+
+       if (!(hdev->features[6] & LMP_EXT_INQ))
+               return 0;
+
+       memset(hdev->eir, 0, sizeof(hdev->eir));
+
+       memset(&cp, 0, sizeof(cp));
+
+       return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
+}
+
+int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
+{
+       struct cmd_lookup match = { NULL, hdev };
+       bool changed = false;
+       int err = 0;
+
+       if (status) {
+               u8 mgmt_err = mgmt_status(status);
+
+               if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
+                                                &hdev->dev_flags))
+                       err = new_settings(hdev, NULL);
+
+               mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
+                                    &mgmt_err);
+
+               return err;
+       }
+
+       if (enable) {
+               if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
+                       changed = true;
+       } else {
+               if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
+                       changed = true;
+       }
+
+       mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
+
+       if (changed)
+               err = new_settings(hdev, match.sk);
+
+       if (match.sk)
+               sock_put(match.sk);
+
+       if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
+               update_eir(hdev);
+       else
+               clear_eir(hdev);
+
+       return err;
+}
+
+static void class_rsp(struct pending_cmd *cmd, void *data)
+{
+       struct cmd_lookup *match = data;
+
+       cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
+                    match->hdev->dev_class, 3);
+
+       list_del(&cmd->list);
+
+       if (match->sk == NULL) {
+               match->sk = cmd->sk;
+               sock_hold(match->sk);
+       }
+
+       mgmt_pending_free(cmd);
+}
+
+int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
+                                  u8 status)
+{
+       struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
+       int err = 0;
+
+       clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
+
+       mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
+       mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
+       mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
+
+       if (!status)
+               err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
+                                3, NULL);
+
+       if (match.sk)
+               sock_put(match.sk);
+
+       return err;
+}
+
 int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
 {
        struct pending_cmd *cmd;
        struct mgmt_cp_set_local_name ev;
-       int err;
+       bool changed = false;
+       int err = 0;
+
+       if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
+               memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
+               changed = true;
+       }
 
        memset(&ev, 0, sizeof(ev));
        memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
+       memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
 
        cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
        if (!cmd)
                goto send_event;
 
+       /* Always assume that either the short or the complete name has
+        * changed if there was a pending mgmt command */
+       changed = true;
+
        if (status) {
                err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
-                                                       mgmt_status(status));
+                                mgmt_status(status));
                goto failed;
        }
 
-       update_eir(hdev);
-
-       err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
-                                                               sizeof(ev));
+       err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
+                          sizeof(ev));
        if (err < 0)
                goto failed;
 
 send_event:
-       err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
-                                                       cmd ? cmd->sk : NULL);
+       if (changed)
+               err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
+                                sizeof(ev), cmd ? cmd->sk : NULL);
+
+       update_eir(hdev);
 
 failed:
        if (cmd)
@@ -2669,7 +3367,7 @@ failed:
 }
 
 int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
-                                               u8 *randomizer, u8 status)
+                                           u8 *randomizer, u8 status)
 {
        struct pending_cmd *cmd;
        int err;
@@ -2681,9 +3379,8 @@ int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
                return -ENOENT;
 
        if (status) {
-               err = cmd_status(cmd->sk, hdev->id,
-                                               MGMT_OP_READ_LOCAL_OOB_DATA,
-                                               mgmt_status(status));
+               err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
+                                mgmt_status(status));
        } else {
                struct mgmt_rp_read_local_oob_data rp;
 
@@ -2691,8 +3388,8 @@ int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
                memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
 
                err = cmd_complete(cmd->sk, hdev->id,
-                                               MGMT_OP_READ_LOCAL_OOB_DATA,
-                                               &rp, sizeof(rp));
+                                  MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
+                                  sizeof(rp));
        }
 
        mgmt_pending_remove(cmd);
@@ -2700,48 +3397,120 @@ int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
        return err;
 }
 
+int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
+{
+       struct cmd_lookup match = { NULL, hdev };
+       bool changed = false;
+       int err = 0;
+
+       if (status) {
+               u8 mgmt_err = mgmt_status(status);
+
+               if (enable && test_and_clear_bit(HCI_LE_ENABLED,
+                                                &hdev->dev_flags))
+                 err = new_settings(hdev, NULL);
+
+               mgmt_pending_foreach(MGMT_OP_SET_LE, hdev,
+                                    cmd_status_rsp, &mgmt_err);
+
+               return err;
+       }
+
+       if (enable) {
+               if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
+                       changed = true;
+       } else {
+               if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
+                       changed = true;
+       }
+
+       mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
+
+       if (changed)
+               err = new_settings(hdev, match.sk);
+
+       if (match.sk)
+               sock_put(match.sk);
+
+       return err;
+}
+
 int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
-                               u8 addr_type, u8 *dev_class, s8 rssi, u8 *eir)
+                     u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
+                     ssp, u8 *eir, u16 eir_len)
 {
-       struct mgmt_ev_device_found ev;
+       char buf[512];
+       struct mgmt_ev_device_found *ev = (void *) buf;
+       size_t ev_size;
 
-       memset(&ev, 0, sizeof(ev));
+       /* Leave 5 bytes for a potential CoD field */
+       if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
+               return -EINVAL;
 
-       bacpy(&ev.addr.bdaddr, bdaddr);
-       ev.addr.type = link_to_mgmt(link_type, addr_type);
-       ev.rssi = rssi;
+       memset(buf, 0, sizeof(buf));
+
+       bacpy(&ev->addr.bdaddr, bdaddr);
+       ev->addr.type = link_to_mgmt(link_type, addr_type);
+       ev->rssi = rssi;
+       if (cfm_name)
+               ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME;
+       if (!ssp)
+               ev->flags[0] |= MGMT_DEV_FOUND_LEGACY_PAIRING;
 
-       if (eir)
-               memcpy(ev.eir, eir, sizeof(ev.eir));
+       if (eir_len > 0)
+               memcpy(ev->eir, eir, eir_len);
 
-       if (dev_class)
-               memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
+       if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
+               eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
+                                         dev_class, 3);
 
-       return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, &ev, sizeof(ev), NULL);
+       put_unaligned_le16(eir_len, &ev->eir_len);
+
+       ev_size = sizeof(*ev) + eir_len;
+
+       return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
 }
 
-int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name)
+int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
+                    u8 addr_type, s8 rssi, u8 *name, u8 name_len)
 {
-       struct mgmt_ev_remote_name ev;
+       struct mgmt_ev_device_found *ev;
+       char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
+       u16 eir_len;
 
-       memset(&ev, 0, sizeof(ev));
+       ev = (struct mgmt_ev_device_found *) buf;
 
-       bacpy(&ev.bdaddr, bdaddr);
-       memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
+       memset(buf, 0, sizeof(buf));
+
+       bacpy(&ev->addr.bdaddr, bdaddr);
+       ev->addr.type = link_to_mgmt(link_type, addr_type);
+       ev->rssi = rssi;
 
-       return mgmt_event(MGMT_EV_REMOTE_NAME, hdev, &ev, sizeof(ev), NULL);
+       eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
+                                 name_len);
+
+       put_unaligned_le16(eir_len, &ev->eir_len);
+
+       return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
+                         sizeof(*ev) + eir_len, NULL);
 }
 
 int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
 {
        struct pending_cmd *cmd;
+       u8 type;
        int err;
 
+       hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+
        cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
        if (!cmd)
                return -ENOENT;
 
-       err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
+       type = hdev->discovery.type;
+
+       err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
+                          &type, sizeof(type));
        mgmt_pending_remove(cmd);
 
        return err;
@@ -2756,7 +3525,8 @@ int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
        if (!cmd)
                return -ENOENT;
 
-       err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
+       err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
+                          &hdev->discovery.type, sizeof(hdev->discovery.type));
        mgmt_pending_remove(cmd);
 
        return err;
@@ -2764,44 +3534,61 @@ int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
 
 int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
 {
+       struct mgmt_ev_discovering ev;
        struct pending_cmd *cmd;
 
+       BT_DBG("%s discovering %u", hdev->name, discovering);
+
        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);
+               u8 type = hdev->discovery.type;
+
+               cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
+                            sizeof(type));
                mgmt_pending_remove(cmd);
        }
 
-       return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
-                                               sizeof(discovering), NULL);
+       memset(&ev, 0, sizeof(ev));
+       ev.type = hdev->discovery.type;
+       ev.discovering = discovering;
+
+       return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
 }
 
-int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
+int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
 {
        struct pending_cmd *cmd;
        struct mgmt_ev_device_blocked ev;
 
        cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
 
-       bacpy(&ev.bdaddr, bdaddr);
+       bacpy(&ev.addr.bdaddr, bdaddr);
+       ev.addr.type = type;
 
        return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
-                                                       cmd ? cmd->sk : NULL);
+                         cmd ? cmd->sk : NULL);
 }
 
-int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
+int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
 {
        struct pending_cmd *cmd;
        struct mgmt_ev_device_unblocked ev;
 
        cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
 
-       bacpy(&ev.bdaddr, bdaddr);
+       bacpy(&ev.addr.bdaddr, bdaddr);
+       ev.addr.type = type;
 
        return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
-                                                       cmd ? cmd->sk : NULL);
+                         cmd ? cmd->sk : NULL);
 }
+
+module_param(enable_hs, bool, 0644);
+MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
+
+module_param(enable_le, bool, 0644);
+MODULE_PARM_DESC(enable_le, "Enable Low Energy support");
index a2d4f5122a6a2030913814a8ebdc0cf6a381e29d..c179734f143f47f6045d7989f333c9b38db1fc7b 100644 (file)
@@ -196,7 +196,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, *entry;
-       struct list_head *head = &rfcomm_dev_list, *p;
+       struct list_head *head = &rfcomm_dev_list;
        int err = 0;
 
        BT_DBG("id %d channel %d", req->dev_id, req->channel);
@@ -215,7 +215,7 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
                                break;
 
                        dev->id++;
-                       head = p;
+                       head = &entry->list;
                }
        } else {
                dev->id = req->dev_id;
@@ -229,7 +229,7 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
                        if (entry->id > dev->id - 1)
                                break;
 
-                       head = p;
+                       head = &entry->list;
                }
        }
 
index 32c47de303440846fce21b5c02e53c89e08e92d8..deb119875fd93aee3fa125ecfd49de66495b7786 100644 (file)
@@ -29,7 +29,7 @@
 #include <linux/scatterlist.h>
 #include <crypto/b128ops.h>
 
-#define SMP_TIMEOUT 30000 /* 30 seconds */
+#define SMP_TIMEOUT    msecs_to_jiffies(30000)
 
 static inline void swap128(u8 src[16], u8 dst[16])
 {
@@ -186,8 +186,7 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
        hci_send_acl(conn->hchan, skb, 0);
 
        cancel_delayed_work_sync(&conn->security_timer);
-       schedule_delayed_work(&conn->security_timer,
-                                       msecs_to_jiffies(SMP_TIMEOUT));
+       schedule_delayed_work(&conn->security_timer, SMP_TIMEOUT);
 }
 
 static __u8 authreq_to_seclevel(__u8 authreq)
@@ -217,7 +216,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
 {
        u8 dist_keys = 0;
 
-       if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->flags)) {
+       if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->dev_flags)) {
                dist_keys = SMP_DIST_ENC_KEY;
                authreq |= SMP_AUTH_BONDING;
        } else {
@@ -250,21 +249,27 @@ static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
                        (max_key_size < SMP_MIN_ENC_KEY_SIZE))
                return SMP_ENC_KEY_SIZE;
 
-       smp->smp_key_size = max_key_size;
+       smp->enc_key_size = max_key_size;
 
        return 0;
 }
 
 static void smp_failure(struct l2cap_conn *conn, u8 reason, u8 send)
 {
+       struct hci_conn *hcon = conn->hcon;
+
        if (send)
                smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason),
                                                                &reason);
 
-       clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->hcon->pend);
-       mgmt_auth_failed(conn->hcon->hdev, conn->dst, reason);
-       cancel_delayed_work_sync(&conn->security_timer);
-       smp_chan_destroy(conn);
+       clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->hcon->flags);
+       mgmt_auth_failed(conn->hcon->hdev, conn->dst, hcon->type,
+                        hcon->dst_type, reason);
+
+       if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) {
+               cancel_delayed_work_sync(&conn->security_timer);
+               smp_chan_destroy(conn);
+       }
 }
 
 #define JUST_WORKS     0x00
@@ -305,7 +310,7 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
                        remote_io > SMP_IO_KEYBOARD_DISPLAY)
                method = JUST_WORKS;
        else
-               method = gen_method[local_io][remote_io];
+               method = gen_method[remote_io][local_io];
 
        /* If not bonding, don't ask user to confirm a Zero TK */
        if (!(auth & SMP_AUTH_BONDING) && method == JUST_CFM)
@@ -346,9 +351,11 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
        hci_dev_lock(hcon->hdev);
 
        if (method == REQ_PASSKEY)
-               ret = mgmt_user_passkey_request(hcon->hdev, conn->dst);
+               ret = mgmt_user_passkey_request(hcon->hdev, conn->dst,
+                                               hcon->type, hcon->dst_type);
        else
                ret = mgmt_user_confirm_request(hcon->hdev, conn->dst,
+                                               hcon->type, hcon->dst_type,
                                                cpu_to_le32(passkey), 0);
 
        hci_dev_unlock(hcon->hdev);
@@ -377,12 +384,11 @@ static void confirm_work(struct work_struct *work)
 
        if (conn->hcon->out)
                ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp, 0,
-                               conn->src, conn->hcon->dst_type, conn->dst,
-                               res);
+                            conn->src, conn->hcon->dst_type, conn->dst, res);
        else
                ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp,
-                               conn->hcon->dst_type, conn->dst, 0, conn->src,
-                               res);
+                            conn->hcon->dst_type, conn->dst, 0, conn->src,
+                            res);
        if (ret) {
                reason = SMP_UNSPECIFIED;
                goto error;
@@ -417,12 +423,10 @@ static void random_work(struct work_struct *work)
 
        if (hcon->out)
                ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp, 0,
-                               conn->src, hcon->dst_type, conn->dst,
-                               res);
+                            conn->src, hcon->dst_type, conn->dst, res);
        else
                ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp,
-                               hcon->dst_type, conn->dst, 0, conn->src,
-                               res);
+                            hcon->dst_type, conn->dst, 0, conn->src, res);
        if (ret) {
                reason = SMP_UNSPECIFIED;
                goto error;
@@ -446,16 +450,16 @@ static void random_work(struct work_struct *work)
                smp_s1(tfm, smp->tk, smp->rrnd, smp->prnd, key);
                swap128(key, stk);
 
-               memset(stk + smp->smp_key_size, 0,
-                               SMP_MAX_ENC_KEY_SIZE - smp->smp_key_size);
+               memset(stk + smp->enc_key_size, 0,
+                      SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);
 
-               if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) {
+               if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags)) {
                        reason = SMP_UNSPECIFIED;
                        goto error;
                }
 
                hci_le_start_enc(hcon, ediv, rand, stk);
-               hcon->enc_key_size = smp->smp_key_size;
+               hcon->enc_key_size = smp->enc_key_size;
        } else {
                u8 stk[16], r[16], rand[8];
                __le16 ediv;
@@ -469,11 +473,12 @@ static void random_work(struct work_struct *work)
                smp_s1(tfm, smp->tk, smp->prnd, smp->rrnd, key);
                swap128(key, stk);
 
-               memset(stk + smp->smp_key_size, 0,
-                               SMP_MAX_ENC_KEY_SIZE - smp->smp_key_size);
+               memset(stk + smp->enc_key_size, 0,
+                               SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);
 
-               hci_add_ltk(hcon->hdev, 0, conn->dst, smp->smp_key_size,
-                                                       ediv, rand, stk);
+               hci_add_ltk(hcon->hdev, conn->dst, hcon->dst_type,
+                           HCI_SMP_STK_SLAVE, 0, 0, stk, smp->enc_key_size,
+                           ediv, rand);
        }
 
        return;
@@ -506,7 +511,7 @@ void smp_chan_destroy(struct l2cap_conn *conn)
 {
        struct smp_chan *smp = conn->smp_chan;
 
-       clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend);
+       BUG_ON(!smp);
 
        if (smp->tfm)
                crypto_free_blkcipher(smp->tfm);
@@ -571,7 +576,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
        if (conn->hcon->link_mode & HCI_LM_MASTER)
                return SMP_CMD_NOTSUPP;
 
-       if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend))
+       if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags))
                smp = smp_chan_create(conn);
 
        smp = conn->smp_chan;
@@ -584,6 +589,8 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
        if (req->auth_req & SMP_AUTH_BONDING)
                auth = req->auth_req;
 
+       conn->hcon->pending_sec_level = authreq_to_seclevel(auth);
+
        build_pairing_cmd(conn, req, &rsp, auth);
 
        key_size = min(req->max_key_size, rsp.max_key_size);
@@ -698,23 +705,18 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
 
 static u8 smp_ltk_encrypt(struct l2cap_conn *conn)
 {
-       struct link_key *key;
-       struct key_master_id *master;
+       struct smp_ltk *key;
        struct hci_conn *hcon = conn->hcon;
 
-       key = hci_find_link_key_type(hcon->hdev, conn->dst,
-                                               HCI_LK_SMP_LTK);
+       key = hci_find_ltk_by_addr(hcon->hdev, conn->dst, hcon->dst_type);
        if (!key)
                return 0;
 
-       if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND,
-                                       &hcon->pend))
+       if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags))
                return 1;
 
-       master = (void *) key->data;
-       hci_le_start_enc(hcon, master->ediv, master->rand,
-                                               key->val);
-       hcon->enc_key_size = key->pin_len;
+       hci_le_start_enc(hcon, key->ediv, key->rand, key->val);
+       hcon->enc_key_size = key->enc_size;
 
        return 1;
 
@@ -733,7 +735,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
        if (smp_ltk_encrypt(conn))
                return 0;
 
-       if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend))
+       if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
                return 0;
 
        smp = smp_chan_create(conn);
@@ -772,7 +774,7 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
                if (smp_ltk_encrypt(conn))
                        goto done;
 
-       if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend))
+       if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
                return 0;
 
        smp = smp_chan_create(conn);
@@ -817,13 +819,19 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
 {
        struct smp_cmd_master_ident *rp = (void *) skb->data;
        struct smp_chan *smp = conn->smp_chan;
+       struct hci_dev *hdev = conn->hcon->hdev;
+       struct hci_conn *hcon = conn->hcon;
+       u8 authenticated;
 
        skb_pull(skb, sizeof(*rp));
 
-       hci_add_ltk(conn->hcon->hdev, 1, conn->dst, smp->smp_key_size,
-                                               rp->ediv, rp->rand, smp->tk);
-
+       hci_dev_lock(hdev);
+       authenticated = (conn->hcon->sec_level == BT_SECURITY_HIGH);
+       hci_add_ltk(conn->hcon->hdev, conn->dst, hcon->dst_type,
+                   HCI_SMP_LTK, 1, authenticated, smp->tk, smp->enc_key_size,
+                   rp->ediv, rp->rand);
        smp_distribute_keys(conn, 1);
+       hci_dev_unlock(hdev);
 
        return 0;
 }
@@ -908,7 +916,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
 
        BT_DBG("conn %p force %d", conn, force);
 
-       if (!test_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend))
+       if (!test_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags))
                return 0;
 
        rsp = (void *) &smp->prsp[1];
@@ -933,6 +941,8 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
        if (*keydist & SMP_DIST_ENC_KEY) {
                struct smp_cmd_encrypt_info enc;
                struct smp_cmd_master_ident ident;
+               struct hci_conn *hcon = conn->hcon;
+               u8 authenticated;
                __le16 ediv;
 
                get_random_bytes(enc.ltk, sizeof(enc.ltk));
@@ -941,8 +951,10 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
 
                smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc);
 
-               hci_add_ltk(conn->hcon->hdev, 1, conn->dst, smp->smp_key_size,
-                                               ediv, ident.rand, enc.ltk);
+               authenticated = hcon->sec_level == BT_SECURITY_HIGH;
+               hci_add_ltk(conn->hcon->hdev, conn->dst, hcon->dst_type,
+                           HCI_SMP_LTK_SLAVE, 1, authenticated,
+                           enc.ltk, smp->enc_key_size, ediv, ident.rand);
 
                ident.ediv = cpu_to_le16(ediv);
 
@@ -982,7 +994,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
        }
 
        if (conn->hcon->out || force) {
-               clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend);
+               clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags);
                cancel_delayed_work_sync(&conn->security_timer);
                smp_chan_destroy(conn);
        }
index 568d5bf175341b4f84ef284173b5d6da623ceafb..702a1ae9220b79bd9e60cc25732201fe8750dcd2 100644 (file)
@@ -446,8 +446,11 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br,
        ip6h->nexthdr = IPPROTO_HOPOPTS;
        ip6h->hop_limit = 1;
        ipv6_addr_set(&ip6h->daddr, htonl(0xff020000), 0, 0, htonl(1));
-       ipv6_dev_get_saddr(dev_net(br->dev), br->dev, &ip6h->daddr, 0,
-                          &ip6h->saddr);
+       if (ipv6_dev_get_saddr(dev_net(br->dev), br->dev, &ip6h->daddr, 0,
+                              &ip6h->saddr)) {
+               kfree_skb(skb);
+               return NULL;
+       }
        ipv6_eth_mc_map(&ip6h->daddr, eth->h_dest);
 
        hopopt = (u8 *)(ip6h + 1);
index 84122472656c3a70f0c0a93020768e81ecb3972a..dec4f3817133c879b524a65f0919b5dabcff46ea 100644 (file)
@@ -62,6 +62,15 @@ static int brnf_filter_pppoe_tagged __read_mostly = 0;
 #define brnf_filter_pppoe_tagged 0
 #endif
 
+#define IS_IP(skb) \
+       (!vlan_tx_tag_present(skb) && skb->protocol == htons(ETH_P_IP))
+
+#define IS_IPV6(skb) \
+       (!vlan_tx_tag_present(skb) && skb->protocol == htons(ETH_P_IPV6))
+
+#define IS_ARP(skb) \
+       (!vlan_tx_tag_present(skb) && skb->protocol == htons(ETH_P_ARP))
+
 static inline __be16 vlan_proto(const struct sk_buff *skb)
 {
        if (vlan_tx_tag_present(skb))
@@ -639,8 +648,7 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff *skb,
                return NF_DROP;
        br = p->br;
 
-       if (skb->protocol == htons(ETH_P_IPV6) || IS_VLAN_IPV6(skb) ||
-           IS_PPPOE_IPV6(skb)) {
+       if (IS_IPV6(skb) || IS_VLAN_IPV6(skb) || IS_PPPOE_IPV6(skb)) {
                if (!brnf_call_ip6tables && !br->nf_call_ip6tables)
                        return NF_ACCEPT;
 
@@ -651,8 +659,7 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff *skb,
        if (!brnf_call_iptables && !br->nf_call_iptables)
                return NF_ACCEPT;
 
-       if (skb->protocol != htons(ETH_P_IP) && !IS_VLAN_IP(skb) &&
-           !IS_PPPOE_IP(skb))
+       if (!IS_IP(skb) && !IS_VLAN_IP(skb) && !IS_PPPOE_IP(skb))
                return NF_ACCEPT;
 
        nf_bridge_pull_encap_header_rcsum(skb);
@@ -701,7 +708,7 @@ static int br_nf_forward_finish(struct sk_buff *skb)
        struct nf_bridge_info *nf_bridge = skb->nf_bridge;
        struct net_device *in;
 
-       if (skb->protocol != htons(ETH_P_ARP) && !IS_VLAN_ARP(skb)) {
+       if (!IS_ARP(skb) && !IS_VLAN_ARP(skb)) {
                in = nf_bridge->physindev;
                if (nf_bridge->mask & BRNF_PKT_TYPE) {
                        skb->pkt_type = PACKET_OTHERHOST;
@@ -718,6 +725,7 @@ static int br_nf_forward_finish(struct sk_buff *skb)
        return 0;
 }
 
+
 /* This is the 'purely bridged' case.  For IP, we pass the packet to
  * netfilter with indev and outdev set to the bridge device,
  * but we are still able to filter on the 'real' indev/outdev
@@ -744,11 +752,9 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff *skb,
        if (!parent)
                return NF_DROP;
 
-       if (skb->protocol == htons(ETH_P_IP) || IS_VLAN_IP(skb) ||
-           IS_PPPOE_IP(skb))
+       if (IS_IP(skb) || IS_VLAN_IP(skb) || IS_PPPOE_IP(skb))
                pf = PF_INET;
-       else if (skb->protocol == htons(ETH_P_IPV6) || IS_VLAN_IPV6(skb) ||
-                IS_PPPOE_IPV6(skb))
+       else if (IS_IPV6(skb) || IS_VLAN_IPV6(skb) || IS_PPPOE_IPV6(skb))
                pf = PF_INET6;
        else
                return NF_ACCEPT;
@@ -795,7 +801,7 @@ static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff *skb,
        if (!brnf_call_arptables && !br->nf_call_arptables)
                return NF_ACCEPT;
 
-       if (skb->protocol != htons(ETH_P_ARP)) {
+       if (!IS_ARP(skb)) {
                if (!IS_VLAN_ARP(skb))
                        return NF_ACCEPT;
                nf_bridge_pull_encap_header(skb);
@@ -853,11 +859,9 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff *skb,
        if (!realoutdev)
                return NF_DROP;
 
-       if (skb->protocol == htons(ETH_P_IP) || IS_VLAN_IP(skb) ||
-           IS_PPPOE_IP(skb))
+       if (IS_IP(skb) || IS_VLAN_IP(skb) || IS_PPPOE_IP(skb))
                pf = PF_INET;
-       else if (skb->protocol == htons(ETH_P_IPV6) || IS_VLAN_IPV6(skb) ||
-                IS_PPPOE_IPV6(skb))
+       else if (IS_IPV6(skb) || IS_VLAN_IPV6(skb) || IS_PPPOE_IPV6(skb))
                pf = PF_INET6;
        else
                return NF_ACCEPT;
index dd147d78a5889ab6c2139712199c3672f9e087c6..8c836d96ba769eaaf4b62ce76b26c7e5e4f814b0 100644 (file)
@@ -17,9 +17,9 @@
 #include "br_private_stp.h"
 
 /* since time values in bpdu are in jiffies and then scaled (1/256)
- * before sending, make sure that is at least one.
+ * before sending, make sure that is at least one STP tick.
  */
-#define MESSAGE_AGE_INCR       ((HZ < 256) ? 1 : (HZ/256))
+#define MESSAGE_AGE_INCR       ((HZ / 256) + 1)
 
 static const char *const br_port_state_names[] = {
        [BR_STATE_DISABLED] = "disabled",
@@ -31,7 +31,7 @@ static const char *const br_port_state_names[] = {
 
 void br_log_state(const struct net_bridge_port *p)
 {
-       br_info(p->br, "port %u(%s) entering %s state\n",
+       br_info(p->br, "port %u(%s) entered %s state\n",
                (unsigned) p->port_no, p->dev->name,
                br_port_state_names[p->state]);
 }
@@ -186,7 +186,7 @@ static void br_record_config_information(struct net_bridge_port *p,
        p->designated_cost = bpdu->root_path_cost;
        p->designated_bridge = bpdu->bridge_id;
        p->designated_port = bpdu->port_id;
-       p->designated_age = jiffies + bpdu->message_age;
+       p->designated_age = jiffies - bpdu->message_age;
 
        mod_timer(&p->message_age_timer, jiffies
                  + (p->br->max_age - bpdu->message_age));
index 19308e305d851a89044434315a86d2e9ca9dc549..f494496373d60c1faf368a05605073a1c71ad04f 100644 (file)
@@ -98,14 +98,13 @@ void br_stp_disable_port(struct net_bridge_port *p)
        struct net_bridge *br = p->br;
        int wasroot;
 
-       br_log_state(p);
-
        wasroot = br_is_root_bridge(br);
        br_become_designated_port(p);
        p->state = BR_STATE_DISABLED;
        p->topology_change_ack = 0;
        p->config_pending = 0;
 
+       br_log_state(p);
        br_ifinfo_notify(RTM_NEWLINK, p);
 
        del_timer(&p->message_age_timer);
index 8aa4ad0e06af9a95e691e47e628198f11c39f069..5fe2ff3b01efe44d07292514b814b0ba7b01d4f0 100644 (file)
@@ -1335,7 +1335,12 @@ static inline int ebt_make_matchname(const struct ebt_entry_match *m,
     const char *base, char __user *ubase)
 {
        char __user *hlp = ubase + ((char *)m - base);
-       if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN))
+       char name[EBT_FUNCTION_MAXNAMELEN] = {};
+
+       /* ebtables expects 32 bytes long names but xt_match names are 29 bytes
+          long. Copy 29 bytes and fill remaining bytes with zeroes. */
+       strncpy(name, m->u.match->name, sizeof(name));
+       if (copy_to_user(hlp, name, EBT_FUNCTION_MAXNAMELEN))
                return -EFAULT;
        return 0;
 }
@@ -1344,7 +1349,10 @@ static inline int ebt_make_watchername(const struct ebt_entry_watcher *w,
     const char *base, char __user *ubase)
 {
        char __user *hlp = ubase + ((char *)w - base);
-       if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN))
+       char name[EBT_FUNCTION_MAXNAMELEN] = {};
+
+       strncpy(name, w->u.watcher->name, sizeof(name));
+       if (copy_to_user(hlp , name, EBT_FUNCTION_MAXNAMELEN))
                return -EFAULT;
        return 0;
 }
@@ -1355,6 +1363,7 @@ ebt_make_names(struct ebt_entry *e, const char *base, char __user *ubase)
        int ret;
        char __user *hlp;
        const struct ebt_entry_target *t;
+       char name[EBT_FUNCTION_MAXNAMELEN] = {};
 
        if (e->bitmask == 0)
                return 0;
@@ -1368,7 +1377,8 @@ ebt_make_names(struct ebt_entry *e, const char *base, char __user *ubase)
        ret = EBT_WATCHER_ITERATE(e, ebt_make_watchername, base, ubase);
        if (ret != 0)
                return ret;
-       if (copy_to_user(hlp, t->u.target->name, EBT_FUNCTION_MAXNAMELEN))
+       strncpy(name, t->u.target->name, sizeof(name));
+       if (copy_to_user(hlp, name, EBT_FUNCTION_MAXNAMELEN))
                return -EFAULT;
        return 0;
 }
index 763a0eda7158b7059b296693effc1c5b9c65bf96..0090809af7bdec0384f3fc9694b762f4fb3c07d3 100644 (file)
@@ -848,21 +848,21 @@ EXPORT_SYMBOL(dev_get_by_flags_rcu);
  *     to allow sysfs to work.  We also disallow any kind of
  *     whitespace.
  */
-int dev_valid_name(const char *name)
+bool dev_valid_name(const char *name)
 {
        if (*name == '\0')
-               return 0;
+               return false;
        if (strlen(name) >= IFNAMSIZ)
-               return 0;
+               return false;
        if (!strcmp(name, ".") || !strcmp(name, ".."))
-               return 0;
+               return false;
 
        while (*name) {
                if (*name == '/' || isspace(*name))
-                       return 0;
+                       return false;
                name++;
        }
-       return 1;
+       return true;
 }
 EXPORT_SYMBOL(dev_valid_name);
 
@@ -5834,12 +5834,12 @@ void netdev_run_todo(void)
 /* Convert net_device_stats to rtnl_link_stats64.  They have the same
  * fields in the same order, with only the type differing.
  */
-static void netdev_stats_to_stats64(struct rtnl_link_stats64 *stats64,
-                                   const struct net_device_stats *netdev_stats)
+void netdev_stats_to_stats64(struct rtnl_link_stats64 *stats64,
+                            const struct net_device_stats *netdev_stats)
 {
 #if BITS_PER_LONG == 64
-        BUILD_BUG_ON(sizeof(*stats64) != sizeof(*netdev_stats));
-        memcpy(stats64, netdev_stats, sizeof(*stats64));
+       BUILD_BUG_ON(sizeof(*stats64) != sizeof(*netdev_stats));
+       memcpy(stats64, netdev_stats, sizeof(*stats64));
 #else
        size_t i, n = sizeof(*stats64) / sizeof(u64);
        const unsigned long *src = (const unsigned long *)netdev_stats;
@@ -5851,6 +5851,7 @@ static void netdev_stats_to_stats64(struct rtnl_link_stats64 *stats64,
                dst[i] = src[i];
 #endif
 }
+EXPORT_SYMBOL(netdev_stats_to_stats64);
 
 /**
  *     dev_get_stats   - get network device statistics
index 2be10181d5832d8e6e00ee5216fe1e6028b26f90..1a63c6efd2eaed0bad1582bd0c1a07a83ed73fb6 100644 (file)
@@ -1060,11 +1060,12 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
        rcu_read_lock();
        cb->seq = net->dev_base_seq;
 
-       nlmsg_parse(cb->nlh, sizeof(struct rtgenmsg), tb, IFLA_MAX,
-                   ifla_policy);
+       if (nlmsg_parse(cb->nlh, sizeof(struct rtgenmsg), tb, IFLA_MAX,
+                       ifla_policy) >= 0) {
 
-       if (tb[IFLA_EXT_MASK])
-               ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]);
+               if (tb[IFLA_EXT_MASK])
+                       ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]);
+       }
 
        for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
                idx = 0;
@@ -1902,10 +1903,11 @@ static u16 rtnl_calcit(struct sk_buff *skb, struct nlmsghdr *nlh)
        u32 ext_filter_mask = 0;
        u16 min_ifinfo_dump_size = 0;
 
-       nlmsg_parse(nlh, sizeof(struct rtgenmsg), tb, IFLA_MAX, ifla_policy);
-
-       if (tb[IFLA_EXT_MASK])
-               ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]);
+       if (nlmsg_parse(nlh, sizeof(struct rtgenmsg), tb, IFLA_MAX,
+                       ifla_policy) >= 0) {
+               if (tb[IFLA_EXT_MASK])
+                       ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]);
+       }
 
        if (!ext_filter_mask)
                return NLMSG_GOODSIZE;
index bf4a9c4808e1faaa7461a472f224a4d3c8edf379..d4d61b694fab9bc497b1cccb808a3a568ad30cc2 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/net.h>
+#include <linux/workqueue.h>
 #include <net/ip.h>
 #include <net/inetpeer.h>
 #include <net/secure_seq.h>
 
 static struct kmem_cache *peer_cachep __read_mostly;
 
+static LIST_HEAD(gc_list);
+static const int gc_delay = 60 * HZ;
+static struct delayed_work gc_work;
+static DEFINE_SPINLOCK(gc_lock);
+
 #define node_height(x) x->avl_height
 
 #define peer_avl_empty ((struct inet_peer *)&peer_fake_node)
@@ -102,6 +108,50 @@ int inet_peer_threshold __read_mostly = 65536 + 128;       /* start to throw entries m
 int inet_peer_minttl __read_mostly = 120 * HZ; /* TTL under high load: 120 sec */
 int inet_peer_maxttl __read_mostly = 10 * 60 * HZ;     /* usual time to live: 10 min */
 
+static void inetpeer_gc_worker(struct work_struct *work)
+{
+       struct inet_peer *p, *n;
+       LIST_HEAD(list);
+
+       spin_lock_bh(&gc_lock);
+       list_replace_init(&gc_list, &list);
+       spin_unlock_bh(&gc_lock);
+
+       if (list_empty(&list))
+               return;
+
+       list_for_each_entry_safe(p, n, &list, gc_list) {
+
+               if(need_resched())
+                       cond_resched();
+
+               if (p->avl_left != peer_avl_empty) {
+                       list_add_tail(&p->avl_left->gc_list, &list);
+                       p->avl_left = peer_avl_empty;
+               }
+
+               if (p->avl_right != peer_avl_empty) {
+                       list_add_tail(&p->avl_right->gc_list, &list);
+                       p->avl_right = peer_avl_empty;
+               }
+
+               n = list_entry(p->gc_list.next, struct inet_peer, gc_list);
+
+               if (!atomic_read(&p->refcnt)) {
+                       list_del(&p->gc_list);
+                       kmem_cache_free(peer_cachep, p);
+               }
+       }
+
+       if (list_empty(&list))
+               return;
+
+       spin_lock_bh(&gc_lock);
+       list_splice(&list, &gc_list);
+       spin_unlock_bh(&gc_lock);
+
+       schedule_delayed_work(&gc_work, gc_delay);
+}
 
 /* Called from ip_output.c:ip_init  */
 void __init inet_initpeers(void)
@@ -126,6 +176,7 @@ void __init inet_initpeers(void)
                        0, SLAB_HWCACHE_ALIGN | SLAB_PANIC,
                        NULL);
 
+       INIT_DELAYED_WORK_DEFERRABLE(&gc_work, inetpeer_gc_worker);
 }
 
 static int addr_compare(const struct inetpeer_addr *a,
@@ -447,9 +498,8 @@ relookup:
                p->rate_last = 0;
                p->pmtu_expires = 0;
                p->pmtu_orig = 0;
-               p->redirect_genid = 0;
                memset(&p->redirect_learned, 0, sizeof(p->redirect_learned));
-
+               INIT_LIST_HEAD(&p->gc_list);
 
                /* Link the node. */
                link_to_pool(p, base);
@@ -509,3 +559,30 @@ bool inet_peer_xrlim_allow(struct inet_peer *peer, int timeout)
        return rc;
 }
 EXPORT_SYMBOL(inet_peer_xrlim_allow);
+
+void inetpeer_invalidate_tree(int family)
+{
+       struct inet_peer *old, *new, *prev;
+       struct inet_peer_base *base = family_to_base(family);
+
+       write_seqlock_bh(&base->lock);
+
+       old = base->root;
+       if (old == peer_avl_empty_rcu)
+               goto out;
+
+       new = peer_avl_empty_rcu;
+
+       prev = cmpxchg(&base->root, old, new);
+       if (prev == old) {
+               base->total = 0;
+               spin_lock(&gc_lock);
+               list_add_tail(&prev->gc_list, &gc_list);
+               spin_unlock(&gc_lock);
+               schedule_delayed_work(&gc_work, gc_delay);
+       }
+
+out:
+       write_sequnlock_bh(&base->lock);
+}
+EXPORT_SYMBOL(inetpeer_invalidate_tree);
index 073a9b01c40c9c37400ce9c320ffb355b0ae6e76..bdaa2c5c28e45fb081fa9890d26ebd5087ff2276 100644 (file)
 /*
  *     Process Router Attention IP option (RFC 2113)
  */
-int ip_call_ra_chain(struct sk_buff *skb)
+bool ip_call_ra_chain(struct sk_buff *skb)
 {
        struct ip_ra_chain *ra;
        u8 protocol = ip_hdr(skb)->protocol;
@@ -167,7 +167,7 @@ int ip_call_ra_chain(struct sk_buff *skb)
                    net_eq(sock_net(sk), dev_net(dev))) {
                        if (ip_is_fragment(ip_hdr(skb))) {
                                if (ip_defrag(skb, IP_DEFRAG_CALL_RA_CHAIN))
-                                       return 1;
+                                       return true;
                        }
                        if (last) {
                                struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
@@ -180,9 +180,9 @@ int ip_call_ra_chain(struct sk_buff *skb)
 
        if (last) {
                raw_rcv(last, skb);
-               return 1;
+               return true;
        }
-       return 0;
+       return false;
 }
 
 static int ip_local_deliver_finish(struct sk_buff *skb)
@@ -265,7 +265,7 @@ int ip_local_deliver(struct sk_buff *skb)
                       ip_local_deliver_finish);
 }
 
-static inline int ip_rcv_options(struct sk_buff *skb)
+static inline bool ip_rcv_options(struct sk_buff *skb)
 {
        struct ip_options *opt;
        const struct iphdr *iph;
@@ -309,9 +309,9 @@ static inline int ip_rcv_options(struct sk_buff *skb)
                        goto drop;
        }
 
-       return 0;
+       return false;
 drop:
-       return -1;
+       return true;
 }
 
 static int ip_rcv_finish(struct sk_buff *skb)
index 74dfc9e5211fa70827b3411dd6c5bceb5773dffa..fcc543cd987a3f22b45ea143c9c754019fa8bacd 100644 (file)
@@ -123,15 +123,6 @@ config IP_NF_TARGET_REJECT
 
          To compile it as a module, choose M here.  If unsure, say N.
 
-config IP_NF_TARGET_LOG
-       tristate "LOG target support"
-       default m if NETFILTER_ADVANCED=n
-       help
-         This option adds a `LOG' target, which allows you to create rules in
-         any iptables table which records the packet header to the syslog.
-
-         To compile it as a module, choose M here.  If unsure, say N.
-
 config IP_NF_TARGET_ULOG
        tristate "ULOG target support"
        default m if NETFILTER_ADVANCED=n
index 213a462b739bbd937ed511485db824aa94e7d26c..240b68469a7a178f990f07559f65ad46b2ae43f0 100644 (file)
@@ -54,7 +54,6 @@ obj-$(CONFIG_IP_NF_MATCH_RPFILTER) += ipt_rpfilter.o
 # targets
 obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o
 obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o
-obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
 obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
 obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o
 obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c
deleted file mode 100644 (file)
index d76d6c9..0000000
+++ /dev/null
@@ -1,516 +0,0 @@
-/*
- * This is a module which is used for logging packets.
- */
-
-/* (C) 1999-2001 Paul `Rusty' Russell
- * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/ip.h>
-#include <net/icmp.h>
-#include <net/udp.h>
-#include <net/tcp.h>
-#include <net/route.h>
-
-#include <linux/netfilter.h>
-#include <linux/netfilter/x_tables.h>
-#include <linux/netfilter_ipv4/ipt_LOG.h>
-#include <net/netfilter/nf_log.h>
-#include <net/netfilter/xt_log.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
-MODULE_DESCRIPTION("Xtables: IPv4 packet logging to syslog");
-
-/* One level of recursion won't kill us */
-static void dump_packet(struct sbuff *m,
-                       const struct nf_loginfo *info,
-                       const struct sk_buff *skb,
-                       unsigned int iphoff)
-{
-       struct iphdr _iph;
-       const struct iphdr *ih;
-       unsigned int logflags;
-
-       if (info->type == NF_LOG_TYPE_LOG)
-               logflags = info->u.log.logflags;
-       else
-               logflags = NF_LOG_MASK;
-
-       ih = skb_header_pointer(skb, iphoff, sizeof(_iph), &_iph);
-       if (ih == NULL) {
-               sb_add(m, "TRUNCATED");
-               return;
-       }
-
-       /* Important fields:
-        * TOS, len, DF/MF, fragment offset, TTL, src, dst, options. */
-       /* Max length: 40 "SRC=255.255.255.255 DST=255.255.255.255 " */
-       sb_add(m, "SRC=%pI4 DST=%pI4 ",
-              &ih->saddr, &ih->daddr);
-
-       /* Max length: 46 "LEN=65535 TOS=0xFF PREC=0xFF TTL=255 ID=65535 " */
-       sb_add(m, "LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ",
-              ntohs(ih->tot_len), ih->tos & IPTOS_TOS_MASK,
-              ih->tos & IPTOS_PREC_MASK, ih->ttl, ntohs(ih->id));
-
-       /* Max length: 6 "CE DF MF " */
-       if (ntohs(ih->frag_off) & IP_CE)
-               sb_add(m, "CE ");
-       if (ntohs(ih->frag_off) & IP_DF)
-               sb_add(m, "DF ");
-       if (ntohs(ih->frag_off) & IP_MF)
-               sb_add(m, "MF ");
-
-       /* Max length: 11 "FRAG:65535 " */
-       if (ntohs(ih->frag_off) & IP_OFFSET)
-               sb_add(m, "FRAG:%u ", ntohs(ih->frag_off) & IP_OFFSET);
-
-       if ((logflags & IPT_LOG_IPOPT) &&
-           ih->ihl * 4 > sizeof(struct iphdr)) {
-               const unsigned char *op;
-               unsigned char _opt[4 * 15 - sizeof(struct iphdr)];
-               unsigned int i, optsize;
-
-               optsize = ih->ihl * 4 - sizeof(struct iphdr);
-               op = skb_header_pointer(skb, iphoff+sizeof(_iph),
-                                       optsize, _opt);
-               if (op == NULL) {
-                       sb_add(m, "TRUNCATED");
-                       return;
-               }
-
-               /* Max length: 127 "OPT (" 15*4*2chars ") " */
-               sb_add(m, "OPT (");
-               for (i = 0; i < optsize; i++)
-                       sb_add(m, "%02X", op[i]);
-               sb_add(m, ") ");
-       }
-
-       switch (ih->protocol) {
-       case IPPROTO_TCP: {
-               struct tcphdr _tcph;
-               const struct tcphdr *th;
-
-               /* Max length: 10 "PROTO=TCP " */
-               sb_add(m, "PROTO=TCP ");
-
-               if (ntohs(ih->frag_off) & IP_OFFSET)
-                       break;
-
-               /* Max length: 25 "INCOMPLETE [65535 bytes] " */
-               th = skb_header_pointer(skb, iphoff + ih->ihl * 4,
-                                       sizeof(_tcph), &_tcph);
-               if (th == NULL) {
-                       sb_add(m, "INCOMPLETE [%u bytes] ",
-                              skb->len - iphoff - ih->ihl*4);
-                       break;
-               }
-
-               /* Max length: 20 "SPT=65535 DPT=65535 " */
-               sb_add(m, "SPT=%u DPT=%u ",
-                      ntohs(th->source), ntohs(th->dest));
-               /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */
-               if (logflags & IPT_LOG_TCPSEQ)
-                       sb_add(m, "SEQ=%u ACK=%u ",
-                              ntohl(th->seq), ntohl(th->ack_seq));
-               /* Max length: 13 "WINDOW=65535 " */
-               sb_add(m, "WINDOW=%u ", ntohs(th->window));
-               /* Max length: 9 "RES=0x3F " */
-               sb_add(m, "RES=0x%02x ", (u8)(ntohl(tcp_flag_word(th) & TCP_RESERVED_BITS) >> 22));
-               /* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */
-               if (th->cwr)
-                       sb_add(m, "CWR ");
-               if (th->ece)
-                       sb_add(m, "ECE ");
-               if (th->urg)
-                       sb_add(m, "URG ");
-               if (th->ack)
-                       sb_add(m, "ACK ");
-               if (th->psh)
-                       sb_add(m, "PSH ");
-               if (th->rst)
-                       sb_add(m, "RST ");
-               if (th->syn)
-                       sb_add(m, "SYN ");
-               if (th->fin)
-                       sb_add(m, "FIN ");
-               /* Max length: 11 "URGP=65535 " */
-               sb_add(m, "URGP=%u ", ntohs(th->urg_ptr));
-
-               if ((logflags & IPT_LOG_TCPOPT) &&
-                   th->doff * 4 > sizeof(struct tcphdr)) {
-                       unsigned char _opt[4 * 15 - sizeof(struct tcphdr)];
-                       const unsigned char *op;
-                       unsigned int i, optsize;
-
-                       optsize = th->doff * 4 - sizeof(struct tcphdr);
-                       op = skb_header_pointer(skb,
-                                               iphoff+ih->ihl*4+sizeof(_tcph),
-                                               optsize, _opt);
-                       if (op == NULL) {
-                               sb_add(m, "TRUNCATED");
-                               return;
-                       }
-
-                       /* Max length: 127 "OPT (" 15*4*2chars ") " */
-                       sb_add(m, "OPT (");
-                       for (i = 0; i < optsize; i++)
-                               sb_add(m, "%02X", op[i]);
-                       sb_add(m, ") ");
-               }
-               break;
-       }
-       case IPPROTO_UDP:
-       case IPPROTO_UDPLITE: {
-               struct udphdr _udph;
-               const struct udphdr *uh;
-
-               if (ih->protocol == IPPROTO_UDP)
-                       /* Max length: 10 "PROTO=UDP "     */
-                       sb_add(m, "PROTO=UDP " );
-               else    /* Max length: 14 "PROTO=UDPLITE " */
-                       sb_add(m, "PROTO=UDPLITE ");
-
-               if (ntohs(ih->frag_off) & IP_OFFSET)
-                       break;
-
-               /* Max length: 25 "INCOMPLETE [65535 bytes] " */
-               uh = skb_header_pointer(skb, iphoff+ih->ihl*4,
-                                       sizeof(_udph), &_udph);
-               if (uh == NULL) {
-                       sb_add(m, "INCOMPLETE [%u bytes] ",
-                              skb->len - iphoff - ih->ihl*4);
-                       break;
-               }
-
-               /* Max length: 20 "SPT=65535 DPT=65535 " */
-               sb_add(m, "SPT=%u DPT=%u LEN=%u ",
-                      ntohs(uh->source), ntohs(uh->dest),
-                      ntohs(uh->len));
-               break;
-       }
-       case IPPROTO_ICMP: {
-               struct icmphdr _icmph;
-               const struct icmphdr *ich;
-               static const size_t required_len[NR_ICMP_TYPES+1]
-                       = { [ICMP_ECHOREPLY] = 4,
-                           [ICMP_DEST_UNREACH]
-                           = 8 + sizeof(struct iphdr),
-                           [ICMP_SOURCE_QUENCH]
-                           = 8 + sizeof(struct iphdr),
-                           [ICMP_REDIRECT]
-                           = 8 + sizeof(struct iphdr),
-                           [ICMP_ECHO] = 4,
-                           [ICMP_TIME_EXCEEDED]
-                           = 8 + sizeof(struct iphdr),
-                           [ICMP_PARAMETERPROB]
-                           = 8 + sizeof(struct iphdr),
-                           [ICMP_TIMESTAMP] = 20,
-                           [ICMP_TIMESTAMPREPLY] = 20,
-                           [ICMP_ADDRESS] = 12,
-                           [ICMP_ADDRESSREPLY] = 12 };
-
-               /* Max length: 11 "PROTO=ICMP " */
-               sb_add(m, "PROTO=ICMP ");
-
-               if (ntohs(ih->frag_off) & IP_OFFSET)
-                       break;
-
-               /* Max length: 25 "INCOMPLETE [65535 bytes] " */
-               ich = skb_header_pointer(skb, iphoff + ih->ihl * 4,
-                                        sizeof(_icmph), &_icmph);
-               if (ich == NULL) {
-                       sb_add(m, "INCOMPLETE [%u bytes] ",
-                              skb->len - iphoff - ih->ihl*4);
-                       break;
-               }
-
-               /* Max length: 18 "TYPE=255 CODE=255 " */
-               sb_add(m, "TYPE=%u CODE=%u ", ich->type, ich->code);
-
-               /* Max length: 25 "INCOMPLETE [65535 bytes] " */
-               if (ich->type <= NR_ICMP_TYPES &&
-                   required_len[ich->type] &&
-                   skb->len-iphoff-ih->ihl*4 < required_len[ich->type]) {
-                       sb_add(m, "INCOMPLETE [%u bytes] ",
-                              skb->len - iphoff - ih->ihl*4);
-                       break;
-               }
-
-               switch (ich->type) {
-               case ICMP_ECHOREPLY:
-               case ICMP_ECHO:
-                       /* Max length: 19 "ID=65535 SEQ=65535 " */
-                       sb_add(m, "ID=%u SEQ=%u ",
-                              ntohs(ich->un.echo.id),
-                              ntohs(ich->un.echo.sequence));
-                       break;
-
-               case ICMP_PARAMETERPROB:
-                       /* Max length: 14 "PARAMETER=255 " */
-                       sb_add(m, "PARAMETER=%u ",
-                              ntohl(ich->un.gateway) >> 24);
-                       break;
-               case ICMP_REDIRECT:
-                       /* Max length: 24 "GATEWAY=255.255.255.255 " */
-                       sb_add(m, "GATEWAY=%pI4 ", &ich->un.gateway);
-                       /* Fall through */
-               case ICMP_DEST_UNREACH:
-               case ICMP_SOURCE_QUENCH:
-               case ICMP_TIME_EXCEEDED:
-                       /* Max length: 3+maxlen */
-                       if (!iphoff) { /* Only recurse once. */
-                               sb_add(m, "[");
-                               dump_packet(m, info, skb,
-                                           iphoff + ih->ihl*4+sizeof(_icmph));
-                               sb_add(m, "] ");
-                       }
-
-                       /* Max length: 10 "MTU=65535 " */
-                       if (ich->type == ICMP_DEST_UNREACH &&
-                           ich->code == ICMP_FRAG_NEEDED)
-                               sb_add(m, "MTU=%u ", ntohs(ich->un.frag.mtu));
-               }
-               break;
-       }
-       /* Max Length */
-       case IPPROTO_AH: {
-               struct ip_auth_hdr _ahdr;
-               const struct ip_auth_hdr *ah;
-
-               if (ntohs(ih->frag_off) & IP_OFFSET)
-                       break;
-
-               /* Max length: 9 "PROTO=AH " */
-               sb_add(m, "PROTO=AH ");
-
-               /* Max length: 25 "INCOMPLETE [65535 bytes] " */
-               ah = skb_header_pointer(skb, iphoff+ih->ihl*4,
-                                       sizeof(_ahdr), &_ahdr);
-               if (ah == NULL) {
-                       sb_add(m, "INCOMPLETE [%u bytes] ",
-                              skb->len - iphoff - ih->ihl*4);
-                       break;
-               }
-
-               /* Length: 15 "SPI=0xF1234567 " */
-               sb_add(m, "SPI=0x%x ", ntohl(ah->spi));
-               break;
-       }
-       case IPPROTO_ESP: {
-               struct ip_esp_hdr _esph;
-               const struct ip_esp_hdr *eh;
-
-               /* Max length: 10 "PROTO=ESP " */
-               sb_add(m, "PROTO=ESP ");
-
-               if (ntohs(ih->frag_off) & IP_OFFSET)
-                       break;
-
-               /* Max length: 25 "INCOMPLETE [65535 bytes] " */
-               eh = skb_header_pointer(skb, iphoff+ih->ihl*4,
-                                       sizeof(_esph), &_esph);
-               if (eh == NULL) {
-                       sb_add(m, "INCOMPLETE [%u bytes] ",
-                              skb->len - iphoff - ih->ihl*4);
-                       break;
-               }
-
-               /* Length: 15 "SPI=0xF1234567 " */
-               sb_add(m, "SPI=0x%x ", ntohl(eh->spi));
-               break;
-       }
-       /* Max length: 10 "PROTO 255 " */
-       default:
-               sb_add(m, "PROTO=%u ", ih->protocol);
-       }
-
-       /* Max length: 15 "UID=4294967295 " */
-       if ((logflags & IPT_LOG_UID) && !iphoff && skb->sk) {
-               read_lock_bh(&skb->sk->sk_callback_lock);
-               if (skb->sk->sk_socket && skb->sk->sk_socket->file)
-                       sb_add(m, "UID=%u GID=%u ",
-                               skb->sk->sk_socket->file->f_cred->fsuid,
-                               skb->sk->sk_socket->file->f_cred->fsgid);
-               read_unlock_bh(&skb->sk->sk_callback_lock);
-       }
-
-       /* Max length: 16 "MARK=0xFFFFFFFF " */
-       if (!iphoff && skb->mark)
-               sb_add(m, "MARK=0x%x ", skb->mark);
-
-       /* Proto    Max log string length */
-       /* IP:      40+46+6+11+127 = 230 */
-       /* TCP:     10+max(25,20+30+13+9+32+11+127) = 252 */
-       /* UDP:     10+max(25,20) = 35 */
-       /* UDPLITE: 14+max(25,20) = 39 */
-       /* ICMP:    11+max(25, 18+25+max(19,14,24+3+n+10,3+n+10)) = 91+n */
-       /* ESP:     10+max(25)+15 = 50 */
-       /* AH:      9+max(25)+15 = 49 */
-       /* unknown: 10 */
-
-       /* (ICMP allows recursion one level deep) */
-       /* maxlen =  IP + ICMP +  IP + max(TCP,UDP,ICMP,unknown) */
-       /* maxlen = 230+   91  + 230 + 252 = 803 */
-}
-
-static void dump_mac_header(struct sbuff *m,
-                           const struct nf_loginfo *info,
-                           const struct sk_buff *skb)
-{
-       struct net_device *dev = skb->dev;
-       unsigned int logflags = 0;
-
-       if (info->type == NF_LOG_TYPE_LOG)
-               logflags = info->u.log.logflags;
-
-       if (!(logflags & IPT_LOG_MACDECODE))
-               goto fallback;
-
-       switch (dev->type) {
-       case ARPHRD_ETHER:
-               sb_add(m, "MACSRC=%pM MACDST=%pM MACPROTO=%04x ",
-                      eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest,
-                      ntohs(eth_hdr(skb)->h_proto));
-               return;
-       default:
-               break;
-       }
-
-fallback:
-       sb_add(m, "MAC=");
-       if (dev->hard_header_len &&
-           skb->mac_header != skb->network_header) {
-               const unsigned char *p = skb_mac_header(skb);
-               unsigned int i;
-
-               sb_add(m, "%02x", *p++);
-               for (i = 1; i < dev->hard_header_len; i++, p++)
-                       sb_add(m, ":%02x", *p);
-       }
-       sb_add(m, " ");
-}
-
-static struct nf_loginfo default_loginfo = {
-       .type   = NF_LOG_TYPE_LOG,
-       .u = {
-               .log = {
-                       .level    = 5,
-                       .logflags = NF_LOG_MASK,
-               },
-       },
-};
-
-static void
-ipt_log_packet(u_int8_t pf,
-              unsigned int hooknum,
-              const struct sk_buff *skb,
-              const struct net_device *in,
-              const struct net_device *out,
-              const struct nf_loginfo *loginfo,
-              const char *prefix)
-{
-       struct sbuff *m = sb_open();
-
-       if (!loginfo)
-               loginfo = &default_loginfo;
-
-       sb_add(m, "<%d>%sIN=%s OUT=%s ", loginfo->u.log.level,
-              prefix,
-              in ? in->name : "",
-              out ? out->name : "");
-#ifdef CONFIG_BRIDGE_NETFILTER
-       if (skb->nf_bridge) {
-               const struct net_device *physindev;
-               const struct net_device *physoutdev;
-
-               physindev = skb->nf_bridge->physindev;
-               if (physindev && in != physindev)
-                       sb_add(m, "PHYSIN=%s ", physindev->name);
-               physoutdev = skb->nf_bridge->physoutdev;
-               if (physoutdev && out != physoutdev)
-                       sb_add(m, "PHYSOUT=%s ", physoutdev->name);
-       }
-#endif
-
-       if (in != NULL)
-               dump_mac_header(m, loginfo, skb);
-
-       dump_packet(m, loginfo, skb, 0);
-
-       sb_close(m);
-}
-
-static unsigned int
-log_tg(struct sk_buff *skb, const struct xt_action_param *par)
-{
-       const struct ipt_log_info *loginfo = par->targinfo;
-       struct nf_loginfo li;
-
-       li.type = NF_LOG_TYPE_LOG;
-       li.u.log.level = loginfo->level;
-       li.u.log.logflags = loginfo->logflags;
-
-       ipt_log_packet(NFPROTO_IPV4, par->hooknum, skb, par->in, par->out, &li,
-                      loginfo->prefix);
-       return XT_CONTINUE;
-}
-
-static int log_tg_check(const struct xt_tgchk_param *par)
-{
-       const struct ipt_log_info *loginfo = par->targinfo;
-
-       if (loginfo->level >= 8) {
-               pr_debug("level %u >= 8\n", loginfo->level);
-               return -EINVAL;
-       }
-       if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') {
-               pr_debug("prefix is not null-terminated\n");
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static struct xt_target log_tg_reg __read_mostly = {
-       .name           = "LOG",
-       .family         = NFPROTO_IPV4,
-       .target         = log_tg,
-       .targetsize     = sizeof(struct ipt_log_info),
-       .checkentry     = log_tg_check,
-       .me             = THIS_MODULE,
-};
-
-static struct nf_logger ipt_log_logger __read_mostly = {
-       .name           = "ipt_LOG",
-       .logfn          = &ipt_log_packet,
-       .me             = THIS_MODULE,
-};
-
-static int __init log_tg_init(void)
-{
-       int ret;
-
-       ret = xt_register_target(&log_tg_reg);
-       if (ret < 0)
-               return ret;
-       nf_log_register(NFPROTO_IPV4, &ipt_log_logger);
-       return 0;
-}
-
-static void __exit log_tg_exit(void)
-{
-       nf_log_unregister(&ipt_log_logger);
-       xt_unregister_target(&log_tg_reg);
-}
-
-module_init(log_tg_init);
-module_exit(log_tg_exit);
index ab5b27a2916f70b79430f1a90ac7d7af6cceaebe..7cbe9cb261c29d44907760b7d51f0d95a9d64b27 100644 (file)
@@ -75,25 +75,31 @@ static int icmp_print_tuple(struct seq_file *s,
                          ntohs(tuple->src.u.icmp.id));
 }
 
+static unsigned int *icmp_get_timeouts(struct net *net)
+{
+       return &nf_ct_icmp_timeout;
+}
+
 /* Returns verdict for packet, or -1 for invalid. */
 static int icmp_packet(struct nf_conn *ct,
                       const struct sk_buff *skb,
                       unsigned int dataoff,
                       enum ip_conntrack_info ctinfo,
                       u_int8_t pf,
-                      unsigned int hooknum)
+                      unsigned int hooknum,
+                      unsigned int *timeout)
 {
        /* Do not immediately delete the connection after the first
           successful reply to avoid excessive conntrackd traffic
           and also to handle correctly ICMP echo reply duplicates. */
-       nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmp_timeout);
+       nf_ct_refresh_acct(ct, ctinfo, skb, *timeout);
 
        return NF_ACCEPT;
 }
 
 /* Called when a new connection for this protocol found. */
 static bool icmp_new(struct nf_conn *ct, const struct sk_buff *skb,
-                    unsigned int dataoff)
+                    unsigned int dataoff, unsigned int *timeouts)
 {
        static const u_int8_t valid_new[] = {
                [ICMP_ECHO] = 1,
@@ -263,6 +269,44 @@ static int icmp_nlattr_tuple_size(void)
 }
 #endif
 
+#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
+
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nfnetlink_cttimeout.h>
+
+static int icmp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
+{
+       unsigned int *timeout = data;
+
+       if (tb[CTA_TIMEOUT_ICMP_TIMEOUT]) {
+               *timeout =
+                       ntohl(nla_get_be32(tb[CTA_TIMEOUT_ICMP_TIMEOUT])) * HZ;
+       } else {
+               /* Set default ICMP timeout. */
+               *timeout = nf_ct_icmp_timeout;
+       }
+       return 0;
+}
+
+static int
+icmp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
+{
+       const unsigned int *timeout = data;
+
+       NLA_PUT_BE32(skb, CTA_TIMEOUT_ICMP_TIMEOUT, htonl(*timeout / HZ));
+
+       return 0;
+
+nla_put_failure:
+       return -ENOSPC;
+}
+
+static const struct nla_policy
+icmp_timeout_nla_policy[CTA_TIMEOUT_ICMP_MAX+1] = {
+       [CTA_TIMEOUT_ICMP_TIMEOUT]      = { .type = NLA_U32 },
+};
+#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
+
 #ifdef CONFIG_SYSCTL
 static struct ctl_table_header *icmp_sysctl_header;
 static struct ctl_table icmp_sysctl_table[] = {
@@ -298,6 +342,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp __read_mostly =
        .invert_tuple           = icmp_invert_tuple,
        .print_tuple            = icmp_print_tuple,
        .packet                 = icmp_packet,
+       .get_timeouts           = icmp_get_timeouts,
        .new                    = icmp_new,
        .error                  = icmp_error,
        .destroy                = NULL,
@@ -308,6 +353,15 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp __read_mostly =
        .nlattr_to_tuple        = icmp_nlattr_to_tuple,
        .nla_policy             = icmp_nla_policy,
 #endif
+#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
+       .ctnl_timeout           = {
+               .nlattr_to_obj  = icmp_timeout_nlattr_to_obj,
+               .obj_to_nlattr  = icmp_timeout_obj_to_nlattr,
+               .nlattr_max     = CTA_TIMEOUT_ICMP_MAX,
+               .obj_size       = sizeof(unsigned int),
+               .nla_policy     = icmp_timeout_nla_policy,
+       },
+#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 #ifdef CONFIG_SYSCTL
        .ctl_table_header       = &icmp_sysctl_header,
        .ctl_table              = icmp_sysctl_table,
index a708933dc2304959bb3192e4fc49d44e4a2f3fa1..abb52adf5acdfdda9f816cb4e336ad9137452396 100644 (file)
@@ -686,6 +686,11 @@ static struct pernet_operations nf_nat_net_ops = {
        .exit = nf_nat_net_exit,
 };
 
+static struct nf_ct_helper_expectfn follow_master_nat = {
+       .name           = "nat-follow-master",
+       .expectfn       = nf_nat_follow_master,
+};
+
 static int __init nf_nat_init(void)
 {
        size_t i;
@@ -717,6 +722,8 @@ static int __init nf_nat_init(void)
 
        l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET);
 
+       nf_ct_helper_expectfn_register(&follow_master_nat);
+
        BUG_ON(nf_nat_seq_adjust_hook != NULL);
        RCU_INIT_POINTER(nf_nat_seq_adjust_hook, nf_nat_seq_adjust);
        BUG_ON(nfnetlink_parse_nat_setup_hook != NULL);
@@ -736,6 +743,7 @@ static void __exit nf_nat_cleanup(void)
        unregister_pernet_subsys(&nf_nat_net_ops);
        nf_ct_l3proto_put(l3proto);
        nf_ct_extend_unregister(&nat_extend);
+       nf_ct_helper_expectfn_unregister(&follow_master_nat);
        RCU_INIT_POINTER(nf_nat_seq_adjust_hook, NULL);
        RCU_INIT_POINTER(nfnetlink_parse_nat_setup_hook, NULL);
        RCU_INIT_POINTER(nf_ct_nat_offset, NULL);
index dc1dd912baf4689df151a0756425f6bde4151cd4..82536701e3a39fb1fab54e1636999b0c4c18d35f 100644 (file)
@@ -568,6 +568,16 @@ static int nat_callforwarding(struct sk_buff *skb, struct nf_conn *ct,
        return 0;
 }
 
+static struct nf_ct_helper_expectfn q931_nat = {
+       .name           = "Q.931",
+       .expectfn       = ip_nat_q931_expect,
+};
+
+static struct nf_ct_helper_expectfn callforwarding_nat = {
+       .name           = "callforwarding",
+       .expectfn       = ip_nat_callforwarding_expect,
+};
+
 /****************************************************************************/
 static int __init init(void)
 {
@@ -590,6 +600,8 @@ static int __init init(void)
        RCU_INIT_POINTER(nat_h245_hook, nat_h245);
        RCU_INIT_POINTER(nat_callforwarding_hook, nat_callforwarding);
        RCU_INIT_POINTER(nat_q931_hook, nat_q931);
+       nf_ct_helper_expectfn_register(&q931_nat);
+       nf_ct_helper_expectfn_register(&callforwarding_nat);
        return 0;
 }
 
@@ -605,6 +617,8 @@ static void __exit fini(void)
        RCU_INIT_POINTER(nat_h245_hook, NULL);
        RCU_INIT_POINTER(nat_callforwarding_hook, NULL);
        RCU_INIT_POINTER(nat_q931_hook, NULL);
+       nf_ct_helper_expectfn_unregister(&q931_nat);
+       nf_ct_helper_expectfn_unregister(&callforwarding_nat);
        synchronize_rcu();
 }
 
index d0319f96269fb88384dcf5a64205761589b2e791..57932c43960ec27d32c55f6986ee28c74b138482 100644 (file)
@@ -526,6 +526,11 @@ err1:
        return NF_DROP;
 }
 
+static struct nf_ct_helper_expectfn sip_nat = {
+        .name           = "sip",
+        .expectfn       = ip_nat_sip_expected,
+};
+
 static void __exit nf_nat_sip_fini(void)
 {
        RCU_INIT_POINTER(nf_nat_sip_hook, NULL);
@@ -535,6 +540,7 @@ static void __exit nf_nat_sip_fini(void)
        RCU_INIT_POINTER(nf_nat_sdp_port_hook, NULL);
        RCU_INIT_POINTER(nf_nat_sdp_session_hook, NULL);
        RCU_INIT_POINTER(nf_nat_sdp_media_hook, NULL);
+       nf_ct_helper_expectfn_unregister(&sip_nat);
        synchronize_rcu();
 }
 
@@ -554,6 +560,7 @@ static int __init nf_nat_sip_init(void)
        RCU_INIT_POINTER(nf_nat_sdp_port_hook, ip_nat_sdp_port);
        RCU_INIT_POINTER(nf_nat_sdp_session_hook, ip_nat_sdp_session);
        RCU_INIT_POINTER(nf_nat_sdp_media_hook, ip_nat_sdp_media);
+       nf_ct_helper_expectfn_register(&sip_nat);
        return 0;
 }
 
index 0489cedc1671dba81fa9851db8c81d79f9437481..815989b90dea2df70d865ce0958442d4bd5bb8f9 100644 (file)
@@ -132,7 +132,6 @@ static int ip_rt_mtu_expires __read_mostly  = 10 * 60 * HZ;
 static int ip_rt_min_pmtu __read_mostly                = 512 + 20 + 20;
 static int ip_rt_min_advmss __read_mostly      = 256;
 static int rt_chain_length_max __read_mostly   = 20;
-static int redirect_genid;
 
 static struct delayed_work expires_work;
 static unsigned long expires_ljiffies;
@@ -937,7 +936,7 @@ static void rt_cache_invalidate(struct net *net)
 
        get_random_bytes(&shuffle, sizeof(shuffle));
        atomic_add(shuffle + 1U, &net->ipv4.rt_genid);
-       redirect_genid++;
+       inetpeer_invalidate_tree(AF_INET);
 }
 
 /*
@@ -1490,10 +1489,8 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
 
                                peer = rt->peer;
                                if (peer) {
-                                       if (peer->redirect_learned.a4 != new_gw ||
-                                           peer->redirect_genid != redirect_genid) {
+                                       if (peer->redirect_learned.a4 != new_gw) {
                                                peer->redirect_learned.a4 = new_gw;
-                                               peer->redirect_genid = redirect_genid;
                                                atomic_inc(&__rt_peer_genid);
                                        }
                                        check_peer_redir(&rt->dst, peer);
@@ -1798,8 +1795,6 @@ static void ipv4_validate_peer(struct rtable *rt)
                if (peer) {
                        check_peer_pmtu(&rt->dst, peer);
 
-                       if (peer->redirect_genid != redirect_genid)
-                               peer->redirect_learned.a4 = 0;
                        if (peer->redirect_learned.a4 &&
                            peer->redirect_learned.a4 != rt->rt_gateway)
                                check_peer_redir(&rt->dst, peer);
@@ -1963,8 +1958,7 @@ static void rt_init_metrics(struct rtable *rt, const struct flowi4 *fl4,
                dst_init_metrics(&rt->dst, peer->metrics, false);
 
                check_peer_pmtu(&rt->dst, peer);
-               if (peer->redirect_genid != redirect_genid)
-                       peer->redirect_learned.a4 = 0;
+
                if (peer->redirect_learned.a4 &&
                    peer->redirect_learned.a4 != rt->rt_gateway) {
                        rt->rt_gateway = peer->redirect_learned.a4;
index ee42d42b2f45ed9164857b6ce89d3cadb510a7d9..b5e315f13641d683c2ab9031c0d52969c6c0873a 100644 (file)
@@ -1585,6 +1585,10 @@ static struct sk_buff *tcp_shift_skb_data(struct sock *sk, struct sk_buff *skb,
                }
        }
 
+       /* tcp_sacktag_one() won't SACK-tag ranges below snd_una */
+       if (!after(TCP_SKB_CB(skb)->seq + len, tp->snd_una))
+               goto fallback;
+
        if (!skb_shift(prev, skb, len))
                goto fallback;
        if (!tcp_shifted_skb(sk, skb, state, pcount, len, mss, dup_sack))
@@ -2569,6 +2573,7 @@ static void tcp_mark_head_lost(struct sock *sk, int packets, int mark_head)
 
                if (cnt > packets) {
                        if ((tcp_is_sack(tp) && !tcp_is_fack(tp)) ||
+                           (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED) ||
                            (oldcnt >= packets))
                                break;
 
index 94abee8cf563d68184db984004caf75a91fa4dcc..507924b640ef2bbc758e54e6ae874418f54bf84d 100644 (file)
@@ -927,7 +927,8 @@ struct tcp_md5sig_key *tcp_md5_do_lookup(struct sock *sk,
 
        /* caller either holds rcu_read_lock() or socket lock */
        md5sig = rcu_dereference_check(tp->md5sig_info,
-                                      sock_owned_by_user(sk));
+                                      sock_owned_by_user(sk) ||
+                                      lockdep_is_held(&sk->sk_lock.slock));
        if (!md5sig)
                return NULL;
 #if IS_ENABLED(CONFIG_IPV6)
index c02280a4d126980540daac44a8b541b92c0b16f0..6b8ebc5da0e1344ad58994e327ba42cac44f3ac3 100644 (file)
@@ -434,6 +434,10 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
        /* Join all-node multicast group */
        ipv6_dev_mc_inc(dev, &in6addr_linklocal_allnodes);
 
+       /* Join all-router multicast group if forwarding is set */
+       if (ndev->cnf.forwarding && dev && (dev->flags & IFF_MULTICAST))
+               ipv6_dev_mc_inc(dev, &in6addr_linklocal_allrouters);
+
        return ndev;
 }
 
index 9a68fb5b9e77f47a2d8fa89d4d234edff805526b..d33cddd16fbb6a720217a9db1f1eef353f990fcb 100644 (file)
@@ -154,15 +154,6 @@ config IP6_NF_TARGET_HL
        (e.g. when running oldconfig). It selects
        CONFIG_NETFILTER_XT_TARGET_HL.
 
-config IP6_NF_TARGET_LOG
-       tristate "LOG target support"
-       default m if NETFILTER_ADVANCED=n
-       help
-         This option adds a `LOG' target, which allows you to create rules in
-         any iptables table which records the packet header to the syslog.
-
-         To compile it as a module, choose M here.  If unsure, say N.
-
 config IP6_NF_FILTER
        tristate "Packet filtering"
        default m if NETFILTER_ADVANCED=n
index 2eaed96db02c4fe203efedad2a2b6c20350781ff..d4dfd0a21097b053c2d646b10104473e27f05ae8 100644 (file)
@@ -31,5 +31,4 @@ obj-$(CONFIG_IP6_NF_MATCH_RPFILTER) += ip6t_rpfilter.o
 obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
 
 # targets
-obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
 obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o
diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c
deleted file mode 100644 (file)
index e6af8d7..0000000
+++ /dev/null
@@ -1,527 +0,0 @@
-/*
- * This is a module which is used for logging packets.
- */
-
-/* (C) 2001 Jan Rekorajski <baggins@pld.org.pl>
- * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/ip.h>
-#include <linux/spinlock.h>
-#include <linux/icmpv6.h>
-#include <net/udp.h>
-#include <net/tcp.h>
-#include <net/ipv6.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter/x_tables.h>
-#include <linux/netfilter_ipv6/ip6_tables.h>
-#include <net/netfilter/nf_log.h>
-#include <net/netfilter/xt_log.h>
-
-MODULE_AUTHOR("Jan Rekorajski <baggins@pld.org.pl>");
-MODULE_DESCRIPTION("Xtables: IPv6 packet logging to syslog");
-MODULE_LICENSE("GPL");
-
-struct in_device;
-#include <net/route.h>
-#include <linux/netfilter_ipv6/ip6t_LOG.h>
-
-/* One level of recursion won't kill us */
-static void dump_packet(struct sbuff *m,
-                       const struct nf_loginfo *info,
-                       const struct sk_buff *skb, unsigned int ip6hoff,
-                       int recurse)
-{
-       u_int8_t currenthdr;
-       int fragment;
-       struct ipv6hdr _ip6h;
-       const struct ipv6hdr *ih;
-       unsigned int ptr;
-       unsigned int hdrlen = 0;
-       unsigned int logflags;
-
-       if (info->type == NF_LOG_TYPE_LOG)
-               logflags = info->u.log.logflags;
-       else
-               logflags = NF_LOG_MASK;
-
-       ih = skb_header_pointer(skb, ip6hoff, sizeof(_ip6h), &_ip6h);
-       if (ih == NULL) {
-               sb_add(m, "TRUNCATED");
-               return;
-       }
-
-       /* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000 " */
-       sb_add(m, "SRC=%pI6 DST=%pI6 ", &ih->saddr, &ih->daddr);
-
-       /* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */
-       sb_add(m, "LEN=%Zu TC=%u HOPLIMIT=%u FLOWLBL=%u ",
-              ntohs(ih->payload_len) + sizeof(struct ipv6hdr),
-              (ntohl(*(__be32 *)ih) & 0x0ff00000) >> 20,
-              ih->hop_limit,
-              (ntohl(*(__be32 *)ih) & 0x000fffff));
-
-       fragment = 0;
-       ptr = ip6hoff + sizeof(struct ipv6hdr);
-       currenthdr = ih->nexthdr;
-       while (currenthdr != NEXTHDR_NONE && ip6t_ext_hdr(currenthdr)) {
-               struct ipv6_opt_hdr _hdr;
-               const struct ipv6_opt_hdr *hp;
-
-               hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
-               if (hp == NULL) {
-                       sb_add(m, "TRUNCATED");
-                       return;
-               }
-
-               /* Max length: 48 "OPT (...) " */
-               if (logflags & IP6T_LOG_IPOPT)
-                       sb_add(m, "OPT ( ");
-
-               switch (currenthdr) {
-               case IPPROTO_FRAGMENT: {
-                       struct frag_hdr _fhdr;
-                       const struct frag_hdr *fh;
-
-                       sb_add(m, "FRAG:");
-                       fh = skb_header_pointer(skb, ptr, sizeof(_fhdr),
-                                               &_fhdr);
-                       if (fh == NULL) {
-                               sb_add(m, "TRUNCATED ");
-                               return;
-                       }
-
-                       /* Max length: 6 "65535 " */
-                       sb_add(m, "%u ", ntohs(fh->frag_off) & 0xFFF8);
-
-                       /* Max length: 11 "INCOMPLETE " */
-                       if (fh->frag_off & htons(0x0001))
-                               sb_add(m, "INCOMPLETE ");
-
-                       sb_add(m, "ID:%08x ", ntohl(fh->identification));
-
-                       if (ntohs(fh->frag_off) & 0xFFF8)
-                               fragment = 1;
-
-                       hdrlen = 8;
-
-                       break;
-               }
-               case IPPROTO_DSTOPTS:
-               case IPPROTO_ROUTING:
-               case IPPROTO_HOPOPTS:
-                       if (fragment) {
-                               if (logflags & IP6T_LOG_IPOPT)
-                                       sb_add(m, ")");
-                               return;
-                       }
-                       hdrlen = ipv6_optlen(hp);
-                       break;
-               /* Max Length */
-               case IPPROTO_AH:
-                       if (logflags & IP6T_LOG_IPOPT) {
-                               struct ip_auth_hdr _ahdr;
-                               const struct ip_auth_hdr *ah;
-
-                               /* Max length: 3 "AH " */
-                               sb_add(m, "AH ");
-
-                               if (fragment) {
-                                       sb_add(m, ")");
-                                       return;
-                               }
-
-                               ah = skb_header_pointer(skb, ptr, sizeof(_ahdr),
-                                                       &_ahdr);
-                               if (ah == NULL) {
-                                       /*
-                                        * Max length: 26 "INCOMPLETE [65535
-                                        *  bytes] )"
-                                        */
-                                       sb_add(m, "INCOMPLETE [%u bytes] )",
-                                              skb->len - ptr);
-                                       return;
-                               }
-
-                               /* Length: 15 "SPI=0xF1234567 */
-                               sb_add(m, "SPI=0x%x ", ntohl(ah->spi));
-
-                       }
-
-                       hdrlen = (hp->hdrlen+2)<<2;
-                       break;
-               case IPPROTO_ESP:
-                       if (logflags & IP6T_LOG_IPOPT) {
-                               struct ip_esp_hdr _esph;
-                               const struct ip_esp_hdr *eh;
-
-                               /* Max length: 4 "ESP " */
-                               sb_add(m, "ESP ");
-
-                               if (fragment) {
-                                       sb_add(m, ")");
-                                       return;
-                               }
-
-                               /*
-                                * Max length: 26 "INCOMPLETE [65535 bytes] )"
-                                */
-                               eh = skb_header_pointer(skb, ptr, sizeof(_esph),
-                                                       &_esph);
-                               if (eh == NULL) {
-                                       sb_add(m, "INCOMPLETE [%u bytes] )",
-                                              skb->len - ptr);
-                                       return;
-                               }
-
-                               /* Length: 16 "SPI=0xF1234567 )" */
-                               sb_add(m, "SPI=0x%x )", ntohl(eh->spi) );
-
-                       }
-                       return;
-               default:
-                       /* Max length: 20 "Unknown Ext Hdr 255" */
-                       sb_add(m, "Unknown Ext Hdr %u", currenthdr);
-                       return;
-               }
-               if (logflags & IP6T_LOG_IPOPT)
-                       sb_add(m, ") ");
-
-               currenthdr = hp->nexthdr;
-               ptr += hdrlen;
-       }
-
-       switch (currenthdr) {
-       case IPPROTO_TCP: {
-               struct tcphdr _tcph;
-               const struct tcphdr *th;
-
-               /* Max length: 10 "PROTO=TCP " */
-               sb_add(m, "PROTO=TCP ");
-
-               if (fragment)
-                       break;
-
-               /* Max length: 25 "INCOMPLETE [65535 bytes] " */
-               th = skb_header_pointer(skb, ptr, sizeof(_tcph), &_tcph);
-               if (th == NULL) {
-                       sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - ptr);
-                       return;
-               }
-
-               /* Max length: 20 "SPT=65535 DPT=65535 " */
-               sb_add(m, "SPT=%u DPT=%u ",
-                      ntohs(th->source), ntohs(th->dest));
-               /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */
-               if (logflags & IP6T_LOG_TCPSEQ)
-                       sb_add(m, "SEQ=%u ACK=%u ",
-                              ntohl(th->seq), ntohl(th->ack_seq));
-               /* Max length: 13 "WINDOW=65535 " */
-               sb_add(m, "WINDOW=%u ", ntohs(th->window));
-               /* Max length: 9 "RES=0x3C " */
-               sb_add(m, "RES=0x%02x ", (u_int8_t)(ntohl(tcp_flag_word(th) & TCP_RESERVED_BITS) >> 22));
-               /* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */
-               if (th->cwr)
-                       sb_add(m, "CWR ");
-               if (th->ece)
-                       sb_add(m, "ECE ");
-               if (th->urg)
-                       sb_add(m, "URG ");
-               if (th->ack)
-                       sb_add(m, "ACK ");
-               if (th->psh)
-                       sb_add(m, "PSH ");
-               if (th->rst)
-                       sb_add(m, "RST ");
-               if (th->syn)
-                       sb_add(m, "SYN ");
-               if (th->fin)
-                       sb_add(m, "FIN ");
-               /* Max length: 11 "URGP=65535 " */
-               sb_add(m, "URGP=%u ", ntohs(th->urg_ptr));
-
-               if ((logflags & IP6T_LOG_TCPOPT) &&
-                   th->doff * 4 > sizeof(struct tcphdr)) {
-                       u_int8_t _opt[60 - sizeof(struct tcphdr)];
-                       const u_int8_t *op;
-                       unsigned int i;
-                       unsigned int optsize = th->doff * 4
-                                              - sizeof(struct tcphdr);
-
-                       op = skb_header_pointer(skb,
-                                               ptr + sizeof(struct tcphdr),
-                                               optsize, _opt);
-                       if (op == NULL) {
-                               sb_add(m, "OPT (TRUNCATED)");
-                               return;
-                       }
-
-                       /* Max length: 127 "OPT (" 15*4*2chars ") " */
-                       sb_add(m, "OPT (");
-                       for (i =0; i < optsize; i++)
-                               sb_add(m, "%02X", op[i]);
-                       sb_add(m, ") ");
-               }
-               break;
-       }
-       case IPPROTO_UDP:
-       case IPPROTO_UDPLITE: {
-               struct udphdr _udph;
-               const struct udphdr *uh;
-
-               if (currenthdr == IPPROTO_UDP)
-                       /* Max length: 10 "PROTO=UDP "     */
-                       sb_add(m, "PROTO=UDP " );
-               else    /* Max length: 14 "PROTO=UDPLITE " */
-                       sb_add(m, "PROTO=UDPLITE ");
-
-               if (fragment)
-                       break;
-
-               /* Max length: 25 "INCOMPLETE [65535 bytes] " */
-               uh = skb_header_pointer(skb, ptr, sizeof(_udph), &_udph);
-               if (uh == NULL) {
-                       sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - ptr);
-                       return;
-               }
-
-               /* Max length: 20 "SPT=65535 DPT=65535 " */
-               sb_add(m, "SPT=%u DPT=%u LEN=%u ",
-                      ntohs(uh->source), ntohs(uh->dest),
-                      ntohs(uh->len));
-               break;
-       }
-       case IPPROTO_ICMPV6: {
-               struct icmp6hdr _icmp6h;
-               const struct icmp6hdr *ic;
-
-               /* Max length: 13 "PROTO=ICMPv6 " */
-               sb_add(m, "PROTO=ICMPv6 ");
-
-               if (fragment)
-                       break;
-
-               /* Max length: 25 "INCOMPLETE [65535 bytes] " */
-               ic = skb_header_pointer(skb, ptr, sizeof(_icmp6h), &_icmp6h);
-               if (ic == NULL) {
-                       sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - ptr);
-                       return;
-               }
-
-               /* Max length: 18 "TYPE=255 CODE=255 " */
-               sb_add(m, "TYPE=%u CODE=%u ", ic->icmp6_type, ic->icmp6_code);
-
-               switch (ic->icmp6_type) {
-               case ICMPV6_ECHO_REQUEST:
-               case ICMPV6_ECHO_REPLY:
-                       /* Max length: 19 "ID=65535 SEQ=65535 " */
-                       sb_add(m, "ID=%u SEQ=%u ",
-                               ntohs(ic->icmp6_identifier),
-                               ntohs(ic->icmp6_sequence));
-                       break;
-               case ICMPV6_MGM_QUERY:
-               case ICMPV6_MGM_REPORT:
-               case ICMPV6_MGM_REDUCTION:
-                       break;
-
-               case ICMPV6_PARAMPROB:
-                       /* Max length: 17 "POINTER=ffffffff " */
-                       sb_add(m, "POINTER=%08x ", ntohl(ic->icmp6_pointer));
-                       /* Fall through */
-               case ICMPV6_DEST_UNREACH:
-               case ICMPV6_PKT_TOOBIG:
-               case ICMPV6_TIME_EXCEED:
-                       /* Max length: 3+maxlen */
-                       if (recurse) {
-                               sb_add(m, "[");
-                               dump_packet(m, info, skb,
-                                           ptr + sizeof(_icmp6h), 0);
-                               sb_add(m, "] ");
-                       }
-
-                       /* Max length: 10 "MTU=65535 " */
-                       if (ic->icmp6_type == ICMPV6_PKT_TOOBIG)
-                               sb_add(m, "MTU=%u ", ntohl(ic->icmp6_mtu));
-               }
-               break;
-       }
-       /* Max length: 10 "PROTO=255 " */
-       default:
-               sb_add(m, "PROTO=%u ", currenthdr);
-       }
-
-       /* Max length: 15 "UID=4294967295 " */
-       if ((logflags & IP6T_LOG_UID) && recurse && skb->sk) {
-               read_lock_bh(&skb->sk->sk_callback_lock);
-               if (skb->sk->sk_socket && skb->sk->sk_socket->file)
-                       sb_add(m, "UID=%u GID=%u ",
-                               skb->sk->sk_socket->file->f_cred->fsuid,
-                               skb->sk->sk_socket->file->f_cred->fsgid);
-               read_unlock_bh(&skb->sk->sk_callback_lock);
-       }
-
-       /* Max length: 16 "MARK=0xFFFFFFFF " */
-       if (!recurse && skb->mark)
-               sb_add(m, "MARK=0x%x ", skb->mark);
-}
-
-static void dump_mac_header(struct sbuff *m,
-                           const struct nf_loginfo *info,
-                           const struct sk_buff *skb)
-{
-       struct net_device *dev = skb->dev;
-       unsigned int logflags = 0;
-
-       if (info->type == NF_LOG_TYPE_LOG)
-               logflags = info->u.log.logflags;
-
-       if (!(logflags & IP6T_LOG_MACDECODE))
-               goto fallback;
-
-       switch (dev->type) {
-       case ARPHRD_ETHER:
-               sb_add(m, "MACSRC=%pM MACDST=%pM MACPROTO=%04x ",
-                      eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest,
-                      ntohs(eth_hdr(skb)->h_proto));
-               return;
-       default:
-               break;
-       }
-
-fallback:
-       sb_add(m, "MAC=");
-       if (dev->hard_header_len &&
-           skb->mac_header != skb->network_header) {
-               const unsigned char *p = skb_mac_header(skb);
-               unsigned int len = dev->hard_header_len;
-               unsigned int i;
-
-               if (dev->type == ARPHRD_SIT &&
-                   (p -= ETH_HLEN) < skb->head)
-                       p = NULL;
-
-               if (p != NULL) {
-                       sb_add(m, "%02x", *p++);
-                       for (i = 1; i < len; i++)
-                               sb_add(m, ":%02x", *p++);
-               }
-               sb_add(m, " ");
-
-               if (dev->type == ARPHRD_SIT) {
-                       const struct iphdr *iph =
-                               (struct iphdr *)skb_mac_header(skb);
-                       sb_add(m, "TUNNEL=%pI4->%pI4 ", &iph->saddr, &iph->daddr);
-               }
-       } else
-               sb_add(m, " ");
-}
-
-static struct nf_loginfo default_loginfo = {
-       .type   = NF_LOG_TYPE_LOG,
-       .u = {
-               .log = {
-                       .level    = 5,
-                       .logflags = NF_LOG_MASK,
-               },
-       },
-};
-
-static void
-ip6t_log_packet(u_int8_t pf,
-               unsigned int hooknum,
-               const struct sk_buff *skb,
-               const struct net_device *in,
-               const struct net_device *out,
-               const struct nf_loginfo *loginfo,
-               const char *prefix)
-{
-       struct sbuff *m = sb_open();
-
-       if (!loginfo)
-               loginfo = &default_loginfo;
-
-       sb_add(m, "<%d>%sIN=%s OUT=%s ", loginfo->u.log.level,
-              prefix,
-              in ? in->name : "",
-              out ? out->name : "");
-
-       if (in != NULL)
-               dump_mac_header(m, loginfo, skb);
-
-       dump_packet(m, loginfo, skb, skb_network_offset(skb), 1);
-
-       sb_close(m);
-}
-
-static unsigned int
-log_tg6(struct sk_buff *skb, const struct xt_action_param *par)
-{
-       const struct ip6t_log_info *loginfo = par->targinfo;
-       struct nf_loginfo li;
-
-       li.type = NF_LOG_TYPE_LOG;
-       li.u.log.level = loginfo->level;
-       li.u.log.logflags = loginfo->logflags;
-
-       ip6t_log_packet(NFPROTO_IPV6, par->hooknum, skb, par->in, par->out,
-                       &li, loginfo->prefix);
-       return XT_CONTINUE;
-}
-
-
-static int log_tg6_check(const struct xt_tgchk_param *par)
-{
-       const struct ip6t_log_info *loginfo = par->targinfo;
-
-       if (loginfo->level >= 8) {
-               pr_debug("level %u >= 8\n", loginfo->level);
-               return -EINVAL;
-       }
-       if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') {
-               pr_debug("prefix not null-terminated\n");
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static struct xt_target log_tg6_reg __read_mostly = {
-       .name           = "LOG",
-       .family         = NFPROTO_IPV6,
-       .target         = log_tg6,
-       .targetsize     = sizeof(struct ip6t_log_info),
-       .checkentry     = log_tg6_check,
-       .me             = THIS_MODULE,
-};
-
-static struct nf_logger ip6t_logger __read_mostly = {
-       .name           = "ip6t_LOG",
-       .logfn          = &ip6t_log_packet,
-       .me             = THIS_MODULE,
-};
-
-static int __init log_tg6_init(void)
-{
-       int ret;
-
-       ret = xt_register_target(&log_tg6_reg);
-       if (ret < 0)
-               return ret;
-       nf_log_register(NFPROTO_IPV6, &ip6t_logger);
-       return 0;
-}
-
-static void __exit log_tg6_exit(void)
-{
-       nf_log_unregister(&ip6t_logger);
-       xt_unregister_target(&log_tg6_reg);
-}
-
-module_init(log_tg6_init);
-module_exit(log_tg6_exit);
index 7c05e7eacbc6561744566168c4ff3c3f64fc828d..92cc9f2931ae46367a7e5fad02e3f31d7978069c 100644 (file)
@@ -88,25 +88,31 @@ static int icmpv6_print_tuple(struct seq_file *s,
                          ntohs(tuple->src.u.icmp.id));
 }
 
+static unsigned int *icmpv6_get_timeouts(struct net *net)
+{
+       return &nf_ct_icmpv6_timeout;
+}
+
 /* Returns verdict for packet, or -1 for invalid. */
 static int icmpv6_packet(struct nf_conn *ct,
                       const struct sk_buff *skb,
                       unsigned int dataoff,
                       enum ip_conntrack_info ctinfo,
                       u_int8_t pf,
-                      unsigned int hooknum)
+                      unsigned int hooknum,
+                      unsigned int *timeout)
 {
        /* Do not immediately delete the connection after the first
           successful reply to avoid excessive conntrackd traffic
           and also to handle correctly ICMP echo reply duplicates. */
-       nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmpv6_timeout);
+       nf_ct_refresh_acct(ct, ctinfo, skb, *timeout);
 
        return NF_ACCEPT;
 }
 
 /* Called when a new connection for this protocol found. */
 static bool icmpv6_new(struct nf_conn *ct, const struct sk_buff *skb,
-                      unsigned int dataoff)
+                      unsigned int dataoff, unsigned int *timeouts)
 {
        static const u_int8_t valid_new[] = {
                [ICMPV6_ECHO_REQUEST - 128] = 1,
@@ -270,6 +276,44 @@ static int icmpv6_nlattr_tuple_size(void)
 }
 #endif
 
+#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
+
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nfnetlink_cttimeout.h>
+
+static int icmpv6_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
+{
+       unsigned int *timeout = data;
+
+       if (tb[CTA_TIMEOUT_ICMPV6_TIMEOUT]) {
+               *timeout =
+                   ntohl(nla_get_be32(tb[CTA_TIMEOUT_ICMPV6_TIMEOUT])) * HZ;
+       } else {
+               /* Set default ICMPv6 timeout. */
+               *timeout = nf_ct_icmpv6_timeout;
+       }
+       return 0;
+}
+
+static int
+icmpv6_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
+{
+       const unsigned int *timeout = data;
+
+       NLA_PUT_BE32(skb, CTA_TIMEOUT_ICMPV6_TIMEOUT, htonl(*timeout / HZ));
+
+       return 0;
+
+nla_put_failure:
+       return -ENOSPC;
+}
+
+static const struct nla_policy
+icmpv6_timeout_nla_policy[CTA_TIMEOUT_ICMPV6_MAX+1] = {
+       [CTA_TIMEOUT_ICMPV6_TIMEOUT]    = { .type = NLA_U32 },
+};
+#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
+
 #ifdef CONFIG_SYSCTL
 static struct ctl_table_header *icmpv6_sysctl_header;
 static struct ctl_table icmpv6_sysctl_table[] = {
@@ -293,6 +337,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 __read_mostly =
        .invert_tuple           = icmpv6_invert_tuple,
        .print_tuple            = icmpv6_print_tuple,
        .packet                 = icmpv6_packet,
+       .get_timeouts           = icmpv6_get_timeouts,
        .new                    = icmpv6_new,
        .error                  = icmpv6_error,
 #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
@@ -301,6 +346,15 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 __read_mostly =
        .nlattr_to_tuple        = icmpv6_nlattr_to_tuple,
        .nla_policy             = icmpv6_nla_policy,
 #endif
+#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
+       .ctnl_timeout           = {
+               .nlattr_to_obj  = icmpv6_timeout_nlattr_to_obj,
+               .obj_to_nlattr  = icmpv6_timeout_obj_to_nlattr,
+               .nlattr_max     = CTA_TIMEOUT_ICMP_MAX,
+               .obj_size       = sizeof(unsigned int),
+               .nla_policy     = icmpv6_timeout_nla_policy,
+       },
+#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 #ifdef CONFIG_SYSCTL
        .ctl_table_header       = &icmpv6_sysctl_header,
        .ctl_table              = icmpv6_sysctl_table,
index 98d1f0ba7fe93702c709d61145c6dc7d0987a13a..07d7d55a1b93af13013b23c361d8c2f7ff8382aa 100644 (file)
@@ -165,8 +165,6 @@ static int afiucv_pm_freeze(struct device *dev)
        read_lock(&iucv_sk_list.lock);
        sk_for_each(sk, node, &iucv_sk_list.head) {
                iucv = iucv_sk(sk);
-               skb_queue_purge(&iucv->send_skb_q);
-               skb_queue_purge(&iucv->backlog_skb_q);
                switch (sk->sk_state) {
                case IUCV_DISCONN:
                case IUCV_CLOSING:
@@ -405,7 +403,19 @@ static struct sock *__iucv_get_sock_by_name(char *nm)
 static void iucv_sock_destruct(struct sock *sk)
 {
        skb_queue_purge(&sk->sk_receive_queue);
-       skb_queue_purge(&sk->sk_write_queue);
+       skb_queue_purge(&sk->sk_error_queue);
+
+       sk_mem_reclaim(sk);
+
+       if (!sock_flag(sk, SOCK_DEAD)) {
+               pr_err("Attempt to release alive iucv socket %p\n", sk);
+               return;
+       }
+
+       WARN_ON(atomic_read(&sk->sk_rmem_alloc));
+       WARN_ON(atomic_read(&sk->sk_wmem_alloc));
+       WARN_ON(sk->sk_wmem_queued);
+       WARN_ON(sk->sk_forward_alloc);
 }
 
 /* Cleanup Listen */
@@ -453,14 +463,28 @@ static void iucv_sever_path(struct sock *sk, int with_user_data)
        }
 }
 
+/* Send FIN through an IUCV socket for HIPER transport */
+static int iucv_send_ctrl(struct sock *sk, u8 flags)
+{
+       int err = 0;
+       int blen;
+       struct sk_buff *skb;
+
+       blen = sizeof(struct af_iucv_trans_hdr) + ETH_HLEN;
+       skb = sock_alloc_send_skb(sk, blen, 1, &err);
+       if (skb) {
+               skb_reserve(skb, blen);
+               err = afiucv_hs_send(NULL, sk, skb, flags);
+       }
+       return err;
+}
+
 /* Close an IUCV socket */
 static void iucv_sock_close(struct sock *sk)
 {
        struct iucv_sock *iucv = iucv_sk(sk);
        unsigned long timeo;
        int err = 0;
-       int blen;
-       struct sk_buff *skb;
 
        lock_sock(sk);
 
@@ -471,14 +495,7 @@ static void iucv_sock_close(struct sock *sk)
 
        case IUCV_CONNECTED:
                if (iucv->transport == AF_IUCV_TRANS_HIPER) {
-                       /* send fin */
-                       blen = sizeof(struct af_iucv_trans_hdr) + ETH_HLEN;
-                       skb = sock_alloc_send_skb(sk, blen, 1, &err);
-                       if (skb) {
-                               skb_reserve(skb, blen);
-                               err = afiucv_hs_send(NULL, sk, skb,
-                                                    AF_IUCV_FLAG_FIN);
-                       }
+                       err = iucv_send_ctrl(sk, AF_IUCV_FLAG_FIN);
                        sk->sk_state = IUCV_DISCONN;
                        sk->sk_state_change(sk);
                }
@@ -782,26 +799,6 @@ static int iucv_sock_autobind(struct sock *sk)
        return err;
 }
 
-static int afiucv_hs_connect(struct socket *sock)
-{
-       struct sock *sk = sock->sk;
-       struct sk_buff *skb;
-       int blen = sizeof(struct af_iucv_trans_hdr) + ETH_HLEN;
-       int err = 0;
-
-       /* send syn */
-       skb = sock_alloc_send_skb(sk, blen, 1, &err);
-       if (!skb) {
-               err = -ENOMEM;
-               goto done;
-       }
-       skb->dev = NULL;
-       skb_reserve(skb, blen);
-       err = afiucv_hs_send(NULL, sk, skb, AF_IUCV_FLAG_SYN);
-done:
-       return err;
-}
-
 static int afiucv_path_connect(struct socket *sock, struct sockaddr *addr)
 {
        struct sockaddr_iucv *sa = (struct sockaddr_iucv *) addr;
@@ -882,7 +879,7 @@ static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr,
        memcpy(iucv->dst_name, sa->siucv_name, 8);
 
        if (iucv->transport == AF_IUCV_TRANS_HIPER)
-               err = afiucv_hs_connect(sock);
+               err = iucv_send_ctrl(sock->sk, AF_IUCV_FLAG_SYN);
        else
                err = afiucv_path_connect(sock, addr);
        if (err)
@@ -1332,8 +1329,7 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
        struct sock *sk = sock->sk;
        struct iucv_sock *iucv = iucv_sk(sk);
        unsigned int copied, rlen;
-       struct sk_buff *skb, *rskb, *cskb, *sskb;
-       int blen;
+       struct sk_buff *skb, *rskb, *cskb;
        int err = 0;
 
        if ((sk->sk_state == IUCV_DISCONN) &&
@@ -1356,6 +1352,8 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
 
        rlen   = skb->len;              /* real length of skb */
        copied = min_t(unsigned int, rlen, len);
+       if (!rlen)
+               sk->sk_shutdown = sk->sk_shutdown | RCV_SHUTDOWN;
 
        cskb = skb;
        if (skb_copy_datagram_iovec(cskb, 0, msg->msg_iov, copied)) {
@@ -1422,15 +1420,7 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
                                iucv_process_message_q(sk);
                        if (atomic_read(&iucv->msg_recv) >=
                                                        iucv->msglimit / 2) {
-                               /* send WIN to peer */
-                               blen = sizeof(struct af_iucv_trans_hdr) +
-                                       ETH_HLEN;
-                               sskb = sock_alloc_send_skb(sk, blen, 1, &err);
-                               if (sskb) {
-                                       skb_reserve(sskb, blen);
-                                       err = afiucv_hs_send(NULL, sk, sskb,
-                                                            AF_IUCV_FLAG_WIN);
-                               }
+                               err = iucv_send_ctrl(sk, AF_IUCV_FLAG_WIN);
                                if (err) {
                                        sk->sk_state = IUCV_DISCONN;
                                        sk->sk_state_change(sk);
@@ -1515,42 +1505,47 @@ static int iucv_sock_shutdown(struct socket *sock, int how)
 
        lock_sock(sk);
        switch (sk->sk_state) {
+       case IUCV_LISTEN:
        case IUCV_DISCONN:
        case IUCV_CLOSING:
        case IUCV_CLOSED:
                err = -ENOTCONN;
                goto fail;
-
        default:
-               sk->sk_shutdown |= how;
                break;
        }
 
        if (how == SEND_SHUTDOWN || how == SHUTDOWN_MASK) {
-               txmsg.class = 0;
-               txmsg.tag = 0;
-               err = pr_iucv->message_send(iucv->path, &txmsg, IUCV_IPRMDATA,
-                                       0, (void *) iprm_shutdown, 8);
-               if (err) {
-                       switch (err) {
-                       case 1:
-                               err = -ENOTCONN;
-                               break;
-                       case 2:
-                               err = -ECONNRESET;
-                               break;
-                       default:
-                               err = -ENOTCONN;
-                               break;
+               if (iucv->transport == AF_IUCV_TRANS_IUCV) {
+                       txmsg.class = 0;
+                       txmsg.tag = 0;
+                       err = pr_iucv->message_send(iucv->path, &txmsg,
+                               IUCV_IPRMDATA, 0, (void *) iprm_shutdown, 8);
+                       if (err) {
+                               switch (err) {
+                               case 1:
+                                       err = -ENOTCONN;
+                                       break;
+                               case 2:
+                                       err = -ECONNRESET;
+                                       break;
+                               default:
+                                       err = -ENOTCONN;
+                                       break;
+                               }
                        }
-               }
+               } else
+                       iucv_send_ctrl(sk, AF_IUCV_FLAG_SHT);
        }
 
+       sk->sk_shutdown |= how;
        if (how == RCV_SHUTDOWN || how == SHUTDOWN_MASK) {
-               err = pr_iucv->path_quiesce(iucv->path, NULL);
-               if (err)
-                       err = -ENOTCONN;
-
+               if (iucv->transport == AF_IUCV_TRANS_IUCV) {
+                       err = pr_iucv->path_quiesce(iucv->path, NULL);
+                       if (err)
+                               err = -ENOTCONN;
+/*                     skb_queue_purge(&sk->sk_receive_queue); */
+               }
                skb_queue_purge(&sk->sk_receive_queue);
        }
 
@@ -2088,8 +2083,13 @@ static int afiucv_hs_callback_rx(struct sock *sk, struct sk_buff *skb)
                return NET_RX_SUCCESS;
        }
 
+       if (sk->sk_shutdown & RCV_SHUTDOWN) {
+               kfree_skb(skb);
+               return NET_RX_SUCCESS;
+       }
+
                /* write stuff from iucv_msg to skb cb */
-       if (skb->len <= sizeof(struct af_iucv_trans_hdr)) {
+       if (skb->len < sizeof(struct af_iucv_trans_hdr)) {
                kfree_skb(skb);
                return NET_RX_SUCCESS;
        }
@@ -2195,7 +2195,10 @@ static int afiucv_hs_rcv(struct sk_buff *skb, struct net_device *dev,
                        kfree_skb(skb);
                        break;
                }
-               /* fall through */
+               /* fall through and receive non-zero length data */
+       case (AF_IUCV_FLAG_SHT):
+               /* shutdown request */
+               /* fall through and receive zero length data */
        case 0:
                /* plain data frame */
                memcpy(CB_TRGCLS(skb), &trans_hdr->iucv_hdr.class,
@@ -2289,6 +2292,44 @@ out_unlock:
        }
 
 }
+
+/*
+ * afiucv_netdev_event: handle netdev notifier chain events
+ */
+static int afiucv_netdev_event(struct notifier_block *this,
+                              unsigned long event, void *ptr)
+{
+       struct net_device *event_dev = (struct net_device *)ptr;
+       struct hlist_node *node;
+       struct sock *sk;
+       struct iucv_sock *iucv;
+
+       switch (event) {
+       case NETDEV_REBOOT:
+       case NETDEV_GOING_DOWN:
+               sk_for_each(sk, node, &iucv_sk_list.head) {
+                       iucv = iucv_sk(sk);
+                       if ((iucv->hs_dev == event_dev) &&
+                           (sk->sk_state == IUCV_CONNECTED)) {
+                               if (event == NETDEV_GOING_DOWN)
+                                       iucv_send_ctrl(sk, AF_IUCV_FLAG_FIN);
+                               sk->sk_state = IUCV_DISCONN;
+                               sk->sk_state_change(sk);
+                       }
+               }
+               break;
+       case NETDEV_DOWN:
+       case NETDEV_UNREGISTER:
+       default:
+               break;
+       }
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block afiucv_netdev_notifier = {
+       .notifier_call = afiucv_netdev_event,
+};
+
 static const struct proto_ops iucv_sock_ops = {
        .family         = PF_IUCV,
        .owner          = THIS_MODULE,
@@ -2388,7 +2429,8 @@ static int __init afiucv_init(void)
                err = afiucv_iucv_init();
                if (err)
                        goto out_sock;
-       }
+       } else
+               register_netdevice_notifier(&afiucv_netdev_notifier);
        dev_add_pack(&iucv_packet_type);
        return 0;
 
@@ -2409,7 +2451,8 @@ static void __exit afiucv_exit(void)
                driver_unregister(&af_iucv_driver);
                pr_iucv->iucv_unregister(&af_iucv_handler, 0);
                symbol_put(iucv_if);
-       }
+       } else
+               unregister_netdevice_notifier(&afiucv_netdev_notifier);
        dev_remove_pack(&iucv_packet_type);
        sock_unregister(PF_IUCV);
        proto_unregister(&iucv_proto);
index c3de921c8cfd89d584d4aaa36aa2e374b78b8a94..677d65929780ad147a531657f30ee26f6b52ae82 100644 (file)
@@ -336,6 +336,20 @@ static void rate_idx_to_bitrate(struct rate_info *rate, struct sta_info *sta, in
                rate->mcs = idx;
 }
 
+void sta_set_rate_info_tx(struct sta_info *sta,
+                         const struct ieee80211_tx_rate *rate,
+                         struct rate_info *rinfo)
+{
+       rinfo->flags = 0;
+       if (rate->flags & IEEE80211_TX_RC_MCS)
+               rinfo->flags |= RATE_INFO_FLAGS_MCS;
+       if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+               rinfo->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
+       if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
+               rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI;
+       rate_idx_to_bitrate(rinfo, sta, rate->idx);
+}
+
 static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
 {
        struct ieee80211_sub_if_data *sdata = sta->sdata;
@@ -378,14 +392,7 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
                sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal);
        }
 
-       sinfo->txrate.flags = 0;
-       if (sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)
-               sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
-       if (sta->last_tx_rate.flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
-               sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
-       if (sta->last_tx_rate.flags & IEEE80211_TX_RC_SHORT_GI)
-               sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
-       rate_idx_to_bitrate(&sinfo->txrate, sta, sta->last_tx_rate.idx);
+       sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate);
 
        sinfo->rxrate.flags = 0;
        if (sta->last_rx_rate_flag & RX_FLAG_HT)
@@ -489,27 +496,13 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
        return ret;
 }
 
-static void ieee80211_config_ap_ssid(struct ieee80211_sub_if_data *sdata,
-                                    struct beacon_parameters *params)
-{
-       struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
-
-       bss_conf->ssid_len = params->ssid_len;
-
-       if (params->ssid_len)
-               memcpy(bss_conf->ssid, params->ssid, params->ssid_len);
-
-       bss_conf->hidden_ssid =
-               (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)
+                                   const u8 *resp, size_t resp_len)
 {
        struct sk_buff *new, *old;
 
        if (!resp || !resp_len)
-               return -EINVAL;
+               return 1;
 
        old = rtnl_dereference(sdata->u.ap.probe_resp);
 
@@ -520,50 +513,28 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
        memcpy(skb_put(new, resp_len), resp, resp_len);
 
        rcu_assign_pointer(sdata->u.ap.probe_resp, new);
-       synchronize_rcu();
-
-       if (old)
+       if (old) {
+               /* TODO: use call_rcu() */
+               synchronize_rcu();
                dev_kfree_skb(old);
+       }
 
        return 0;
 }
 
-/*
- * This handles both adding a beacon and setting new beacon info
- */
-static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
-                                  struct beacon_parameters *params)
+static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
+                                  struct cfg80211_beacon_data *params)
 {
        struct beacon_data *new, *old;
        int new_head_len, new_tail_len;
-       int size;
-       int err = -EINVAL;
-       u32 changed = 0;
+       int size, err;
+       u32 changed = BSS_CHANGED_BEACON;
 
        old = rtnl_dereference(sdata->u.ap.beacon);
 
-       /* head must not be zero-length */
-       if (params->head && !params->head_len)
-               return -EINVAL;
-
-       /*
-        * This is a kludge. beacon interval should really be part
-        * of the beacon information.
-        */
-       if (params->interval &&
-           (sdata->vif.bss_conf.beacon_int != params->interval)) {
-               sdata->vif.bss_conf.beacon_int = params->interval;
-               ieee80211_bss_info_change_notify(sdata,
-                                                BSS_CHANGED_BEACON_INT);
-       }
-
        /* Need to have a beacon head if we don't have one yet */
        if (!params->head && !old)
-               return err;
-
-       /* sorry, no way to start beaconing without dtim period */
-       if (!params->dtim_period && !old)
-               return err;
+               return -EINVAL;
 
        /* new or old head? */
        if (params->head)
@@ -586,12 +557,6 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
 
        /* start filling the new info now */
 
-       /* new or old dtim period? */
-       if (params->dtim_period)
-               new->dtim_period = params->dtim_period;
-       else
-               new->dtim_period = old->dtim_period;
-
        /*
         * pointers go into the block we allocated,
         * memory is | beacon_data | head | tail |
@@ -614,46 +579,37 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
                if (old)
                        memcpy(new->tail, old->tail, new_tail_len);
 
-       sdata->vif.bss_conf.dtim_period = new->dtim_period;
-
-       rcu_assign_pointer(sdata->u.ap.beacon, new);
-
-       synchronize_rcu();
-
-       kfree(old);
-
        err = ieee80211_set_probe_resp(sdata, params->probe_resp,
                                       params->probe_resp_len);
-       if (!err)
+       if (err < 0)
+               return err;
+       if (err == 0)
                changed |= BSS_CHANGED_AP_PROBE_RESP;
 
-       ieee80211_config_ap_ssid(sdata, params);
-       changed |= BSS_CHANGED_BEACON_ENABLED |
-                  BSS_CHANGED_BEACON |
-                  BSS_CHANGED_SSID;
+       rcu_assign_pointer(sdata->u.ap.beacon, new);
+
+       if (old)
+               kfree_rcu(old, rcu_head);
 
-       ieee80211_bss_info_change_notify(sdata, changed);
-       return 0;
+       return changed;
 }
 
-static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
-                               struct beacon_parameters *params)
+static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
+                             struct cfg80211_ap_settings *params)
 {
-       struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct beacon_data *old;
        struct ieee80211_sub_if_data *vlan;
-       int ret;
-
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       u32 changed = BSS_CHANGED_BEACON_INT |
+                     BSS_CHANGED_BEACON_ENABLED |
+                     BSS_CHANGED_BEACON |
+                     BSS_CHANGED_SSID;
+       int err;
 
        old = rtnl_dereference(sdata->u.ap.beacon);
        if (old)
                return -EALREADY;
 
-       ret = ieee80211_config_beacon(sdata, params);
-       if (ret)
-               return ret;
-
        /*
         * Apply control port protocol, this allows us to
         * not encrypt dynamic WEP control frames.
@@ -667,14 +623,32 @@ static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
                        params->crypto.control_port_no_encrypt;
        }
 
+       sdata->vif.bss_conf.beacon_int = params->beacon_interval;
+       sdata->vif.bss_conf.dtim_period = params->dtim_period;
+
+       sdata->vif.bss_conf.ssid_len = params->ssid_len;
+       if (params->ssid_len)
+               memcpy(sdata->vif.bss_conf.ssid, params->ssid,
+                      params->ssid_len);
+       sdata->vif.bss_conf.hidden_ssid =
+               (params->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE);
+
+       err = ieee80211_assign_beacon(sdata, &params->beacon);
+       if (err < 0)
+               return err;
+       changed |= err;
+
+       ieee80211_bss_info_change_notify(sdata, changed);
+
        return 0;
 }
 
-static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
-                               struct beacon_parameters *params)
+static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev,
+                                  struct cfg80211_beacon_data *params)
 {
        struct ieee80211_sub_if_data *sdata;
        struct beacon_data *old;
+       int err;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
@@ -682,10 +656,14 @@ static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
        if (!old)
                return -ENOENT;
 
-       return ieee80211_config_beacon(sdata, params);
+       err = ieee80211_assign_beacon(sdata, params);
+       if (err < 0)
+               return err;
+       ieee80211_bss_info_change_notify(sdata, err);
+       return 0;
 }
 
-static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
+static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
 {
        struct ieee80211_sub_if_data *sdata;
        struct beacon_data *old;
@@ -697,10 +675,11 @@ static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
                return -ENOENT;
 
        RCU_INIT_POINTER(sdata->u.ap.beacon, NULL);
-       synchronize_rcu();
-       kfree(old);
+
+       kfree_rcu(old, rcu_head);
 
        ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
+
        return 0;
 }
 
@@ -1342,6 +1321,14 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy,
        }
        if (_chg_mesh_attr(NL80211_MESHCONF_FORWARDING, mask))
                conf->dot11MeshForwarding = nconf->dot11MeshForwarding;
+       if (_chg_mesh_attr(NL80211_MESHCONF_RSSI_THRESHOLD, mask)) {
+               /* our RSSI threshold implementation is supported only for
+                * devices that report signal in dBm.
+                */
+               if (!(sdata->local->hw.flags & IEEE80211_HW_SIGNAL_DBM))
+                       return -ENOTSUPP;
+               conf->rssi_threshold = nconf->rssi_threshold;
+       }
        return 0;
 }
 
@@ -1623,19 +1610,15 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev,
 }
 
 static int ieee80211_deauth(struct wiphy *wiphy, struct net_device *dev,
-                           struct cfg80211_deauth_request *req,
-                           void *cookie)
+                           struct cfg80211_deauth_request *req)
 {
-       return ieee80211_mgd_deauth(IEEE80211_DEV_TO_SUB_IF(dev),
-                                   req, cookie);
+       return ieee80211_mgd_deauth(IEEE80211_DEV_TO_SUB_IF(dev), req);
 }
 
 static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev,
-                             struct cfg80211_disassoc_request *req,
-                             void *cookie)
+                             struct cfg80211_disassoc_request *req)
 {
-       return ieee80211_mgd_disassoc(IEEE80211_DEV_TO_SUB_IF(dev),
-                                     req, cookie);
+       return ieee80211_mgd_disassoc(IEEE80211_DEV_TO_SUB_IF(dev), req);
 }
 
 static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
@@ -2699,9 +2682,9 @@ struct cfg80211_ops mac80211_config_ops = {
        .get_key = ieee80211_get_key,
        .set_default_key = ieee80211_config_default_key,
        .set_default_mgmt_key = ieee80211_config_default_mgmt_key,
-       .add_beacon = ieee80211_add_beacon,
-       .set_beacon = ieee80211_set_beacon,
-       .del_beacon = ieee80211_del_beacon,
+       .start_ap = ieee80211_start_ap,
+       .change_beacon = ieee80211_change_beacon,
+       .stop_ap = ieee80211_stop_ap,
        .add_station = ieee80211_add_station,
        .del_station = ieee80211_del_station,
        .change_station = ieee80211_change_station,
index 510ed1dab3c7eb1d9b179451f7f7c68a58a91272..f6de8a65f4020e70d7a630608eea166f6ef6b430 100644 (file)
@@ -443,6 +443,7 @@ IEEE80211_IF_FILE(dot11MeshGateAnnouncementProtocol,
 IEEE80211_IF_FILE(dot11MeshHWMPRannInterval,
                u.mesh.mshcfg.dot11MeshHWMPRannInterval, DEC);
 IEEE80211_IF_FILE(dot11MeshForwarding, u.mesh.mshcfg.dot11MeshForwarding, DEC);
+IEEE80211_IF_FILE(rssi_threshold, u.mesh.mshcfg.rssi_threshold, DEC);
 #endif
 
 
@@ -537,11 +538,15 @@ static void add_monitor_files(struct ieee80211_sub_if_data *sdata)
 
 #ifdef CONFIG_MAC80211_MESH
 
+static void add_mesh_files(struct ieee80211_sub_if_data *sdata)
+{
+       DEBUGFS_ADD_MODE(tsf, 0600);
+}
+
 static void add_mesh_stats(struct ieee80211_sub_if_data *sdata)
 {
        struct dentry *dir = debugfs_create_dir("mesh_stats",
                                                sdata->debugfs.dir);
-
 #define MESHSTATS_ADD(name)\
        debugfs_create_file(#name, 0400, dir, sdata, &name##_ops);
 
@@ -581,6 +586,7 @@ static void add_mesh_config(struct ieee80211_sub_if_data *sdata)
        MESHPARAMS_ADD(dot11MeshHWMPRootMode);
        MESHPARAMS_ADD(dot11MeshHWMPRannInterval);
        MESHPARAMS_ADD(dot11MeshGateAnnouncementProtocol);
+       MESHPARAMS_ADD(rssi_threshold);
 #undef MESHPARAMS_ADD
 }
 #endif
@@ -593,6 +599,7 @@ static void add_files(struct ieee80211_sub_if_data *sdata)
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_MESH_POINT:
 #ifdef CONFIG_MAC80211_MESH
+               add_mesh_files(sdata);
                add_mesh_stats(sdata);
                add_mesh_config(sdata);
 #endif
index 8361da4b36ab143d744ba03cde17c6fc5feac7d4..33fd8d9f714ec05db8aeba88d0bb5c6bf97e8fd0 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/etherdevice.h>
 #include <linux/rtnetlink.h>
 #include <net/mac80211.h>
-#include <asm/unaligned.h>
 
 #include "ieee80211_i.h"
 #include "driver-ops.h"
@@ -67,7 +66,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
        skb_reset_tail_pointer(skb);
        skb_reserve(skb, sdata->local->hw.extra_tx_headroom);
 
-       if (memcmp(ifibss->bssid, bssid, ETH_ALEN))
+       if (compare_ether_addr(ifibss->bssid, bssid))
                sta_info_flush(sdata->local, sdata);
 
        /* if merging, indicate to driver that we leave the old IBSS */
@@ -404,7 +403,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
                return;
 
        if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
-           memcmp(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN) == 0) {
+           compare_ether_addr(mgmt->bssid, sdata->u.ibss.bssid) == 0) {
 
                rcu_read_lock();
                sta = sta_info_get(sdata, mgmt->sa);
@@ -509,7 +508,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
                goto put_bss;
 
        /* same BSSID */
-       if (memcmp(cbss->bssid, sdata->u.ibss.bssid, ETH_ALEN) == 0)
+       if (compare_ether_addr(cbss->bssid, sdata->u.ibss.bssid) == 0)
                goto put_bss;
 
        if (rx_status->flag & RX_FLAG_MACTIME_MPDU) {
@@ -832,8 +831,8 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
        if (!tx_last_beacon && is_multicast_ether_addr(mgmt->da))
                return;
 
-       if (memcmp(mgmt->bssid, ifibss->bssid, ETH_ALEN) != 0 &&
-           memcmp(mgmt->bssid, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0)
+       if (compare_ether_addr(mgmt->bssid, ifibss->bssid) != 0 &&
+           !is_broadcast_ether_addr(mgmt->bssid))
                return;
 
        end = ((u8 *) mgmt) + len;
index 74594f012cd3256f9f27d5bbda04133ee218470e..796b13bfc9532c1adcb5199934980c255443dbe0 100644 (file)
@@ -105,6 +105,44 @@ struct ieee80211_bss {
         */
        bool has_erp_value;
        u8 erp_value;
+
+       /* Keep track of the corruption of the last beacon/probe response. */
+       u8 corrupt_data;
+
+       /* Keep track of what bits of information we have valid info for. */
+       u8 valid_data;
+};
+
+/**
+ * enum ieee80211_corrupt_data_flags - BSS data corruption flags
+ * @IEEE80211_BSS_CORRUPT_BEACON: last beacon frame received was corrupted
+ * @IEEE80211_BSS_CORRUPT_PROBE_RESP: last probe response received was corrupted
+ *
+ * These are bss flags that are attached to a bss in the
+ * @corrupt_data field of &struct ieee80211_bss.
+ */
+enum ieee80211_bss_corrupt_data_flags {
+       IEEE80211_BSS_CORRUPT_BEACON            = BIT(0),
+       IEEE80211_BSS_CORRUPT_PROBE_RESP        = BIT(1)
+};
+
+/**
+ * enum ieee80211_valid_data_flags - BSS valid data flags
+ * @IEEE80211_BSS_VALID_DTIM: DTIM data was gathered from non-corrupt IE
+ * @IEEE80211_BSS_VALID_WMM: WMM/UAPSD data was gathered from non-corrupt IE
+ * @IEEE80211_BSS_VALID_RATES: Supported rates were gathered from non-corrupt IE
+ * @IEEE80211_BSS_VALID_ERP: ERP flag was gathered from non-corrupt IE
+ *
+ * These are bss flags that are attached to a bss in the
+ * @valid_data field of &struct ieee80211_bss.  They show which parts
+ * of the data structure were recieved as a result of an un-corrupted
+ * beacon/probe response.
+ */
+enum ieee80211_bss_valid_data_flags {
+       IEEE80211_BSS_VALID_DTIM                = BIT(0),
+       IEEE80211_BSS_VALID_WMM                 = BIT(1),
+       IEEE80211_BSS_VALID_RATES               = BIT(2),
+       IEEE80211_BSS_VALID_ERP                 = BIT(3)
 };
 
 static inline u8 *bss_mesh_cfg(struct ieee80211_bss *bss)
@@ -228,7 +266,7 @@ struct ieee80211_rx_data {
 struct beacon_data {
        u8 *head, *tail;
        int head_len, tail_len;
-       int dtim_period;
+       struct rcu_head rcu_head;
 };
 
 struct ieee80211_if_ap {
@@ -480,7 +518,7 @@ struct ieee80211_if_ibss {
 
        bool control_port;
 
-       u8 bssid[ETH_ALEN];
+       u8 bssid[ETH_ALEN] __aligned(2);
        u8 ssid[IEEE80211_MAX_SSID_LEN];
        u8 ssid_len, ie_len;
        u8 *ie;
@@ -1120,6 +1158,9 @@ struct ieee802_11_elems {
        u8 quiet_elem_len;
        u8 num_of_quiet_elem;   /* can be more the one */
        u8 timeout_int_len;
+
+       /* whether a parse error occurred while retrieving these elements */
+       bool parse_error;
 };
 
 static inline struct ieee80211_local *hw_to_local(
@@ -1128,12 +1169,6 @@ static inline struct ieee80211_local *hw_to_local(
        return container_of(hw, struct ieee80211_local, hw);
 }
 
-static inline struct ieee80211_hw *local_to_hw(
-       struct ieee80211_local *local)
-{
-       return &local->hw;
-}
-
 
 static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
 {
@@ -1156,11 +1191,9 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
 int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
                        struct cfg80211_assoc_request *req);
 int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
-                        struct cfg80211_deauth_request *req,
-                        void *cookie);
+                        struct cfg80211_deauth_request *req);
 int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
-                          struct cfg80211_disassoc_request *req,
-                          void *cookie);
+                          struct cfg80211_disassoc_request *req);
 void ieee80211_send_pspoll(struct ieee80211_local *local,
                           struct ieee80211_sub_if_data *sdata);
 void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency);
@@ -1178,6 +1211,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
                                  struct sk_buff *skb);
 void ieee80211_sta_reset_beacon_monitor(struct ieee80211_sub_if_data *sdata);
 void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata);
+void ieee80211_mgd_teardown(struct ieee80211_sub_if_data *sdata);
 
 /* IBSS code */
 void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local);
@@ -1355,7 +1389,8 @@ int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
 void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int keyidx,
                                     struct ieee80211_hdr *hdr, const u8 *tsc,
                                     gfp_t gfp);
-void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata);
+void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
+                              bool bss_notify);
 void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
 
 void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata,
index daa50ea15f46b8de2af40d05b884cbba9b946839..401c01f0731e996e5c22435f0066b53c97529559 100644 (file)
@@ -304,7 +304,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
                 * need to initialise the hardware if the hardware
                 * doesn't start up with sane defaults
                 */
-               ieee80211_set_wmm_default(sdata);
+               ieee80211_set_wmm_default(sdata, true);
        }
 
        set_bit(SDATA_STATE_RUNNING, &sdata->state);
@@ -644,6 +644,8 @@ static void ieee80211_teardown_sdata(struct net_device *dev)
 
        if (ieee80211_vif_is_mesh(&sdata->vif))
                mesh_rmc_free(sdata);
+       else if (sdata->vif.type == NL80211_IFTYPE_STATION)
+               ieee80211_mgd_teardown(sdata);
 
        flushed = sta_info_flush(local, sdata);
        WARN_ON(flushed);
index e8616b3ff636e8175dbf3e16cd31ce22a22ef954..5bb600d93d77b4cf2ec9c0196c002b7ab46538df 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/slab.h>
 #include <linux/export.h>
 #include <net/mac80211.h>
+#include <asm/unaligned.h>
 #include "ieee80211_i.h"
 #include "driver-ops.h"
 #include "debugfs_key.h"
index 2306d7514fff5bb2c82d609a859a3e826fdd6099..36fa8051296c80fab82c37f206a46d5892592435 100644 (file)
@@ -286,11 +286,11 @@ static void ieee80211_tasklet_handler(unsigned long data)
                        /* Clear skb->pkt_type in order to not confuse kernel
                         * netstack. */
                        skb->pkt_type = 0;
-                       ieee80211_rx(local_to_hw(local), skb);
+                       ieee80211_rx(&local->hw, skb);
                        break;
                case IEEE80211_TX_STATUS_MSG:
                        skb->pkt_type = 0;
-                       ieee80211_tx_status(local_to_hw(local), skb);
+                       ieee80211_tx_status(&local->hw, skb);
                        break;
                case IEEE80211_EOSP_MSG:
                        eosp_data = (void *)skb->cb;
@@ -668,7 +668,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 
        ieee80211_hw_roc_setup(local);
 
-       return local_to_hw(local);
+       return &local->hw;
 }
 EXPORT_SYMBOL(ieee80211_alloc_hw);
 
index c707c8bf6d2cbc1ee8e5e54b8d9776d59e5229a4..e5fbb7cf356250ce75968d8102d4dd87430ef551 100644 (file)
@@ -204,7 +204,7 @@ int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr,
                        kmem_cache_free(rm_cache, p);
                        --entries;
                } else if ((seqnum == p->seqnum) &&
-                          (memcmp(sa, p->sa, ETH_ALEN) == 0))
+                          (compare_ether_addr(sa, p->sa) == 0))
                        return -1;
        }
 
index bd14bd26a2b64eec5321bb218e2cd407e60b2ada..8d53b71378e3865cb38376ad35195be8c8193e41 100644 (file)
@@ -13,7 +13,6 @@
 
 #include <linux/types.h>
 #include <linux/jhash.h>
-#include <asm/unaligned.h>
 #include "ieee80211_i.h"
 
 
@@ -86,6 +85,8 @@ enum mesh_deferred_task_flags {
  * @state_lock: mesh path state lock used to protect changes to the
  * mpath itself.  No need to take this lock when adding or removing
  * an mpath to a hash bucket on a path table.
+ * @rann_snd_addr: the RANN sender address
+ * @is_root: the destination station of this path is a root node
  * @is_gate: the destination station of this path is a mesh gate
  *
  *
@@ -110,6 +111,8 @@ struct mesh_path {
        u8 discovery_retries;
        enum mesh_path_flags flags;
        spinlock_t state_lock;
+       u8 rann_snd_addr[ETH_ALEN];
+       bool is_root;
        bool is_gate;
 };
 
index c27dec904963ceccf94b37d488cdae8d2e875c10..1c6f3d02aebf5a4f19630f604aae94cda6810247 100644 (file)
@@ -8,6 +8,8 @@
  */
 
 #include <linux/slab.h>
+#include <linux/etherdevice.h>
+#include <asm/unaligned.h>
 #include "wme.h"
 #include "mesh.h"
 
@@ -322,6 +324,7 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local,
                                   struct sta_info *sta)
 {
        struct ieee80211_supported_band *sband;
+       struct rate_info rinfo;
        /* This should be adjusted for each device */
        int device_constant = 1 << ARITH_SHIFT;
        int test_frame_len = TEST_FRAME_LEN << ARITH_SHIFT;
@@ -335,7 +338,9 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local,
        if (sta->fail_avg >= 100)
                return MAX_METRIC;
 
-       if (sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)
+       sta_set_rate_info_tx(sta, &sta->last_tx_rate, &rinfo);
+       rate = cfg80211_calculate_bitrate(&rinfo);
+       if (WARN_ON(!rate))
                return MAX_METRIC;
 
        err = (sta->fail_avg << ARITH_SHIFT) / 100;
@@ -343,7 +348,6 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local,
        /* bitrate is in units of 100 Kbps, while we need rate in units of
         * 1Mbps. This will be corrected on tx_time computation.
         */
-       rate = sband->bitrates[sta->last_tx_rate.idx].bitrate;
        tx_time = (device_constant + 10 * test_frame_len / rate);
        estimated_retx = ((1 << (2 * ARITH_SHIFT)) / (s_unit - err));
        result = (tx_time * estimated_retx) >> (2 * ARITH_SHIFT) ;
@@ -418,7 +422,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
                new_metric = MAX_METRIC;
        exp_time = TU_TO_EXP_TIME(orig_lifetime);
 
-       if (memcmp(orig_addr, sdata->vif.addr, ETH_ALEN) == 0) {
+       if (compare_ether_addr(orig_addr, sdata->vif.addr) == 0) {
                /* This MP is the originator, we are not interested in this
                 * frame, except for updating transmitter's path info.
                 */
@@ -468,7 +472,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
 
        /* Update and check transmitter routing info */
        ta = mgmt->sa;
-       if (memcmp(orig_addr, ta, ETH_ALEN) == 0)
+       if (compare_ether_addr(orig_addr, ta) == 0)
                fresh_info = false;
        else {
                fresh_info = true;
@@ -512,8 +516,9 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
                                    u8 *preq_elem, u32 metric)
 {
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
-       struct mesh_path *mpath;
+       struct mesh_path *mpath = NULL;
        u8 *target_addr, *orig_addr;
+       const u8 *da;
        u8 target_flags, ttl;
        u32 orig_sn, target_sn, lifetime;
        bool reply = false;
@@ -528,7 +533,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
 
        mhwmp_dbg("received PREQ from %pM", orig_addr);
 
-       if (memcmp(target_addr, sdata->vif.addr, ETH_ALEN) == 0) {
+       if (compare_ether_addr(target_addr, sdata->vif.addr) == 0) {
                mhwmp_dbg("PREQ is for us");
                forward = false;
                reply = true;
@@ -590,9 +595,11 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
                flags = PREQ_IE_FLAGS(preq_elem);
                preq_id = PREQ_IE_PREQ_ID(preq_elem);
                hopcount = PREQ_IE_HOPCOUNT(preq_elem) + 1;
+               da = (mpath && mpath->is_root) ?
+                       mpath->rann_snd_addr : broadcast_addr;
                mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr,
                                cpu_to_le32(orig_sn), target_flags, target_addr,
-                               cpu_to_le32(target_sn), broadcast_addr,
+                               cpu_to_le32(target_sn), da,
                                hopcount, ttl, cpu_to_le32(lifetime),
                                cpu_to_le32(metric), cpu_to_le32(preq_id),
                                sdata);
@@ -614,6 +621,7 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
                                    struct ieee80211_mgmt *mgmt,
                                    u8 *prep_elem, u32 metric)
 {
+       struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
        struct mesh_path *mpath;
        u8 *target_addr, *orig_addr;
        u8 ttl, hopcount, flags;
@@ -623,10 +631,13 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
        mhwmp_dbg("received PREP from %pM", PREP_IE_ORIG_ADDR(prep_elem));
 
        orig_addr = PREP_IE_ORIG_ADDR(prep_elem);
-       if (memcmp(orig_addr, sdata->vif.addr, ETH_ALEN) == 0)
+       if (compare_ether_addr(orig_addr, sdata->vif.addr) == 0)
                /* destination, no forwarding required */
                return;
 
+       if (!ifmsh->mshcfg.dot11MeshForwarding)
+               return;
+
        ttl = PREP_IE_TTL(prep_elem);
        if (ttl <= 1) {
                sdata->u.mesh.mshstats.dropped_frames_ttl++;
@@ -693,21 +704,26 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata,
        rcu_read_lock();
        mpath = mesh_path_lookup(target_addr, sdata);
        if (mpath) {
+               struct sta_info *sta;
+
                spin_lock_bh(&mpath->state_lock);
+               sta = next_hop_deref_protected(mpath);
                if (mpath->flags & MESH_PATH_ACTIVE &&
-                   memcmp(ta, next_hop_deref_protected(mpath)->sta.addr,
-                                                       ETH_ALEN) == 0 &&
+                   compare_ether_addr(ta, sta->sta.addr) == 0 &&
                    (!(mpath->flags & MESH_PATH_SN_VALID) ||
                    SN_GT(target_sn, mpath->sn))) {
                        mpath->flags &= ~MESH_PATH_ACTIVE;
                        mpath->sn = target_sn;
                        spin_unlock_bh(&mpath->state_lock);
+                       if (!ifmsh->mshcfg.dot11MeshForwarding)
+                               goto endperr;
                        mesh_path_error_tx(ttl, target_addr, cpu_to_le32(target_sn),
                                           cpu_to_le16(target_rcode),
                                           broadcast_addr, sdata);
                } else
                        spin_unlock_bh(&mpath->state_lock);
        }
+endperr:
        rcu_read_unlock();
 }
 
@@ -738,11 +754,11 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
        metric = rann->rann_metric;
 
        /*  Ignore our own RANNs */
-       if (memcmp(orig_addr, sdata->vif.addr, ETH_ALEN) == 0)
+       if (compare_ether_addr(orig_addr, sdata->vif.addr) == 0)
                return;
 
-       mhwmp_dbg("received RANN from %pM (is_gate=%d)", orig_addr,
-                       root_is_gate);
+       mhwmp_dbg("received RANN from %pM via neighbour %pM (is_gate=%d)",
+                       orig_addr, mgmt->sa, root_is_gate);
 
        rcu_read_lock();
        mpath = mesh_path_lookup(orig_addr, sdata);
@@ -764,7 +780,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
                mesh_queue_preq(mpath, PREQ_Q_F_START | PREQ_Q_F_REFRESH);
        }
 
-       if (mpath->sn < orig_sn) {
+       if (mpath->sn < orig_sn && ifmsh->mshcfg.dot11MeshForwarding) {
                mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr,
                                       cpu_to_le32(orig_sn),
                                       0, NULL, 0, broadcast_addr,
@@ -773,6 +789,11 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
                                       0, sdata);
                mpath->sn = orig_sn;
        }
+
+       /* Using individually addressed PREQ for root node */
+       memcpy(mpath->rann_snd_addr, mgmt->sa, ETH_ALEN);
+       mpath->is_root = true;
+
        if (root_is_gate)
                mesh_path_add_gate(mpath);
 
@@ -908,6 +929,7 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
        struct mesh_preq_queue *preq_node;
        struct mesh_path *mpath;
        u8 ttl, target_flags;
+       const u8 *da;
        u32 lifetime;
 
        spin_lock_bh(&ifmsh->mesh_preq_queue_lock);
@@ -970,9 +992,10 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
                target_flags = MP_F_RF;
 
        spin_unlock_bh(&mpath->state_lock);
+       da = (mpath->is_root) ? mpath->rann_snd_addr : broadcast_addr;
        mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->vif.addr,
                        cpu_to_le32(ifmsh->sn), target_flags, mpath->dst,
-                       cpu_to_le32(mpath->sn), broadcast_addr, 0,
+                       cpu_to_le32(mpath->sn), da, 0,
                        ttl, cpu_to_le32(lifetime), 0,
                        cpu_to_le32(ifmsh->preq_id++), sdata);
        mod_timer(&mpath->timer, jiffies + mpath->discovery_timeout);
@@ -1063,7 +1086,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
        if (time_after(jiffies,
                       mpath->exp_time -
                       msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time)) &&
-           !memcmp(sdata->vif.addr, hdr->addr4, ETH_ALEN) &&
+           !compare_ether_addr(sdata->vif.addr, hdr->addr4) &&
            !(mpath->flags & MESH_PATH_RESOLVING) &&
            !(mpath->flags & MESH_PATH_FIXED))
                mesh_queue_preq(mpath, PREQ_Q_F_START | PREQ_Q_F_REFRESH);
index dc51669e67d883bf59a97575bc1bd355a6ce5f39..be1361b5f7ada32953a080a573bb6574d0fe9ac9 100644 (file)
@@ -348,7 +348,7 @@ static struct mesh_path *mpath_lookup(struct mesh_table *tbl, u8 *dst,
        hlist_for_each_entry_rcu(node, n, bucket, list) {
                mpath = node->mpath;
                if (mpath->sdata == sdata &&
-                               memcmp(dst, mpath->dst, ETH_ALEN) == 0) {
+                               compare_ether_addr(dst, mpath->dst) == 0) {
                        if (MPATH_EXPIRED(mpath)) {
                                spin_lock_bh(&mpath->state_lock);
                                mpath->flags &= ~MESH_PATH_ACTIVE;
@@ -523,7 +523,7 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
        int err = 0;
        u32 hash_idx;
 
-       if (memcmp(dst, sdata->vif.addr, ETH_ALEN) == 0)
+       if (compare_ether_addr(dst, sdata->vif.addr) == 0)
                /* never add ourselves as neighbours */
                return -ENOTSUPP;
 
@@ -559,12 +559,13 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
        hash_idx = mesh_table_hash(dst, sdata, tbl);
        bucket = &tbl->hash_buckets[hash_idx];
 
-       spin_lock_bh(&tbl->hashwlock[hash_idx]);
+       spin_lock(&tbl->hashwlock[hash_idx]);
 
        err = -EEXIST;
        hlist_for_each_entry(node, n, bucket, list) {
                mpath = node->mpath;
-               if (mpath->sdata == sdata && memcmp(dst, mpath->dst, ETH_ALEN) == 0)
+               if (mpath->sdata == sdata &&
+                   compare_ether_addr(dst, mpath->dst) == 0)
                        goto err_exists;
        }
 
@@ -575,7 +576,7 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
 
        mesh_paths_generation++;
 
-       spin_unlock_bh(&tbl->hashwlock[hash_idx]);
+       spin_unlock(&tbl->hashwlock[hash_idx]);
        read_unlock_bh(&pathtbl_resize_lock);
        if (grow) {
                set_bit(MESH_WORK_GROW_MPATH_TABLE,  &ifmsh->wrkq_flags);
@@ -584,7 +585,7 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
        return 0;
 
 err_exists:
-       spin_unlock_bh(&tbl->hashwlock[hash_idx]);
+       spin_unlock(&tbl->hashwlock[hash_idx]);
        read_unlock_bh(&pathtbl_resize_lock);
        kfree(new_node);
 err_node_alloc:
@@ -655,7 +656,7 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
        int err = 0;
        u32 hash_idx;
 
-       if (memcmp(dst, sdata->vif.addr, ETH_ALEN) == 0)
+       if (compare_ether_addr(dst, sdata->vif.addr) == 0)
                /* never add ourselves as neighbours */
                return -ENOTSUPP;
 
@@ -687,12 +688,13 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
        hash_idx = mesh_table_hash(dst, sdata, tbl);
        bucket = &tbl->hash_buckets[hash_idx];
 
-       spin_lock_bh(&tbl->hashwlock[hash_idx]);
+       spin_lock(&tbl->hashwlock[hash_idx]);
 
        err = -EEXIST;
        hlist_for_each_entry(node, n, bucket, list) {
                mpath = node->mpath;
-               if (mpath->sdata == sdata && memcmp(dst, mpath->dst, ETH_ALEN) == 0)
+               if (mpath->sdata == sdata &&
+                   compare_ether_addr(dst, mpath->dst) == 0)
                        goto err_exists;
        }
 
@@ -701,7 +703,7 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
            tbl->mean_chain_len * (tbl->hash_mask + 1))
                grow = 1;
 
-       spin_unlock_bh(&tbl->hashwlock[hash_idx]);
+       spin_unlock(&tbl->hashwlock[hash_idx]);
        read_unlock_bh(&pathtbl_resize_lock);
        if (grow) {
                set_bit(MESH_WORK_GROW_MPP_TABLE,  &ifmsh->wrkq_flags);
@@ -710,7 +712,7 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
        return 0;
 
 err_exists:
-       spin_unlock_bh(&tbl->hashwlock[hash_idx]);
+       spin_unlock(&tbl->hashwlock[hash_idx]);
        read_unlock_bh(&pathtbl_resize_lock);
        kfree(new_node);
 err_node_alloc:
@@ -809,9 +811,9 @@ void mesh_path_flush_by_nexthop(struct sta_info *sta)
        for_each_mesh_entry(tbl, p, node, i) {
                mpath = node->mpath;
                if (rcu_dereference(mpath->next_hop) == sta) {
-                       spin_lock_bh(&tbl->hashwlock[i]);
+                       spin_lock(&tbl->hashwlock[i]);
                        __mesh_path_del(tbl, node);
-                       spin_unlock_bh(&tbl->hashwlock[i]);
+                       spin_unlock(&tbl->hashwlock[i]);
                }
        }
        read_unlock_bh(&pathtbl_resize_lock);
@@ -882,11 +884,11 @@ int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata)
        hash_idx = mesh_table_hash(addr, sdata, tbl);
        bucket = &tbl->hash_buckets[hash_idx];
 
-       spin_lock_bh(&tbl->hashwlock[hash_idx]);
+       spin_lock(&tbl->hashwlock[hash_idx]);
        hlist_for_each_entry(node, n, bucket, list) {
                mpath = node->mpath;
                if (mpath->sdata == sdata &&
-                   memcmp(addr, mpath->dst, ETH_ALEN) == 0) {
+                   compare_ether_addr(addr, mpath->dst) == 0) {
                        __mesh_path_del(tbl, node);
                        goto enddel;
                }
@@ -895,7 +897,7 @@ int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata)
        err = -ENXIO;
 enddel:
        mesh_paths_generation++;
-       spin_unlock_bh(&tbl->hashwlock[hash_idx]);
+       spin_unlock(&tbl->hashwlock[hash_idx]);
        read_unlock_bh(&pathtbl_resize_lock);
        return err;
 }
index 8806e5ef8ffecebb799504a16c338a2f496991a0..4e53c4cbca9e5248f26254a261796ffdd5236681 100644 (file)
 #define dot11MeshHoldingTimeout(s) (s->u.mesh.mshcfg.dot11MeshHoldingTimeout)
 #define dot11MeshMaxPeerLinks(s) (s->u.mesh.mshcfg.dot11MeshMaxPeerLinks)
 
+/* We only need a valid sta if user configured a minimum rssi_threshold. */
+#define rssi_threshold_check(sta, sdata) \
+               (sdata->u.mesh.mshcfg.rssi_threshold == 0 ||\
+               (sta && (s8) -ewma_read(&sta->avg_signal) > \
+               sdata->u.mesh.mshcfg.rssi_threshold))
+
 enum plink_event {
        PLINK_UNDEFINED,
        OPN_ACPT,
@@ -301,7 +307,8 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates,
        if (mesh_peer_accepts_plinks(elems) &&
                        sta->plink_state == NL80211_PLINK_LISTEN &&
                        sdata->u.mesh.accepting_plinks &&
-                       sdata->u.mesh.mshcfg.auto_open_plinks)
+                       sdata->u.mesh.mshcfg.auto_open_plinks &&
+                       rssi_threshold_check(sta, sdata))
                mesh_plink_open(sta);
 
        rcu_read_unlock();
@@ -531,6 +538,14 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
                return;
        }
 
+       if (ftype == WLAN_SP_MESH_PEERING_OPEN &&
+           !rssi_threshold_check(sta, sdata)) {
+               mpl_dbg("Mesh plink: %pM does not meet rssi threshold\n",
+                       mgmt->sa);
+               rcu_read_unlock();
+               return;
+       }
+
        if (sta && !test_sta_flag(sta, WLAN_STA_AUTH)) {
                mpl_dbg("Mesh plink: Action frame from non-authed peer\n");
                rcu_read_unlock();
index 52133dab9297fc44447704e19b9a7daadd17569f..c08924aeac0017de011a3c305fcedf9faa4f8796 100644 (file)
@@ -88,6 +88,8 @@ MODULE_PARM_DESC(probe_wait_ms,
 #define TMR_RUNNING_TIMER      0
 #define TMR_RUNNING_CHANSW     1
 
+#define DEAUTH_DISASSOC_LEN    (24 /* hdr */ + 2 /* reason */)
+
 /*
  * All cfg80211 functions have to be called outside a locked
  * section so that they can acquire a lock themselves... This
@@ -612,47 +614,42 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
 }
 
 static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
-                                          const u8 *bssid, u16 stype, u16 reason,
-                                          void *cookie, bool send_frame)
+                                          const u8 *bssid, u16 stype,
+                                          u16 reason, bool send_frame,
+                                          u8 *frame_buf)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct sk_buff *skb;
-       struct ieee80211_mgmt *mgmt;
-
-       skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt));
-       if (!skb)
-               return;
-
-       skb_reserve(skb, local->hw.extra_tx_headroom);
+       struct ieee80211_mgmt *mgmt = (void *)frame_buf;
 
-       mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
-       memset(mgmt, 0, 24);
+       /* build frame */
+       mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype);
+       mgmt->duration = 0; /* initialize only */
+       mgmt->seq_ctrl = 0; /* initialize only */
        memcpy(mgmt->da, bssid, ETH_ALEN);
        memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        memcpy(mgmt->bssid, bssid, ETH_ALEN);
-       mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype);
-       skb_put(skb, 2);
        /* u.deauth.reason_code == u.disassoc.reason_code */
        mgmt->u.deauth.reason_code = cpu_to_le16(reason);
 
-       if (stype == IEEE80211_STYPE_DEAUTH)
-               if (cookie)
-                       __cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len);
-               else
-                       cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len);
-       else
-               if (cookie)
-                       __cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len);
-               else
-                       cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len);
-       if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED))
-               IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+       if (send_frame) {
+               skb = dev_alloc_skb(local->hw.extra_tx_headroom +
+                                   DEAUTH_DISASSOC_LEN);
+               if (!skb)
+                       return;
+
+               skb_reserve(skb, local->hw.extra_tx_headroom);
 
-       if (send_frame)
+               /* copy in frame */
+               memcpy(skb_put(skb, DEAUTH_DISASSOC_LEN),
+                      mgmt, DEAUTH_DISASSOC_LEN);
+
+               if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED))
+                       IEEE80211_SKB_CB(skb)->flags |=
+                               IEEE80211_TX_INTFL_DONT_ENCRYPT;
                ieee80211_tx_skb(sdata, skb);
-       else
-               kfree_skb(skb);
+       }
 }
 
 void ieee80211_send_pspoll(struct ieee80211_local *local,
@@ -1280,7 +1277,6 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
 
        /* enable WMM or activate new settings */
        sdata->vif.bss_conf.qos = true;
-       ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS);
 }
 
 static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
@@ -1392,7 +1388,8 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
 }
 
 static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
-                                  bool remove_sta, bool tx)
+                                  u16 stype, u16 reason, bool tx,
+                                  u8 *frame_buf)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_local *local = sdata->local;
@@ -1402,6 +1399,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 
        ASSERT_MGD_MTX(ifmgd);
 
+       if (WARN_ON_ONCE(tx && !frame_buf))
+               return;
+
        if (WARN_ON(!ifmgd->associated))
                return;
 
@@ -1435,14 +1435,25 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        }
        mutex_unlock(&local->sta_mtx);
 
+       /* deauthenticate/disassociate now */
+       if (tx || frame_buf)
+               ieee80211_send_deauth_disassoc(sdata, bssid, stype, reason,
+                                              tx, frame_buf);
+
+       /* flush out frame */
+       if (tx)
+               drv_flush(local, false);
+
+       /* remove AP and TDLS peers */
+       sta_info_flush(local, sdata);
+
+       /* finally reset all BSS / config parameters */
        changed |= ieee80211_reset_erp_info(sdata);
 
        ieee80211_led_assoc(local, 0);
        changed |= BSS_CHANGED_ASSOC;
        sdata->vif.bss_conf.assoc = false;
 
-       ieee80211_set_wmm_default(sdata);
-
        /* channel(_type) changes are handled by ieee80211_hw_config */
        WARN_ON(!ieee80211_set_channel_type(local, sdata, NL80211_CHAN_NO_HT));
 
@@ -1470,13 +1481,15 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
                changed |= BSS_CHANGED_ARP_FILTER;
        }
 
+       sdata->vif.bss_conf.qos = false;
+       changed |= BSS_CHANGED_QOS;
+
        /* The BSSID (not really interesting) and HT changed */
        changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT;
        ieee80211_bss_info_change_notify(sdata, changed);
 
-       /* remove AP and TDLS peers */
-       if (remove_sta)
-               sta_info_flush(local, sdata);
+       /* disassociated - set to defaults now */
+       ieee80211_set_wmm_default(sdata, false);
 
        del_timer_sync(&sdata->u.mgd.conn_mon_timer);
        del_timer_sync(&sdata->u.mgd.bcn_mon_timer);
@@ -1674,6 +1687,7 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata)
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_local *local = sdata->local;
        u8 bssid[ETH_ALEN];
+       u8 frame_buf[DEAUTH_DISASSOC_LEN];
 
        mutex_lock(&ifmgd->mtx);
        if (!ifmgd->associated) {
@@ -1686,17 +1700,16 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata)
        printk(KERN_DEBUG "%s: Connection to AP %pM lost.\n",
               sdata->name, bssid);
 
-       ieee80211_set_disassoc(sdata, true, true);
+       ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
+                              WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
+                              false, frame_buf);
        mutex_unlock(&ifmgd->mtx);
 
        /*
         * must be outside lock due to cfg80211,
         * but that's not a problem.
         */
-       ieee80211_send_deauth_disassoc(sdata, bssid,
-                                      IEEE80211_STYPE_DEAUTH,
-                                      WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
-                                      NULL, true);
+       cfg80211_send_deauth(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN);
 
        mutex_lock(&local->mtx);
        ieee80211_recalc_idle(local);
@@ -1812,7 +1825,7 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
 
        memcpy(bssid, ifmgd->auth_data->bss->bssid, ETH_ALEN);
 
-       if (memcmp(bssid, mgmt->bssid, ETH_ALEN))
+       if (compare_ether_addr(bssid, mgmt->bssid))
                return RX_MGMT_NONE;
 
        auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg);
@@ -1893,7 +1906,7 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
                return RX_MGMT_NONE;
 
        if (!ifmgd->associated ||
-           memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN))
+           compare_ether_addr(mgmt->bssid, ifmgd->associated->bssid))
                return RX_MGMT_NONE;
 
        bssid = ifmgd->associated->bssid;
@@ -1903,7 +1916,8 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
        printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n",
                        sdata->name, bssid, reason_code);
 
-       ieee80211_set_disassoc(sdata, true, false);
+       ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
+
        mutex_lock(&sdata->local->mtx);
        ieee80211_recalc_idle(sdata->local);
        mutex_unlock(&sdata->local->mtx);
@@ -1925,7 +1939,7 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
                return RX_MGMT_NONE;
 
        if (!ifmgd->associated ||
-           memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN))
+           compare_ether_addr(mgmt->bssid, ifmgd->associated->bssid))
                return RX_MGMT_NONE;
 
        reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
@@ -1933,10 +1947,12 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
        printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n",
                        sdata->name, mgmt->sa, reason_code);
 
-       ieee80211_set_disassoc(sdata, true, false);
+       ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
+
        mutex_lock(&sdata->local->mtx);
        ieee80211_recalc_idle(sdata->local);
        mutex_unlock(&sdata->local->mtx);
+
        return RX_MGMT_CFG80211_DISASSOC;
 }
 
@@ -2142,7 +2158,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
                ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
                                         elems.wmm_param_len);
        else
-               ieee80211_set_wmm_default(sdata);
+               ieee80211_set_wmm_default(sdata, false);
+       changed |= BSS_CHANGED_QOS;
 
        if (elems.ht_info_elem && elems.wmm_param &&
            (sdata->local->hw.queues >= 4) &&
@@ -2190,7 +2207,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
 
        if (!assoc_data)
                return RX_MGMT_NONE;
-       if (memcmp(assoc_data->bss->bssid, mgmt->bssid, ETH_ALEN))
+       if (compare_ether_addr(assoc_data->bss->bssid, mgmt->bssid))
                return RX_MGMT_NONE;
 
        /*
@@ -2238,14 +2255,28 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
        } else {
                printk(KERN_DEBUG "%s: associated\n", sdata->name);
 
-               ieee80211_destroy_assoc_data(sdata, true);
+               /* tell driver about sync done first */
+               if (assoc_data->synced) {
+                       drv_finish_tx_sync(sdata->local, sdata,
+                                          assoc_data->bss->bssid,
+                                          IEEE80211_TX_SYNC_ASSOC);
+                       assoc_data->synced = false;
+               }
 
                if (!ieee80211_assoc_success(sdata, *bss, mgmt, len)) {
                        /* oops -- internal error -- send timeout for now */
+                       ieee80211_destroy_assoc_data(sdata, true);
                        sta_info_destroy_addr(sdata, mgmt->bssid);
                        cfg80211_put_bss(*bss);
                        return RX_MGMT_CFG80211_ASSOC_TIMEOUT;
                }
+
+               /*
+                * destroy assoc_data afterwards, as otherwise an idle
+                * recalc after assoc_data is NULL but before associated
+                * is set can cause the interface to go idle
+                */
+               ieee80211_destroy_assoc_data(sdata, true);
        }
 
        return RX_MGMT_CFG80211_RX_ASSOC;
@@ -2264,8 +2295,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
        bool need_ps = false;
 
        if (sdata->u.mgd.associated &&
-           memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid,
-                  ETH_ALEN) == 0) {
+           compare_ether_addr(mgmt->bssid, sdata->u.mgd.associated->bssid)
+           == 0) {
                bss = (void *)sdata->u.mgd.associated->priv;
                /* not previously set so we may need to recalc */
                need_ps = !bss->dtim_period;
@@ -2320,7 +2351,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
 
        ASSERT_MGD_MTX(ifmgd);
 
-       if (memcmp(mgmt->da, sdata->vif.addr, ETH_ALEN))
+       if (compare_ether_addr(mgmt->da, sdata->vif.addr))
                return; /* ignore ProbeResp to foreign address */
 
        baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
@@ -2333,11 +2364,12 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
        ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false);
 
        if (ifmgd->associated &&
-           memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN) == 0)
+           compare_ether_addr(mgmt->bssid, ifmgd->associated->bssid) == 0)
                ieee80211_reset_ap_probe(sdata);
 
        if (ifmgd->auth_data && !ifmgd->auth_data->bss->proberesp_ies &&
-           memcmp(mgmt->bssid, ifmgd->auth_data->bss->bssid, ETH_ALEN) == 0) {
+           compare_ether_addr(mgmt->bssid, ifmgd->auth_data->bss->bssid)
+           == 0) {
                /* got probe response, continue with auth */
                printk(KERN_DEBUG "%s: direct probe responded\n", sdata->name);
                ifmgd->auth_data->tries = 0;
@@ -2394,7 +2426,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                return;
 
        if (ifmgd->assoc_data && !ifmgd->assoc_data->have_beacon &&
-           memcmp(mgmt->bssid, ifmgd->assoc_data->bss->bssid, ETH_ALEN) == 0) {
+           compare_ether_addr(mgmt->bssid, ifmgd->assoc_data->bss->bssid)
+           == 0) {
                ieee802_11_parse_elems(mgmt->u.beacon.variable,
                                       len - baselen, &elems);
 
@@ -2409,7 +2442,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
        }
 
        if (!ifmgd->associated ||
-           memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN))
+           compare_ether_addr(mgmt->bssid, ifmgd->associated->bssid))
                return;
        bssid = ifmgd->associated->bssid;
 
@@ -2681,19 +2714,20 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata,
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+       u8 frame_buf[DEAUTH_DISASSOC_LEN];
 
        ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL |
                          IEEE80211_STA_BEACON_POLL);
 
-       ieee80211_set_disassoc(sdata, true, true);
+       ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason,
+                              false, frame_buf);
        mutex_unlock(&ifmgd->mtx);
+
        /*
         * must be outside lock due to cfg80211,
         * but that's not a problem.
         */
-       ieee80211_send_deauth_disassoc(sdata, bssid,
-                       IEEE80211_STYPE_DEAUTH, reason,
-                       NULL, true);
+       cfg80211_send_deauth(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN);
 
        mutex_lock(&local->mtx);
        ieee80211_recalc_idle(local);
@@ -2974,13 +3008,17 @@ static void ieee80211_sta_monitor_work(struct work_struct *work)
 
 static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata)
 {
+       u32 flags;
+
        if (sdata->vif.type == NL80211_IFTYPE_STATION) {
                sdata->u.mgd.flags &= ~(IEEE80211_STA_BEACON_POLL |
                                        IEEE80211_STA_CONNECTION_POLL);
 
                /* let's probe the connection once */
-               ieee80211_queue_work(&sdata->local->hw,
-                          &sdata->u.mgd.monitor_work);
+               flags = sdata->local->hw.flags;
+               if (!(flags & IEEE80211_HW_CONNECTION_MONITOR))
+                       ieee80211_queue_work(&sdata->local->hw,
+                                            &sdata->u.mgd.monitor_work);
                /* and do all the other regular work too */
                ieee80211_queue_work(&sdata->local->hw, &sdata->work);
        }
@@ -3044,7 +3082,6 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata)
                add_timer(&ifmgd->chswitch_timer);
        ieee80211_sta_reset_beacon_monitor(sdata);
        ieee80211_restart_sta_timer(sdata);
-       ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.monitor_work);
 }
 #endif
 
@@ -3174,7 +3211,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
        ifmgd->auth_data = auth_data;
 
        if (ifmgd->associated)
-               ieee80211_set_disassoc(sdata, true, false);
+               ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
 
        printk(KERN_DEBUG "%s: authenticate with %pM\n",
               sdata->name, req->bss->bssid);
@@ -3252,7 +3289,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
        mutex_lock(&ifmgd->mtx);
 
        if (ifmgd->associated)
-               ieee80211_set_disassoc(sdata, true, false);
+               ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
 
        if (ifmgd->auth_data && !ifmgd->auth_data->done) {
                err = -EBUSY;
@@ -3268,7 +3305,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
                bool match;
 
                /* keep sta info, bssid if matching */
-               match = memcmp(ifmgd->bssid, req->bss->bssid, ETH_ALEN) == 0;
+               match = compare_ether_addr(ifmgd->bssid, req->bss->bssid) == 0;
                ieee80211_destroy_auth_data(sdata, match);
        }
 
@@ -3390,7 +3427,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
                        goto err_clear;
                }
        } else
-               WARN_ON_ONCE(memcmp(ifmgd->bssid, req->bss->bssid, ETH_ALEN));
+               WARN_ON_ONCE(compare_ether_addr(ifmgd->bssid, req->bss->bssid));
 
        if (!bss->dtim_period &&
            sdata->local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) {
@@ -3409,6 +3446,20 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
        }
        run_again(ifmgd, assoc_data->timeout);
 
+       if (bss->corrupt_data) {
+               char *corrupt_type = "data";
+               if (bss->corrupt_data & IEEE80211_BSS_CORRUPT_BEACON) {
+                       if (bss->corrupt_data &
+                                       IEEE80211_BSS_CORRUPT_PROBE_RESP)
+                               corrupt_type = "beacon and probe response";
+                       else
+                               corrupt_type = "beacon";
+               } else if (bss->corrupt_data & IEEE80211_BSS_CORRUPT_PROBE_RESP)
+                       corrupt_type = "probe response";
+               printk(KERN_DEBUG "%s: associating with AP with corrupt %s\n",
+                      sdata->name, corrupt_type);
+       }
+
        err = 0;
        goto out;
  err_clear:
@@ -3422,32 +3473,35 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
 }
 
 int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
-                        struct cfg80211_deauth_request *req,
-                        void *cookie)
+                        struct cfg80211_deauth_request *req)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-       bool assoc_bss = false;
+       u8 frame_buf[DEAUTH_DISASSOC_LEN];
 
        mutex_lock(&ifmgd->mtx);
 
-       if (ifmgd->associated &&
-           memcmp(ifmgd->associated->bssid, req->bssid, ETH_ALEN) == 0) {
-               ieee80211_set_disassoc(sdata, false, true);
-               assoc_bss = true;
-       } else if (ifmgd->auth_data) {
+       if (ifmgd->auth_data) {
                ieee80211_destroy_auth_data(sdata, false);
                mutex_unlock(&ifmgd->mtx);
                return 0;
        }
-       mutex_unlock(&ifmgd->mtx);
 
-       printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n",
+       printk(KERN_DEBUG
+              "%s: deauthenticating from %pM by local choice (reason=%d)\n",
               sdata->name, req->bssid, req->reason_code);
 
-       ieee80211_send_deauth_disassoc(sdata, req->bssid, IEEE80211_STYPE_DEAUTH,
-                                      req->reason_code, cookie, true);
-       if (assoc_bss)
-               sta_info_flush(sdata->local, sdata);
+       if (ifmgd->associated &&
+           compare_ether_addr(ifmgd->associated->bssid, req->bssid) == 0)
+               ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
+                                      req->reason_code, true, frame_buf);
+       else
+               ieee80211_send_deauth_disassoc(sdata, req->bssid,
+                                              IEEE80211_STYPE_DEAUTH,
+                                              req->reason_code, true,
+                                              frame_buf);
+       mutex_unlock(&ifmgd->mtx);
+
+       __cfg80211_send_deauth(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN);
 
        mutex_lock(&sdata->local->mtx);
        ieee80211_recalc_idle(sdata->local);
@@ -3457,11 +3511,11 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
 }
 
 int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
-                          struct cfg80211_disassoc_request *req,
-                          void *cookie)
+                          struct cfg80211_disassoc_request *req)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        u8 bssid[ETH_ALEN];
+       u8 frame_buf[DEAUTH_DISASSOC_LEN];
 
        mutex_lock(&ifmgd->mtx);
 
@@ -3480,14 +3534,12 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
               sdata->name, req->bss->bssid, req->reason_code);
 
        memcpy(bssid, req->bss->bssid, ETH_ALEN);
-       ieee80211_set_disassoc(sdata, false, true);
-
+       ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DISASSOC,
+                              req->reason_code, !req->local_state_change,
+                              frame_buf);
        mutex_unlock(&ifmgd->mtx);
 
-       ieee80211_send_deauth_disassoc(sdata, req->bss->bssid,
-                       IEEE80211_STYPE_DISASSOC, req->reason_code,
-                       cookie, !req->local_state_change);
-       sta_info_flush(sdata->local, sdata);
+       __cfg80211_send_disassoc(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN);
 
        mutex_lock(&sdata->local->mtx);
        ieee80211_recalc_idle(sdata->local);
@@ -3496,6 +3548,19 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
        return 0;
 }
 
+void ieee80211_mgd_teardown(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+
+       mutex_lock(&ifmgd->mtx);
+       if (ifmgd->assoc_data)
+               ieee80211_destroy_assoc_data(sdata, false);
+       if (ifmgd->auth_data)
+               ieee80211_destroy_auth_data(sdata, false);
+       del_timer_sync(&ifmgd->timer);
+       mutex_unlock(&ifmgd->mtx);
+}
+
 void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
                               enum nl80211_cqm_rssi_threshold_event rssi_event,
                               gfp_t gfp)
index 2b53a5348aceca296705217fa76301dfcdbc424d..ef8eba1d736d125cffa30c5a8a1431f2c6fdb1b1 100644 (file)
@@ -102,7 +102,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
 
                        state = sta->sta_state;
                        for (; state > IEEE80211_STA_NOTEXIST; state--)
-                               WARN_ON(drv_sta_state(local, sdata, sta,
+                               WARN_ON(drv_sta_state(local, sta->sdata, sta,
                                                      state, state - 1));
                }
 
index 3ab85c02ef0403daacad61c3cd00d41fd2b6aadc..5f6e32ca08585ff640fb790f4353f9ace120aaf6 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/export.h>
 #include <net/mac80211.h>
 #include <net/ieee80211_radiotap.h>
+#include <asm/unaligned.h>
 
 #include "ieee80211_i.h"
 #include "driver-ops.h"
@@ -176,7 +177,8 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
        pos += 2;
 
        /* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */
-       if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) {
+       if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM &&
+           !(status->flag & RX_FLAG_NO_SIGNAL_VAL)) {
                *pos = status->signal;
                rthdr->it_present |=
                        cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL);
@@ -226,7 +228,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
 {
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(origskb);
        struct ieee80211_sub_if_data *sdata;
-       int needed_headroom = 0;
+       int needed_headroom;
        struct sk_buff *skb, *skb2;
        struct net_device *prev_dev = NULL;
        int present_fcs_len = 0;
@@ -488,12 +490,12 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
                        if (ieee80211_has_tods(hdr->frame_control) ||
                                !ieee80211_has_fromds(hdr->frame_control))
                                return RX_DROP_MONITOR;
-                       if (memcmp(hdr->addr3, dev_addr, ETH_ALEN) == 0)
+                       if (compare_ether_addr(hdr->addr3, dev_addr) == 0)
                                return RX_DROP_MONITOR;
                } else {
                        if (!ieee80211_has_a4(hdr->frame_control))
                                return RX_DROP_MONITOR;
-                       if (memcmp(hdr->addr4, dev_addr, ETH_ALEN) == 0)
+                       if (compare_ether_addr(hdr->addr4, dev_addr) == 0)
                                return RX_DROP_MONITOR;
                }
        }
@@ -1308,8 +1310,10 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
 
        sta->rx_fragments++;
        sta->rx_bytes += rx->skb->len;
-       sta->last_signal = status->signal;
-       ewma_add(&sta->avg_signal, -status->signal);
+       if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) {
+               sta->last_signal = status->signal;
+               ewma_add(&sta->avg_signal, -status->signal);
+       }
 
        /*
         * Change STA power saving mode only at the end of a frame
@@ -1956,6 +1960,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
                return RX_DROP_MONITOR;
        }
 
+       if (!ifmsh->mshcfg.dot11MeshForwarding)
+               goto out;
+
        fwd_skb = skb_copy(skb, GFP_ATOMIC);
        if (!fwd_skb) {
                if (net_ratelimit())
@@ -2181,9 +2188,14 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
        if (rx->sdata->vif.type == NL80211_IFTYPE_AP &&
            ieee80211_is_beacon(mgmt->frame_control) &&
            !(rx->flags & IEEE80211_RX_BEACON_REPORTED)) {
+               int sig = 0;
+
+               if (rx->local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
+                       sig = status->signal;
+
                cfg80211_report_obss_beacon(rx->local->hw.wiphy,
                                            rx->skb->data, rx->skb->len,
-                                           status->freq, GFP_ATOMIC);
+                                           status->freq, sig, GFP_ATOMIC);
                rx->flags |= IEEE80211_RX_BEACON_REPORTED;
        }
 
@@ -2335,7 +2347,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
                        if (sdata->vif.type != NL80211_IFTYPE_STATION)
                                break;
 
-                       if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN))
+                       if (compare_ether_addr(mgmt->bssid, sdata->u.mgd.bssid))
                                break;
 
                        goto queue;
@@ -2407,6 +2419,7 @@ static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx)
 {
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
+       int sig = 0;
 
        /* skip known-bad action frames and return them in the next handler */
        if (status->rx_flags & IEEE80211_RX_MALFORMED_ACTION_FRM)
@@ -2419,7 +2432,10 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx)
         * it transmitted were processed or returned.
         */
 
-       if (cfg80211_rx_mgmt(rx->sdata->dev, status->freq,
+       if (rx->local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
+               sig = status->signal;
+
+       if (cfg80211_rx_mgmt(rx->sdata->dev, status->freq, sig,
                             rx->skb->data, rx->skb->len,
                             GFP_ATOMIC)) {
                if (rx->sta)
@@ -2537,16 +2553,10 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
 {
        struct ieee80211_sub_if_data *sdata;
        struct ieee80211_local *local = rx->local;
-       struct ieee80211_rtap_hdr {
-               struct ieee80211_radiotap_header hdr;
-               u8 flags;
-               u8 rate_or_pad;
-               __le16 chan_freq;
-               __le16 chan_flags;
-       } __packed *rthdr;
        struct sk_buff *skb = rx->skb, *skb2;
        struct net_device *prev_dev = NULL;
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+       int needed_headroom;
 
        /*
         * If cooked monitor has been processed already, then
@@ -2560,30 +2570,15 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
        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;
-
-       rthdr = (void *)skb_push(skb, sizeof(*rthdr));
-       memset(rthdr, 0, sizeof(*rthdr));
-       rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr));
-       rthdr->hdr.it_present =
-               cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
-                           (1 << IEEE80211_RADIOTAP_CHANNEL));
+       /* room for the radiotap header based on driver features */
+       needed_headroom = ieee80211_rx_radiotap_len(local, status);
 
-       if (rate) {
-               rthdr->rate_or_pad = rate->bitrate / 5;
-               rthdr->hdr.it_present |=
-                       cpu_to_le32(1 << IEEE80211_RADIOTAP_RATE);
-       }
-       rthdr->chan_freq = cpu_to_le16(status->freq);
+       if (skb_headroom(skb) < needed_headroom &&
+           pskb_expand_head(skb, needed_headroom, 0, GFP_ATOMIC))
+               goto out_free_skb;
 
-       if (status->band == IEEE80211_BAND_5GHZ)
-               rthdr->chan_flags = cpu_to_le16(IEEE80211_CHAN_OFDM |
-                                               IEEE80211_CHAN_5GHZ);
-       else
-               rthdr->chan_flags = cpu_to_le16(IEEE80211_CHAN_DYN |
-                                               IEEE80211_CHAN_2GHZ);
+       /* prepend radiotap information */
+       ieee80211_add_rx_radiotap_header(local, skb, rate, needed_headroom);
 
        skb_set_mac_header(skb, 0);
        skb->ip_summed = CHECKSUM_UNNECESSARY;
index 9270771702fe9a5a12fef9fcde4554f30b18b58d..33cd169013781321a813e10ebfb474c9595bd857 100644 (file)
@@ -13,6 +13,7 @@
  */
 
 #include <linux/if_arp.h>
+#include <linux/etherdevice.h>
 #include <linux/rtnetlink.h>
 #include <linux/pm_qos.h>
 #include <net/sch_generic.h>
@@ -103,16 +104,35 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
        cbss->free_priv = ieee80211_rx_bss_free;
        bss = (void *)cbss->priv;
 
+       if (elems->parse_error) {
+               if (beacon)
+                       bss->corrupt_data |= IEEE80211_BSS_CORRUPT_BEACON;
+               else
+                       bss->corrupt_data |= IEEE80211_BSS_CORRUPT_PROBE_RESP;
+       } else {
+               if (beacon)
+                       bss->corrupt_data &= ~IEEE80211_BSS_CORRUPT_BEACON;
+               else
+                       bss->corrupt_data &= ~IEEE80211_BSS_CORRUPT_PROBE_RESP;
+       }
+
        /* save the ERP value so that it is available at association time */
-       if (elems->erp_info && elems->erp_info_len >= 1) {
+       if (elems->erp_info && elems->erp_info_len >= 1 &&
+                       (!elems->parse_error ||
+                        !(bss->valid_data & IEEE80211_BSS_VALID_ERP))) {
                bss->erp_value = elems->erp_info[0];
                bss->has_erp_value = true;
+               if (!elems->parse_error)
+                       bss->valid_data |= IEEE80211_BSS_VALID_ERP;
        }
 
-       if (elems->tim) {
+       if (elems->tim && (!elems->parse_error ||
+                          !(bss->valid_data & IEEE80211_BSS_VALID_DTIM))) {
                struct ieee80211_tim_ie *tim_ie =
                        (struct ieee80211_tim_ie *)elems->tim;
                bss->dtim_period = tim_ie->dtim_period;
+               if (!elems->parse_error)
+                               bss->valid_data |= IEEE80211_BSS_VALID_DTIM;
        }
 
        /* If the beacon had no TIM IE, or it was invalid, use 1 */
@@ -120,26 +140,38 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
                bss->dtim_period = 1;
 
        /* replace old supported rates if we get new values */
-       srlen = 0;
-       if (elems->supp_rates) {
-               clen = IEEE80211_MAX_SUPP_RATES;
-               if (clen > elems->supp_rates_len)
-                       clen = elems->supp_rates_len;
-               memcpy(bss->supp_rates, elems->supp_rates, clen);
-               srlen += clen;
-       }
-       if (elems->ext_supp_rates) {
-               clen = IEEE80211_MAX_SUPP_RATES - srlen;
-               if (clen > elems->ext_supp_rates_len)
-                       clen = elems->ext_supp_rates_len;
-               memcpy(bss->supp_rates + srlen, elems->ext_supp_rates, clen);
-               srlen += clen;
+       if (!elems->parse_error ||
+           !(bss->valid_data & IEEE80211_BSS_VALID_RATES)) {
+               srlen = 0;
+               if (elems->supp_rates) {
+                       clen = IEEE80211_MAX_SUPP_RATES;
+                       if (clen > elems->supp_rates_len)
+                               clen = elems->supp_rates_len;
+                       memcpy(bss->supp_rates, elems->supp_rates, clen);
+                       srlen += clen;
+               }
+               if (elems->ext_supp_rates) {
+                       clen = IEEE80211_MAX_SUPP_RATES - srlen;
+                       if (clen > elems->ext_supp_rates_len)
+                               clen = elems->ext_supp_rates_len;
+                       memcpy(bss->supp_rates + srlen, elems->ext_supp_rates,
+                              clen);
+                       srlen += clen;
+               }
+               if (srlen) {
+                       bss->supp_rates_len = srlen;
+                       if (!elems->parse_error)
+                               bss->valid_data |= IEEE80211_BSS_VALID_RATES;
+               }
        }
-       if (srlen)
-               bss->supp_rates_len = srlen;
 
-       bss->wmm_used = elems->wmm_param || elems->wmm_info;
-       bss->uapsd_supported = is_uapsd_supported(elems);
+       if (!elems->parse_error ||
+           !(bss->valid_data & IEEE80211_BSS_VALID_WMM)) {
+               bss->wmm_used = elems->wmm_param || elems->wmm_info;
+               bss->uapsd_supported = is_uapsd_supported(elems);
+               if (!elems->parse_error)
+                       bss->valid_data |= IEEE80211_BSS_VALID_WMM;
+       }
 
        if (!beacon)
                bss->last_probe_resp = jiffies;
@@ -176,7 +208,7 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
        presp = ieee80211_is_probe_resp(fc);
        if (presp) {
                /* ignore ProbeResp to foreign address */
-               if (memcmp(mgmt->da, sdata->vif.addr, ETH_ALEN))
+               if (compare_ether_addr(mgmt->da, sdata->vif.addr))
                        return RX_DROP_MONITOR;
 
                presp = true;
index 4034ee6160222e8b3343ab91863c4b454acd8b16..38137cb5f6f05877a6aadca7fcb846d0062df648 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/etherdevice.h>
 #include <linux/netdevice.h>
 #include <linux/types.h>
 #include <linux/slab.h>
@@ -101,7 +102,7 @@ struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata,
                                    lockdep_is_held(&local->sta_mtx));
        while (sta) {
                if (sta->sdata == sdata &&
-                   memcmp(sta->sta.addr, addr, ETH_ALEN) == 0)
+                   compare_ether_addr(sta->sta.addr, addr) == 0)
                        break;
                sta = rcu_dereference_check(sta->hnext,
                                            lockdep_is_held(&local->sta_mtx));
@@ -124,7 +125,7 @@ struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata,
        while (sta) {
                if ((sta->sdata == sdata ||
                     (sta->sdata->bss && sta->sdata->bss == sdata->bss)) &&
-                   memcmp(sta->sta.addr, addr, ETH_ALEN) == 0)
+                   compare_ether_addr(sta->sta.addr, addr) == 0)
                        break;
                sta = rcu_dereference_check(sta->hnext,
                                            lockdep_is_held(&local->sta_mtx));
@@ -865,8 +866,10 @@ int sta_info_flush(struct ieee80211_local *local,
 
        mutex_lock(&local->sta_mtx);
        list_for_each_entry_safe(sta, tmp, &local->sta_list, list) {
-               if (!sdata || sdata == sta->sdata)
+               if (!sdata || sdata == sta->sdata) {
                        WARN_ON(__sta_info_destroy(sta));
+                       ret++;
+               }
        }
        mutex_unlock(&local->sta_mtx);
 
@@ -1048,7 +1051,7 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
         * exchange. Also set EOSP to indicate this packet
         * ends the poll/service period.
         */
-       info->flags |= IEEE80211_TX_CTL_POLL_RESPONSE |
+       info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER |
                       IEEE80211_TX_STATUS_EOSP |
                       IEEE80211_TX_CTL_REQ_TX_STATUS;
 
@@ -1175,7 +1178,7 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
                         * STA may still remain is PS mode after this frame
                         * exchange.
                         */
-                       info->flags |= IEEE80211_TX_CTL_POLL_RESPONSE;
+                       info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER;
 
                        /*
                         * Use MoreData flag to indicate whether there are
index 23a97c9dc042f9caa284e4536f2deb28f1ce44ab..ab0576827baf84c9b22a0b0aef2177699c856adf 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/if_ether.h>
 #include <linux/workqueue.h>
 #include <linux/average.h>
+#include <linux/etherdevice.h>
 #include "key.h"
 
 /**
@@ -489,7 +490,7 @@ void for_each_sta_info_type_check(struct ieee80211_local *local,
                nxt = _sta ? rcu_dereference(_sta->hnext) : NULL        \
             )                                                          \
        /* compare address and run code only if it matches */           \
-       if (memcmp(_sta->sta.addr, (_addr), ETH_ALEN) == 0)
+       if (compare_ether_addr(_sta->sta.addr, (_addr)) == 0)
 
 /*
  * Get STA info by index, BROKEN!
@@ -528,6 +529,9 @@ void sta_info_init(struct ieee80211_local *local);
 void sta_info_stop(struct ieee80211_local *local);
 int sta_info_flush(struct ieee80211_local *local,
                   struct ieee80211_sub_if_data *sdata);
+void sta_set_rate_info_tx(struct sta_info *sta,
+                         const struct ieee80211_tx_rate *rate,
+                         struct rate_info *rinfo);
 void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
                          unsigned long exp_time);
 
index d67f0b967f8abcfd3a5b8dac8b0504a7d41b0a63..5f8f89e89d6b446e989d9d3ae546174a711e016f 100644 (file)
@@ -10,7 +10,9 @@
  */
 
 #include <linux/export.h>
+#include <linux/etherdevice.h>
 #include <net/mac80211.h>
+#include <asm/unaligned.h>
 #include "ieee80211_i.h"
 #include "rate.h"
 #include "mesh.h"
@@ -376,7 +378,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
 
        for_each_sta_info(local, hdr->addr1, sta, tmp) {
                /* skip wrong virtual interface */
-               if (memcmp(hdr->addr2, sta->sdata->vif.addr, ETH_ALEN))
+               if (compare_ether_addr(hdr->addr2, sta->sdata->vif.addr))
                        continue;
 
                if (info->flags & IEEE80211_TX_STATUS_EOSP)
index 1be0ca2b5936d1430e9a74164834ccf6aa74de2f..570737df2d2244e729c9c9928a902592ccc3d120 100644 (file)
@@ -448,18 +448,23 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
        struct ieee80211_local *local = tx->local;
 
-       if (unlikely(!sta ||
-                    ieee80211_is_probe_resp(hdr->frame_control) ||
-                    ieee80211_is_auth(hdr->frame_control) ||
-                    ieee80211_is_assoc_resp(hdr->frame_control) ||
-                    ieee80211_is_reassoc_resp(hdr->frame_control)))
+       if (unlikely(!sta))
                return TX_CONTINUE;
 
        if (unlikely((test_sta_flag(sta, WLAN_STA_PS_STA) ||
                      test_sta_flag(sta, WLAN_STA_PS_DRIVER)) &&
-                    !(info->flags & IEEE80211_TX_CTL_POLL_RESPONSE))) {
+                    !(info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER))) {
                int ac = skb_get_queue_mapping(tx->skb);
 
+               /* only deauth, disassoc and action are bufferable MMPDUs */
+               if (ieee80211_is_mgmt(hdr->frame_control) &&
+                   !ieee80211_is_deauth(hdr->frame_control) &&
+                   !ieee80211_is_disassoc(hdr->frame_control) &&
+                   !ieee80211_is_action(hdr->frame_control)) {
+                       info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER;
+                       return TX_CONTINUE;
+               }
+
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
                printk(KERN_DEBUG "STA %pM aid %d: PS buffer for AC %d\n",
                       sta->sta.addr, sta->sta.aid, ac);
@@ -625,7 +630,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
                         tx->local->hw.wiphy->frag_threshold);
 
        /* set up the tx rate control struct we give the RC algo */
-       txrc.hw = local_to_hw(tx->local);
+       txrc.hw = &tx->local->hw;
        txrc.sband = sband;
        txrc.bss_conf = &tx->sdata->vif.bss_conf;
        txrc.skb = tx->skb;
@@ -2206,7 +2211,8 @@ void ieee80211_tx_pending(unsigned long data)
 
 /* functions for drivers to get certain frames */
 
-static void ieee80211_beacon_add_tim(struct ieee80211_if_ap *bss,
+static void ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
+                                    struct ieee80211_if_ap *bss,
                                     struct sk_buff *skb,
                                     struct beacon_data *beacon)
 {
@@ -2223,7 +2229,7 @@ static void ieee80211_beacon_add_tim(struct ieee80211_if_ap *bss,
                                          IEEE80211_MAX_AID+1);
 
        if (bss->dtim_count == 0)
-               bss->dtim_count = beacon->dtim_period - 1;
+               bss->dtim_count = sdata->vif.bss_conf.dtim_period - 1;
        else
                bss->dtim_count--;
 
@@ -2231,7 +2237,7 @@ static void ieee80211_beacon_add_tim(struct ieee80211_if_ap *bss,
        *pos++ = WLAN_EID_TIM;
        *pos++ = 4;
        *pos++ = bss->dtim_count;
-       *pos++ = beacon->dtim_period;
+       *pos++ = sdata->vif.bss_conf.dtim_period;
 
        if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf))
                aid0 = 1;
@@ -2324,12 +2330,14 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
                         * of the tim bitmap in mac80211 and the driver.
                         */
                        if (local->tim_in_locked_section) {
-                               ieee80211_beacon_add_tim(ap, skb, beacon);
+                               ieee80211_beacon_add_tim(sdata, ap, skb,
+                                                        beacon);
                        } else {
                                unsigned long flags;
 
                                spin_lock_irqsave(&local->tim_lock, flags);
-                               ieee80211_beacon_add_tim(ap, skb, beacon);
+                               ieee80211_beacon_add_tim(sdata, ap, skb,
+                                                        beacon);
                                spin_unlock_irqrestore(&local->tim_lock, flags);
                        }
 
index 264397aee8114eb6c26f477f877be6e16f4e4c80..32f7a3b3d43ce0f4232ef890f004af5186dceb51 100644 (file)
@@ -572,24 +572,40 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
        size_t left = len;
        u8 *pos = start;
        bool calc_crc = filter != 0;
+       DECLARE_BITMAP(seen_elems, 256);
 
+       bitmap_zero(seen_elems, 256);
        memset(elems, 0, sizeof(*elems));
        elems->ie_start = start;
        elems->total_len = len;
 
        while (left >= 2) {
                u8 id, elen;
+               bool elem_parse_failed;
 
                id = *pos++;
                elen = *pos++;
                left -= 2;
 
-               if (elen > left)
+               if (elen > left) {
+                       elems->parse_error = true;
                        break;
+               }
+
+               if (id != WLAN_EID_VENDOR_SPECIFIC &&
+                   id != WLAN_EID_QUIET &&
+                   test_bit(id, seen_elems)) {
+                       elems->parse_error = true;
+                       left -= elen;
+                       pos += elen;
+                       continue;
+               }
 
                if (calc_crc && id < 64 && (filter & (1ULL << id)))
                        crc = crc32_be(crc, pos - 2, elen + 2);
 
+               elem_parse_failed = false;
+
                switch (id) {
                case WLAN_EID_SSID:
                        elems->ssid = pos;
@@ -615,7 +631,8 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
                        if (elen >= sizeof(struct ieee80211_tim_ie)) {
                                elems->tim = (void *)pos;
                                elems->tim_len = elen;
-                       }
+                       } else
+                               elem_parse_failed = true;
                        break;
                case WLAN_EID_IBSS_PARAMS:
                        elems->ibss_params = pos;
@@ -664,10 +681,14 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
                case WLAN_EID_HT_CAPABILITY:
                        if (elen >= sizeof(struct ieee80211_ht_cap))
                                elems->ht_cap_elem = (void *)pos;
+                       else
+                               elem_parse_failed = true;
                        break;
                case WLAN_EID_HT_INFORMATION:
                        if (elen >= sizeof(struct ieee80211_ht_info))
                                elems->ht_info_elem = (void *)pos;
+                       else
+                               elem_parse_failed = true;
                        break;
                case WLAN_EID_MESH_ID:
                        elems->mesh_id = pos;
@@ -676,6 +697,8 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
                case WLAN_EID_MESH_CONFIG:
                        if (elen >= sizeof(struct ieee80211_meshconf_ie))
                                elems->mesh_config = (void *)pos;
+                       else
+                               elem_parse_failed = true;
                        break;
                case WLAN_EID_PEER_MGMT:
                        elems->peering = pos;
@@ -696,6 +719,8 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
                case WLAN_EID_RANN:
                        if (elen >= sizeof(struct ieee80211_rann_ie))
                                elems->rann = (void *)pos;
+                       else
+                               elem_parse_failed = true;
                        break;
                case WLAN_EID_CHANNEL_SWITCH:
                        elems->ch_switch_elem = pos;
@@ -724,10 +749,18 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
                        break;
                }
 
+               if (elem_parse_failed)
+                       elems->parse_error = true;
+               else
+                       set_bit(id, seen_elems);
+
                left -= elen;
                pos += elen;
        }
 
+       if (left != 0)
+               elems->parse_error = true;
+
        return crc;
 }
 
@@ -737,7 +770,8 @@ void ieee802_11_parse_elems(u8 *start, size_t len,
        ieee802_11_parse_elems_crc(start, len, elems, 0, 0);
 }
 
-void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
+void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
+                              bool bss_notify)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_tx_queue_params qparam;
@@ -753,7 +787,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
        use_11b = (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) &&
                 !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE);
 
-       for (queue = 0; queue < local_to_hw(local)->queues; queue++) {
+       for (queue = 0; queue < local->hw.queues; queue++) {
                /* Set defaults according to 802.11-2007 Table 7-37 */
                aCWmax = 1023;
                if (use_11b)
@@ -807,7 +841,9 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
        if (sdata->vif.type != NL80211_IFTYPE_MONITOR) {
                sdata->vif.bss_conf.qos =
                        sdata->vif.type != NL80211_IFTYPE_STATION;
-               ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS);
+               if (bss_notify)
+                       ieee80211_bss_info_change_notify(sdata,
+                                                        BSS_CHANGED_QOS);
        }
 }
 
@@ -829,7 +865,7 @@ void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
        else
                sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
 
-       ieee80211_set_wmm_default(sdata);
+       ieee80211_set_wmm_default(sdata, true);
 }
 
 u32 ieee80211_mandatory_rates(struct ieee80211_local *local,
index f8ac4ef0b7949827a49befea4fb1d6419b41fdde..0c6f67e8f2e5c22e281c34b62b27f171db0c2fb5 100644 (file)
@@ -103,6 +103,16 @@ config NF_CONNTRACK_EVENTS
 
          If unsure, say `N'.
 
+config NF_CONNTRACK_TIMEOUT
+       bool  'Connection tracking timeout'
+       depends on NETFILTER_ADVANCED
+       help
+         This option enables support for connection tracking timeout
+         extension. This allows you to attach timeout policies to flow
+         via the CT target.
+
+         If unsure, say `N'.
+
 config NF_CONNTRACK_TIMESTAMP
        bool  'Connection tracking timestamping'
        depends on NETFILTER_ADVANCED
@@ -314,6 +324,17 @@ config NF_CT_NETLINK
        help
          This option enables support for a netlink-based userspace interface
 
+config NF_CT_NETLINK_TIMEOUT
+       tristate  'Connection tracking timeout tuning via Netlink'
+       select NETFILTER_NETLINK
+       depends on NETFILTER_ADVANCED
+       help
+         This option enables support for connection tracking timeout
+         fine-grain tuning. This allows you to attach specific timeout
+         policies to flows, instead of using the global timeout policy.
+
+         If unsure, say `N'.
+
 endif # NF_CONNTRACK
 
 # transparent proxy support
@@ -524,6 +545,15 @@ config NETFILTER_XT_TARGET_LED
          For more information on the LEDs available on your system, see
          Documentation/leds/leds-class.txt
 
+config NETFILTER_XT_TARGET_LOG
+       tristate "LOG target support"
+       default m if NETFILTER_ADVANCED=n
+       help
+         This option adds a `LOG' target, which allows you to create rules in
+         any iptables table which records the packet header to the syslog.
+
+         To compile it as a module, choose M here.  If unsure, say N.
+
 config NETFILTER_XT_TARGET_MARK
        tristate '"MARK" target support'
        depends on NETFILTER_ADVANCED
index 40f4c3d636c583d0deb95fa1af959e967c635c87..ca3676586f51570c49fed1312390111e13cc10db 100644 (file)
@@ -1,6 +1,7 @@
 netfilter-objs := core.o nf_log.o nf_queue.o nf_sockopt.o
 
 nf_conntrack-y := nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_expect.o nf_conntrack_helper.o nf_conntrack_proto.o nf_conntrack_l3proto_generic.o nf_conntrack_proto_generic.o nf_conntrack_proto_tcp.o nf_conntrack_proto_udp.o nf_conntrack_extend.o nf_conntrack_acct.o
+nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMEOUT) += nf_conntrack_timeout.o
 nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMESTAMP) += nf_conntrack_timestamp.o
 nf_conntrack-$(CONFIG_NF_CONNTRACK_EVENTS) += nf_conntrack_ecache.o
 
@@ -22,6 +23,7 @@ obj-$(CONFIG_NF_CT_PROTO_UDPLITE) += nf_conntrack_proto_udplite.o
 
 # netlink interface for nf_conntrack
 obj-$(CONFIG_NF_CT_NETLINK) += nf_conntrack_netlink.o
+obj-$(CONFIG_NF_CT_NETLINK_TIMEOUT) += nfnetlink_cttimeout.o
 
 # connection tracking helpers
 nf_conntrack_h323-objs := nf_conntrack_h323_main.o nf_conntrack_h323_asn1.o
@@ -58,6 +60,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_CT) += xt_CT.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_HL) += xt_HL.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o
+obj-$(CONFIG_NETFILTER_XT_TARGET_LOG) += xt_LOG.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o
index e3e73997c3be3f260f276c126a8e5c1dc853d682..a72a4dff0031b72ac26412fe953d3f90d698a790 100644 (file)
@@ -442,7 +442,7 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map,
        map->timeout = IPSET_NO_TIMEOUT;
 
        set->data = map;
-       set->family = AF_INET;
+       set->family = NFPROTO_IPV4;
 
        return true;
 }
@@ -550,7 +550,7 @@ static struct ip_set_type bitmap_ip_type __read_mostly = {
        .protocol       = IPSET_PROTOCOL,
        .features       = IPSET_TYPE_IP,
        .dimension      = IPSET_DIM_ONE,
-       .family         = AF_INET,
+       .family         = NFPROTO_IPV4,
        .revision_min   = 0,
        .revision_max   = 0,
        .create         = bitmap_ip_create,
index 56096f544978e68ce089524e15bd3cb23dff389b..81324c12c5bec09a288cc39a60ea1c920da2ec62 100644 (file)
@@ -543,7 +543,7 @@ init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,
        map->timeout = IPSET_NO_TIMEOUT;
 
        set->data = map;
-       set->family = AF_INET;
+       set->family = NFPROTO_IPV4;
 
        return true;
 }
@@ -623,7 +623,7 @@ static struct ip_set_type bitmap_ipmac_type = {
        .protocol       = IPSET_PROTOCOL,
        .features       = IPSET_TYPE_IP | IPSET_TYPE_MAC,
        .dimension      = IPSET_DIM_TWO,
-       .family         = AF_INET,
+       .family         = NFPROTO_IPV4,
        .revision_min   = 0,
        .revision_max   = 0,
        .create         = bitmap_ipmac_create,
index 29ba93bb94be14268877354e69c7fe46d57cf7eb..382ec28ba72efc1fd420eeb38153825593375ba8 100644 (file)
@@ -422,7 +422,7 @@ init_map_port(struct ip_set *set, struct bitmap_port *map,
        map->timeout = IPSET_NO_TIMEOUT;
 
        set->data = map;
-       set->family = AF_UNSPEC;
+       set->family = NFPROTO_UNSPEC;
 
        return true;
 }
@@ -483,7 +483,7 @@ static struct ip_set_type bitmap_port_type = {
        .protocol       = IPSET_PROTOCOL,
        .features       = IPSET_TYPE_PORT,
        .dimension      = IPSET_DIM_ONE,
-       .family         = AF_UNSPEC,
+       .family         = NFPROTO_UNSPEC,
        .revision_min   = 0,
        .revision_max   = 0,
        .create         = bitmap_port_create,
index e7f90e7082b4bd93d8a8c84382626a3ab151de5b..e6c1c9605a58804fe514406b4a272d7ba1badfd2 100644 (file)
@@ -69,7 +69,7 @@ find_set_type(const char *name, u8 family, u8 revision)
 
        list_for_each_entry_rcu(type, &ip_set_type_list, list)
                if (STREQ(type->name, name) &&
-                   (type->family == family || type->family == AF_UNSPEC) &&
+                   (type->family == family || type->family == NFPROTO_UNSPEC) &&
                    revision >= type->revision_min &&
                    revision <= type->revision_max)
                        return type;
@@ -149,7 +149,7 @@ __find_set_type_minmax(const char *name, u8 family, u8 *min, u8 *max,
        rcu_read_lock();
        list_for_each_entry_rcu(type, &ip_set_type_list, list)
                if (STREQ(type->name, name) &&
-                   (type->family == family || type->family == AF_UNSPEC)) {
+                   (type->family == family || type->family == NFPROTO_UNSPEC)) {
                        found = true;
                        if (type->revision_min < *min)
                                *min = type->revision_min;
@@ -164,8 +164,8 @@ __find_set_type_minmax(const char *name, u8 family, u8 *min, u8 *max,
                __find_set_type_minmax(name, family, min, max, true);
 }
 
-#define family_name(f) ((f) == AF_INET ? "inet" : \
-                        (f) == AF_INET6 ? "inet6" : "any")
+#define family_name(f) ((f) == NFPROTO_IPV4 ? "inet" : \
+                        (f) == NFPROTO_IPV6 ? "inet6" : "any")
 
 /* Register a set type structure. The type is identified by
  * the unique triple of name, family and revision.
@@ -354,7 +354,7 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
        pr_debug("set %s, index %u\n", set->name, index);
 
        if (opt->dim < set->type->dimension ||
-           !(opt->family == set->family || set->family == AF_UNSPEC))
+           !(opt->family == set->family || set->family == NFPROTO_UNSPEC))
                return 0;
 
        read_lock_bh(&set->lock);
@@ -387,7 +387,7 @@ ip_set_add(ip_set_id_t index, const struct sk_buff *skb,
        pr_debug("set %s, index %u\n", set->name, index);
 
        if (opt->dim < set->type->dimension ||
-           !(opt->family == set->family || set->family == AF_UNSPEC))
+           !(opt->family == set->family || set->family == NFPROTO_UNSPEC))
                return 0;
 
        write_lock_bh(&set->lock);
@@ -410,7 +410,7 @@ ip_set_del(ip_set_id_t index, const struct sk_buff *skb,
        pr_debug("set %s, index %u\n", set->name, index);
 
        if (opt->dim < set->type->dimension ||
-           !(opt->family == set->family || set->family == AF_UNSPEC))
+           !(opt->family == set->family || set->family == NFPROTO_UNSPEC))
                return 0;
 
        write_lock_bh(&set->lock);
@@ -575,7 +575,7 @@ start_msg(struct sk_buff *skb, u32 pid, u32 seq, unsigned int flags,
                return NULL;
 
        nfmsg = nlmsg_data(nlh);
-       nfmsg->nfgen_family = AF_INET;
+       nfmsg->nfgen_family = NFPROTO_IPV4;
        nfmsg->version = NFNETLINK_V0;
        nfmsg->res_id = 0;
 
index 1f03556666f4196cf74e6e0b8433f27756c65ede..6fdf88ae2353b67be38c307fd8d4cb114594e624 100644 (file)
@@ -136,10 +136,10 @@ ip_set_get_ip_port(const struct sk_buff *skb, u8 pf, bool src, __be16 *port)
        u8 proto;
 
        switch (pf) {
-       case AF_INET:
+       case NFPROTO_IPV4:
                ret = ip_set_get_ip4_port(skb, src, port, &proto);
                break;
-       case AF_INET6:
+       case NFPROTO_IPV6:
                ret = ip_set_get_ip6_port(skb, src, port, &proto);
                break;
        default:
index 4015fcaf87bc9556726e5a73b1ebaae1ab29595c..5139dea6019e44ba24ee01d9c4f65beb3eddfe61 100644 (file)
@@ -366,11 +366,11 @@ hash_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
        u8 netmask, hbits;
        struct ip_set_hash *h;
 
-       if (!(set->family == AF_INET || set->family == AF_INET6))
+       if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
                return -IPSET_ERR_INVALID_FAMILY;
-       netmask = set->family == AF_INET ? 32 : 128;
+       netmask = set->family == NFPROTO_IPV4 ? 32 : 128;
        pr_debug("Create set %s with family %s\n",
-                set->name, set->family == AF_INET ? "inet" : "inet6");
+                set->name, set->family == NFPROTO_IPV4 ? "inet" : "inet6");
 
        if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
@@ -389,8 +389,8 @@ hash_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
        if (tb[IPSET_ATTR_NETMASK]) {
                netmask = nla_get_u8(tb[IPSET_ATTR_NETMASK]);
 
-               if ((set->family == AF_INET && netmask > 32) ||
-                   (set->family == AF_INET6 && netmask > 128) ||
+               if ((set->family == NFPROTO_IPV4 && netmask > 32) ||
+                   (set->family == NFPROTO_IPV6 && netmask > 128) ||
                    netmask == 0)
                        return -IPSET_ERR_INVALID_NETMASK;
        }
@@ -419,15 +419,15 @@ hash_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
        if (tb[IPSET_ATTR_TIMEOUT]) {
                h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
 
-               set->variant = set->family == AF_INET
+               set->variant = set->family == NFPROTO_IPV4
                        ? &hash_ip4_tvariant : &hash_ip6_tvariant;
 
-               if (set->family == AF_INET)
+               if (set->family == NFPROTO_IPV4)
                        hash_ip4_gc_init(set);
                else
                        hash_ip6_gc_init(set);
        } else {
-               set->variant = set->family == AF_INET
+               set->variant = set->family == NFPROTO_IPV4
                        ? &hash_ip4_variant : &hash_ip6_variant;
        }
 
@@ -443,7 +443,7 @@ static struct ip_set_type hash_ip_type __read_mostly = {
        .protocol       = IPSET_PROTOCOL,
        .features       = IPSET_TYPE_IP,
        .dimension      = IPSET_DIM_ONE,
-       .family         = AF_UNSPEC,
+       .family         = NFPROTO_UNSPEC,
        .revision_min   = 0,
        .revision_max   = 0,
        .create         = hash_ip_create,
index 37d667e3f6f82d82e442b66d4c38dd592cba06d3..9c27e249c1713bb14d9d03c730bd2a5a125c6177 100644 (file)
@@ -450,7 +450,7 @@ hash_ipport_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
        u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
        u8 hbits;
 
-       if (!(set->family == AF_INET || set->family == AF_INET6))
+       if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
                return -IPSET_ERR_INVALID_FAMILY;
 
        if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
@@ -490,15 +490,15 @@ hash_ipport_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
        if (tb[IPSET_ATTR_TIMEOUT]) {
                h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
 
-               set->variant = set->family == AF_INET
+               set->variant = set->family == NFPROTO_IPV4
                        ? &hash_ipport4_tvariant : &hash_ipport6_tvariant;
 
-               if (set->family == AF_INET)
+               if (set->family == NFPROTO_IPV4)
                        hash_ipport4_gc_init(set);
                else
                        hash_ipport6_gc_init(set);
        } else {
-               set->variant = set->family == AF_INET
+               set->variant = set->family == NFPROTO_IPV4
                        ? &hash_ipport4_variant : &hash_ipport6_variant;
        }
 
@@ -514,7 +514,7 @@ static struct ip_set_type hash_ipport_type __read_mostly = {
        .protocol       = IPSET_PROTOCOL,
        .features       = IPSET_TYPE_IP | IPSET_TYPE_PORT,
        .dimension      = IPSET_DIM_TWO,
-       .family         = AF_UNSPEC,
+       .family         = NFPROTO_UNSPEC,
        .revision_min   = 0,
        .revision_max   = 1,    /* SCTP and UDPLITE support added */
        .create         = hash_ipport_create,
index e69e2718fbe162343eaf97defd30153155ee2ef1..9134057c07284cf41b1e2d119415e8c043a0fc9a 100644 (file)
@@ -468,7 +468,7 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
        u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
        u8 hbits;
 
-       if (!(set->family == AF_INET || set->family == AF_INET6))
+       if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
                return -IPSET_ERR_INVALID_FAMILY;
 
        if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
@@ -508,15 +508,15 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
        if (tb[IPSET_ATTR_TIMEOUT]) {
                h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
 
-               set->variant = set->family == AF_INET
+               set->variant = set->family == NFPROTO_IPV4
                        ? &hash_ipportip4_tvariant : &hash_ipportip6_tvariant;
 
-               if (set->family == AF_INET)
+               if (set->family == NFPROTO_IPV4)
                        hash_ipportip4_gc_init(set);
                else
                        hash_ipportip6_gc_init(set);
        } else {
-               set->variant = set->family == AF_INET
+               set->variant = set->family == NFPROTO_IPV4
                        ? &hash_ipportip4_variant : &hash_ipportip6_variant;
        }
 
@@ -532,7 +532,7 @@ static struct ip_set_type hash_ipportip_type __read_mostly = {
        .protocol       = IPSET_PROTOCOL,
        .features       = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2,
        .dimension      = IPSET_DIM_THREE,
-       .family         = AF_UNSPEC,
+       .family         = NFPROTO_UNSPEC,
        .revision_min   = 0,
        .revision_max   = 1,    /* SCTP and UDPLITE support added */
        .create         = hash_ipportip_create,
index 64199b4e93c952e24ca8c5508af1d3788b1286f8..5d05e69698626570ca8247732d4bb8f8af632674 100644 (file)
@@ -41,12 +41,19 @@ hash_ipportnet_same_set(const struct ip_set *a, const struct ip_set *b);
 
 /* The type variant functions: IPv4 */
 
+/* We squeeze the "nomatch" flag into cidr: we don't support cidr == 0
+ * However this way we have to store internally cidr - 1,
+ * dancing back and forth.
+ */
+#define IP_SET_HASH_WITH_NETS_PACKED
+
 /* Member elements without timeout */
 struct hash_ipportnet4_elem {
        __be32 ip;
        __be32 ip2;
        __be16 port;
-       u8 cidr;
+       u8 cidr:7;
+       u8 nomatch:1;
        u8 proto;
 };
 
@@ -55,7 +62,8 @@ struct hash_ipportnet4_telem {
        __be32 ip;
        __be32 ip2;
        __be16 port;
-       u8 cidr;
+       u8 cidr:7;
+       u8 nomatch:1;
        u8 proto;
        unsigned long timeout;
 };
@@ -85,11 +93,23 @@ hash_ipportnet4_data_copy(struct hash_ipportnet4_elem *dst,
        memcpy(dst, src, sizeof(*dst));
 }
 
+static inline void
+hash_ipportnet4_data_flags(struct hash_ipportnet4_elem *dst, u32 flags)
+{
+       dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH);
+}
+
+static inline bool
+hash_ipportnet4_data_match(const struct hash_ipportnet4_elem *elem)
+{
+       return !elem->nomatch;
+}
+
 static inline void
 hash_ipportnet4_data_netmask(struct hash_ipportnet4_elem *elem, u8 cidr)
 {
        elem->ip2 &= ip_set_netmask(cidr);
-       elem->cidr = cidr;
+       elem->cidr = cidr - 1;
 }
 
 static inline void
@@ -102,11 +122,15 @@ static bool
 hash_ipportnet4_data_list(struct sk_buff *skb,
                          const struct hash_ipportnet4_elem *data)
 {
+       u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
+
        NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
        NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP2, data->ip2);
        NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
-       NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr);
+       NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr + 1);
        NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
+       if (flags)
+               NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
        return 0;
 
 nla_put_failure:
@@ -119,14 +143,17 @@ hash_ipportnet4_data_tlist(struct sk_buff *skb,
 {
        const struct hash_ipportnet4_telem *tdata =
                (const struct hash_ipportnet4_telem *)data;
+       u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
 
        NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip);
        NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP2, tdata->ip2);
        NLA_PUT_NET16(skb, IPSET_ATTR_PORT, tdata->port);
-       NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr);
+       NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr + 1);
        NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
        NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
                      htonl(ip_set_timeout_get(tdata->timeout)));
+       if (flags)
+               NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
 
        return 0;
 
@@ -158,13 +185,11 @@ hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_ipportnet4_elem data = {
-               .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
+               .cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1
        };
 
-       if (data.cidr == 0)
-               return -EINVAL;
        if (adt == IPSET_TEST)
-               data.cidr = HOST_MASK;
+               data.cidr = HOST_MASK - 1;
 
        if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
                                 &data.port, &data.proto))
@@ -172,7 +197,7 @@ hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
 
        ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
        ip4addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &data.ip2);
-       data.ip2 &= ip_set_netmask(data.cidr);
+       data.ip2 &= ip_set_netmask(data.cidr + 1);
 
        return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
 }
@@ -183,17 +208,19 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
 {
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
-       struct hash_ipportnet4_elem data = { .cidr = HOST_MASK };
+       struct hash_ipportnet4_elem data = { .cidr = HOST_MASK - 1 };
        u32 ip, ip_to = 0, p = 0, port, port_to;
        u32 ip2_from = 0, ip2_to, ip2_last, ip2;
        u32 timeout = h->timeout;
        bool with_ports = false;
+       u8 cidr;
        int ret;
 
        if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
                     !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
-                    !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
+                    !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
+                    !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
                return -IPSET_ERR_PROTOCOL;
 
        if (tb[IPSET_ATTR_LINENO])
@@ -208,9 +235,10 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
                return ret;
 
        if (tb[IPSET_ATTR_CIDR2]) {
-               data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
-               if (!data.cidr)
+               cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
+               if (!cidr || cidr > HOST_MASK)
                        return -IPSET_ERR_INVALID_CIDR;
+               data.cidr = cidr - 1;
        }
 
        if (tb[IPSET_ATTR_PORT])
@@ -236,12 +264,18 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
                timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
        }
 
+       if (tb[IPSET_ATTR_CADT_FLAGS] && adt == IPSET_ADD) {
+               u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
+               if (cadt_flags & IPSET_FLAG_NOMATCH)
+                       flags |= (cadt_flags << 16);
+       }
+
        with_ports = with_ports && tb[IPSET_ATTR_PORT_TO];
        if (adt == IPSET_TEST ||
            !(tb[IPSET_ATTR_CIDR] || tb[IPSET_ATTR_IP_TO] || with_ports ||
              tb[IPSET_ATTR_IP2_TO])) {
                data.ip = htonl(ip);
-               data.ip2 = htonl(ip2_from & ip_set_hostmask(data.cidr));
+               data.ip2 = htonl(ip2_from & ip_set_hostmask(data.cidr + 1));
                ret = adtfn(set, &data, timeout, flags);
                return ip_set_eexist(ret, flags) ? 0 : ret;
        }
@@ -275,7 +309,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
                if (ip2_from + UINT_MAX == ip2_to)
                        return -IPSET_ERR_HASH_RANGE;
        } else {
-               ip_set_mask_from_to(ip2_from, ip2_to, data.cidr);
+               ip_set_mask_from_to(ip2_from, ip2_to, data.cidr + 1);
        }
 
        if (retried)
@@ -290,7 +324,8 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
                        while (!after(ip2, ip2_to)) {
                                data.ip2 = htonl(ip2);
                                ip2_last = ip_set_range_to_cidr(ip2, ip2_to,
-                                                               &data.cidr);
+                                                               &cidr);
+                               data.cidr = cidr - 1;
                                ret = adtfn(set, &data, timeout, flags);
 
                                if (ret && !ip_set_eexist(ret, flags))
@@ -321,7 +356,8 @@ struct hash_ipportnet6_elem {
        union nf_inet_addr ip;
        union nf_inet_addr ip2;
        __be16 port;
-       u8 cidr;
+       u8 cidr:7;
+       u8 nomatch:1;
        u8 proto;
 };
 
@@ -329,7 +365,8 @@ struct hash_ipportnet6_telem {
        union nf_inet_addr ip;
        union nf_inet_addr ip2;
        __be16 port;
-       u8 cidr;
+       u8 cidr:7;
+       u8 nomatch:1;
        u8 proto;
        unsigned long timeout;
 };
@@ -359,6 +396,18 @@ hash_ipportnet6_data_copy(struct hash_ipportnet6_elem *dst,
        memcpy(dst, src, sizeof(*dst));
 }
 
+static inline void
+hash_ipportnet6_data_flags(struct hash_ipportnet6_elem *dst, u32 flags)
+{
+       dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH);
+}
+
+static inline bool
+hash_ipportnet6_data_match(const struct hash_ipportnet6_elem *elem)
+{
+       return !elem->nomatch;
+}
+
 static inline void
 hash_ipportnet6_data_zero_out(struct hash_ipportnet6_elem *elem)
 {
@@ -378,18 +427,22 @@ static inline void
 hash_ipportnet6_data_netmask(struct hash_ipportnet6_elem *elem, u8 cidr)
 {
        ip6_netmask(&elem->ip2, cidr);
-       elem->cidr = cidr;
+       elem->cidr = cidr - 1;
 }
 
 static bool
 hash_ipportnet6_data_list(struct sk_buff *skb,
                          const struct hash_ipportnet6_elem *data)
 {
+       u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
+
        NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
        NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP2, &data->ip2);
        NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
-       NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr);
+       NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr + 1);
        NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
+       if (flags)
+               NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
        return 0;
 
 nla_put_failure:
@@ -402,14 +455,17 @@ hash_ipportnet6_data_tlist(struct sk_buff *skb,
 {
        const struct hash_ipportnet6_telem *e =
                (const struct hash_ipportnet6_telem *)data;
+       u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
 
        NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
        NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP2, &data->ip2);
        NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
-       NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr);
+       NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr + 1);
        NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
        NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
                      htonl(ip_set_timeout_get(e->timeout)));
+       if (flags)
+               NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
        return 0;
 
 nla_put_failure:
@@ -438,13 +494,11 @@ hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb,
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_ipportnet6_elem data = {
-               .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
+               .cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1
        };
 
-       if (data.cidr == 0)
-               return -EINVAL;
        if (adt == IPSET_TEST)
-               data.cidr = HOST_MASK;
+               data.cidr = HOST_MASK - 1;
 
        if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
                                 &data.port, &data.proto))
@@ -452,7 +506,7 @@ hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb,
 
        ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
        ip6addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &data.ip2.in6);
-       ip6_netmask(&data.ip2, data.cidr);
+       ip6_netmask(&data.ip2, data.cidr + 1);
 
        return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
 }
@@ -463,16 +517,18 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
 {
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
-       struct hash_ipportnet6_elem data = { .cidr = HOST_MASK };
+       struct hash_ipportnet6_elem data = { .cidr = HOST_MASK - 1 };
        u32 port, port_to;
        u32 timeout = h->timeout;
        bool with_ports = false;
+       u8 cidr;
        int ret;
 
        if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
                     !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
+                    !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) ||
                     tb[IPSET_ATTR_IP_TO] ||
                     tb[IPSET_ATTR_CIDR]))
                return -IPSET_ERR_PROTOCOL;
@@ -490,13 +546,14 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
        if (ret)
                return ret;
 
-       if (tb[IPSET_ATTR_CIDR2])
-               data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
-
-       if (!data.cidr)
-               return -IPSET_ERR_INVALID_CIDR;
+       if (tb[IPSET_ATTR_CIDR2]) {
+               cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
+               if (!cidr || cidr > HOST_MASK)
+                       return -IPSET_ERR_INVALID_CIDR;
+               data.cidr = cidr - 1;
+       }
 
-       ip6_netmask(&data.ip2, data.cidr);
+       ip6_netmask(&data.ip2, data.cidr + 1);
 
        if (tb[IPSET_ATTR_PORT])
                data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
@@ -521,6 +578,12 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
                timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
        }
 
+       if (tb[IPSET_ATTR_CADT_FLAGS] && adt == IPSET_ADD) {
+               u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
+               if (cadt_flags & IPSET_FLAG_NOMATCH)
+                       flags |= (cadt_flags << 16);
+       }
+
        if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
                ret = adtfn(set, &data, timeout, flags);
                return ip_set_eexist(ret, flags) ? 0 : ret;
@@ -554,7 +617,7 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
        u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
        u8 hbits;
 
-       if (!(set->family == AF_INET || set->family == AF_INET6))
+       if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
                return -IPSET_ERR_INVALID_FAMILY;
 
        if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
@@ -573,7 +636,7 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
 
        h = kzalloc(sizeof(*h)
                    + sizeof(struct ip_set_hash_nets)
-                     * (set->family == AF_INET ? 32 : 128), GFP_KERNEL);
+                     * (set->family == NFPROTO_IPV4 ? 32 : 128), GFP_KERNEL);
        if (!h)
                return -ENOMEM;
 
@@ -596,16 +659,16 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
        if (tb[IPSET_ATTR_TIMEOUT]) {
                h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
 
-               set->variant = set->family == AF_INET
+               set->variant = set->family == NFPROTO_IPV4
                        ? &hash_ipportnet4_tvariant
                        : &hash_ipportnet6_tvariant;
 
-               if (set->family == AF_INET)
+               if (set->family == NFPROTO_IPV4)
                        hash_ipportnet4_gc_init(set);
                else
                        hash_ipportnet6_gc_init(set);
        } else {
-               set->variant = set->family == AF_INET
+               set->variant = set->family == NFPROTO_IPV4
                        ? &hash_ipportnet4_variant : &hash_ipportnet6_variant;
        }
 
@@ -621,10 +684,11 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = {
        .protocol       = IPSET_PROTOCOL,
        .features       = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2,
        .dimension      = IPSET_DIM_THREE,
-       .family         = AF_UNSPEC,
+       .family         = NFPROTO_UNSPEC,
        .revision_min   = 0,
        /*                1        SCTP and UDPLITE support added */
-       .revision_max   = 2,    /* Range as input support for IPv4 added */
+       /*                2        Range as input support for IPv4 added */
+       .revision_max   = 3,    /* nomatch flag support added */
        .create         = hash_ipportnet_create,
        .create_policy  = {
                [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
@@ -643,6 +707,7 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = {
                [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
                [IPSET_ATTR_CIDR2]      = { .type = NLA_U8 },
                [IPSET_ATTR_PROTO]      = { .type = NLA_U8 },
+               [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
                [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
                [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
        },
index 28988196775e67a39bcf954e004068d2de456db5..7c3d945517cfa55c62faeccb24d6bce29c958faa 100644 (file)
@@ -43,7 +43,7 @@ hash_net_same_set(const struct ip_set *a, const struct ip_set *b);
 struct hash_net4_elem {
        __be32 ip;
        u16 padding0;
-       u8 padding1;
+       u8 nomatch;
        u8 cidr;
 };
 
@@ -51,7 +51,7 @@ struct hash_net4_elem {
 struct hash_net4_telem {
        __be32 ip;
        u16 padding0;
-       u8 padding1;
+       u8 nomatch;
        u8 cidr;
        unsigned long timeout;
 };
@@ -61,7 +61,8 @@ hash_net4_data_equal(const struct hash_net4_elem *ip1,
                     const struct hash_net4_elem *ip2,
                     u32 *multi)
 {
-       return ip1->ip == ip2->ip && ip1->cidr == ip2->cidr;
+       return ip1->ip == ip2->ip &&
+              ip1->cidr == ip2->cidr;
 }
 
 static inline bool
@@ -76,6 +77,19 @@ hash_net4_data_copy(struct hash_net4_elem *dst,
 {
        dst->ip = src->ip;
        dst->cidr = src->cidr;
+       dst->nomatch = src->nomatch;
+}
+
+static inline void
+hash_net4_data_flags(struct hash_net4_elem *dst, u32 flags)
+{
+       dst->nomatch = flags & IPSET_FLAG_NOMATCH;
+}
+
+static inline bool
+hash_net4_data_match(const struct hash_net4_elem *elem)
+{
+       return !elem->nomatch;
 }
 
 static inline void
@@ -95,8 +109,12 @@ hash_net4_data_zero_out(struct hash_net4_elem *elem)
 static bool
 hash_net4_data_list(struct sk_buff *skb, const struct hash_net4_elem *data)
 {
+       u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
+
        NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
        NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
+       if (flags)
+               NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
        return 0;
 
 nla_put_failure:
@@ -108,11 +126,14 @@ hash_net4_data_tlist(struct sk_buff *skb, const struct hash_net4_elem *data)
 {
        const struct hash_net4_telem *tdata =
                (const struct hash_net4_telem *)data;
+       u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
 
        NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip);
        NLA_PUT_U8(skb, IPSET_ATTR_CIDR, tdata->cidr);
        NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
                      htonl(ip_set_timeout_get(tdata->timeout)));
+       if (flags)
+               NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
 
        return 0;
 
@@ -167,7 +188,8 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
        int ret;
 
        if (unlikely(!tb[IPSET_ATTR_IP] ||
-                    !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
+                    !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
+                    !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
                return -IPSET_ERR_PROTOCOL;
 
        if (tb[IPSET_ATTR_LINENO])
@@ -179,7 +201,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
 
        if (tb[IPSET_ATTR_CIDR]) {
                data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
-               if (!data.cidr)
+               if (!data.cidr || data.cidr > HOST_MASK)
                        return -IPSET_ERR_INVALID_CIDR;
        }
 
@@ -189,6 +211,12 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
                timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
        }
 
+       if (tb[IPSET_ATTR_CADT_FLAGS] && adt == IPSET_ADD) {
+               u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
+               if (cadt_flags & IPSET_FLAG_NOMATCH)
+                       flags |= (cadt_flags << 16);
+       }
+
        if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) {
                data.ip = htonl(ip & ip_set_hostmask(data.cidr));
                ret = adtfn(set, &data, timeout, flags);
@@ -236,14 +264,14 @@ hash_net_same_set(const struct ip_set *a, const struct ip_set *b)
 struct hash_net6_elem {
        union nf_inet_addr ip;
        u16 padding0;
-       u8 padding1;
+       u8 nomatch;
        u8 cidr;
 };
 
 struct hash_net6_telem {
        union nf_inet_addr ip;
        u16 padding0;
-       u8 padding1;
+       u8 nomatch;
        u8 cidr;
        unsigned long timeout;
 };
@@ -269,6 +297,19 @@ hash_net6_data_copy(struct hash_net6_elem *dst,
 {
        dst->ip.in6 = src->ip.in6;
        dst->cidr = src->cidr;
+       dst->nomatch = src->nomatch;
+}
+
+static inline void
+hash_net6_data_flags(struct hash_net6_elem *dst, u32 flags)
+{
+       dst->nomatch = flags & IPSET_FLAG_NOMATCH;
+}
+
+static inline bool
+hash_net6_data_match(const struct hash_net6_elem *elem)
+{
+       return !elem->nomatch;
 }
 
 static inline void
@@ -296,8 +337,12 @@ hash_net6_data_netmask(struct hash_net6_elem *elem, u8 cidr)
 static bool
 hash_net6_data_list(struct sk_buff *skb, const struct hash_net6_elem *data)
 {
+       u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
+
        NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
        NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
+       if (flags)
+               NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
        return 0;
 
 nla_put_failure:
@@ -309,11 +354,14 @@ hash_net6_data_tlist(struct sk_buff *skb, const struct hash_net6_elem *data)
 {
        const struct hash_net6_telem *e =
                (const struct hash_net6_telem *)data;
+       u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
 
        NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
        NLA_PUT_U8(skb, IPSET_ATTR_CIDR, e->cidr);
        NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
                      htonl(ip_set_timeout_get(e->timeout)));
+       if (flags)
+               NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
        return 0;
 
 nla_put_failure:
@@ -366,7 +414,8 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *tb[],
        int ret;
 
        if (unlikely(!tb[IPSET_ATTR_IP] ||
-                    !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
+                    !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
+                    !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
                return -IPSET_ERR_PROTOCOL;
        if (unlikely(tb[IPSET_ATTR_IP_TO]))
                return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
@@ -381,7 +430,7 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *tb[],
        if (tb[IPSET_ATTR_CIDR])
                data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
 
-       if (!data.cidr)
+       if (!data.cidr || data.cidr > HOST_MASK)
                return -IPSET_ERR_INVALID_CIDR;
 
        ip6_netmask(&data.ip, data.cidr);
@@ -392,6 +441,12 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *tb[],
                timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
        }
 
+       if (tb[IPSET_ATTR_CADT_FLAGS] && adt == IPSET_ADD) {
+               u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
+               if (cadt_flags & IPSET_FLAG_NOMATCH)
+                       flags |= (cadt_flags << 16);
+       }
+
        ret = adtfn(set, &data, timeout, flags);
 
        return ip_set_eexist(ret, flags) ? 0 : ret;
@@ -406,7 +461,7 @@ hash_net_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
        struct ip_set_hash *h;
        u8 hbits;
 
-       if (!(set->family == AF_INET || set->family == AF_INET6))
+       if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
                return -IPSET_ERR_INVALID_FAMILY;
 
        if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
@@ -425,7 +480,7 @@ hash_net_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
 
        h = kzalloc(sizeof(*h)
                    + sizeof(struct ip_set_hash_nets)
-                     * (set->family == AF_INET ? 32 : 128), GFP_KERNEL);
+                     * (set->family == NFPROTO_IPV4 ? 32 : 128), GFP_KERNEL);
        if (!h)
                return -ENOMEM;
 
@@ -448,15 +503,15 @@ hash_net_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
        if (tb[IPSET_ATTR_TIMEOUT]) {
                h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
 
-               set->variant = set->family == AF_INET
+               set->variant = set->family == NFPROTO_IPV4
                        ? &hash_net4_tvariant : &hash_net6_tvariant;
 
-               if (set->family == AF_INET)
+               if (set->family == NFPROTO_IPV4)
                        hash_net4_gc_init(set);
                else
                        hash_net6_gc_init(set);
        } else {
-               set->variant = set->family == AF_INET
+               set->variant = set->family == NFPROTO_IPV4
                        ? &hash_net4_variant : &hash_net6_variant;
        }
 
@@ -472,9 +527,10 @@ static struct ip_set_type hash_net_type __read_mostly = {
        .protocol       = IPSET_PROTOCOL,
        .features       = IPSET_TYPE_IP,
        .dimension      = IPSET_DIM_ONE,
-       .family         = AF_UNSPEC,
+       .family         = NFPROTO_UNSPEC,
        .revision_min   = 0,
-       .revision_max   = 1,    /* Range as input support for IPv4 added */
+       /*              = 1        Range as input support for IPv4 added */
+       .revision_max   = 2,    /* nomatch flag support added */
        .create         = hash_net_create,
        .create_policy  = {
                [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
@@ -488,6 +544,7 @@ static struct ip_set_type hash_net_type __read_mostly = {
                [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
                [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
                [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+               [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
        },
        .me             = THIS_MODULE,
 };
index e13095deb50d3a9f70ec3c5b5c58899f847d8ee6..f24037ff432201015e81731f61133d45079128d6 100644 (file)
@@ -163,7 +163,8 @@ struct hash_netiface4_elem_hashed {
        __be32 ip;
        u8 physdev;
        u8 cidr;
-       u16 padding;
+       u8 nomatch;
+       u8 padding;
 };
 
 #define HKEY_DATALEN   sizeof(struct hash_netiface4_elem_hashed)
@@ -173,7 +174,8 @@ struct hash_netiface4_elem {
        __be32 ip;
        u8 physdev;
        u8 cidr;
-       u16 padding;
+       u8 nomatch;
+       u8 padding;
        const char *iface;
 };
 
@@ -182,7 +184,8 @@ struct hash_netiface4_telem {
        __be32 ip;
        u8 physdev;
        u8 cidr;
-       u16 padding;
+       u8 nomatch;
+       u8 padding;
        const char *iface;
        unsigned long timeout;
 };
@@ -207,11 +210,25 @@ hash_netiface4_data_isnull(const struct hash_netiface4_elem *elem)
 
 static inline void
 hash_netiface4_data_copy(struct hash_netiface4_elem *dst,
-                        const struct hash_netiface4_elem *src) {
+                        const struct hash_netiface4_elem *src)
+{
        dst->ip = src->ip;
        dst->cidr = src->cidr;
        dst->physdev = src->physdev;
        dst->iface = src->iface;
+       dst->nomatch = src->nomatch;
+}
+
+static inline void
+hash_netiface4_data_flags(struct hash_netiface4_elem *dst, u32 flags)
+{
+       dst->nomatch = flags & IPSET_FLAG_NOMATCH;
+}
+
+static inline bool
+hash_netiface4_data_match(const struct hash_netiface4_elem *elem)
+{
+       return !elem->nomatch;
 }
 
 static inline void
@@ -233,11 +250,13 @@ hash_netiface4_data_list(struct sk_buff *skb,
 {
        u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0;
 
+       if (data->nomatch)
+               flags |= IPSET_FLAG_NOMATCH;
        NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
        NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
        NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface);
        if (flags)
-               NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, flags);
+               NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
        return 0;
 
 nla_put_failure:
@@ -252,11 +271,13 @@ hash_netiface4_data_tlist(struct sk_buff *skb,
                (const struct hash_netiface4_telem *)data;
        u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0;
 
+       if (data->nomatch)
+               flags |= IPSET_FLAG_NOMATCH;
        NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
        NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
        NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface);
        if (flags)
-               NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, flags);
+               NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
        NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
                      htonl(ip_set_timeout_get(tdata->timeout)));
 
@@ -361,7 +382,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
 
        if (tb[IPSET_ATTR_CIDR]) {
                data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
-               if (!data.cidr)
+               if (!data.cidr || data.cidr > HOST_MASK)
                        return -IPSET_ERR_INVALID_CIDR;
        }
 
@@ -387,6 +408,8 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
                u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
                if (cadt_flags & IPSET_FLAG_PHYSDEV)
                        data.physdev = 1;
+               if (adt == IPSET_ADD && (cadt_flags & IPSET_FLAG_NOMATCH))
+                       flags |= (cadt_flags << 16);
        }
 
        if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) {
@@ -440,7 +463,8 @@ struct hash_netiface6_elem_hashed {
        union nf_inet_addr ip;
        u8 physdev;
        u8 cidr;
-       u16 padding;
+       u8 nomatch;
+       u8 padding;
 };
 
 #define HKEY_DATALEN   sizeof(struct hash_netiface6_elem_hashed)
@@ -449,7 +473,8 @@ struct hash_netiface6_elem {
        union nf_inet_addr ip;
        u8 physdev;
        u8 cidr;
-       u16 padding;
+       u8 nomatch;
+       u8 padding;
        const char *iface;
 };
 
@@ -457,7 +482,8 @@ struct hash_netiface6_telem {
        union nf_inet_addr ip;
        u8 physdev;
        u8 cidr;
-       u16 padding;
+       u8 nomatch;
+       u8 padding;
        const char *iface;
        unsigned long timeout;
 };
@@ -487,9 +513,22 @@ hash_netiface6_data_copy(struct hash_netiface6_elem *dst,
        memcpy(dst, src, sizeof(*dst));
 }
 
+static inline void
+hash_netiface6_data_flags(struct hash_netiface6_elem *dst, u32 flags)
+{
+       dst->nomatch = flags & IPSET_FLAG_NOMATCH;
+}
+
+static inline bool
+hash_netiface6_data_match(const struct hash_netiface6_elem *elem)
+{
+       return !elem->nomatch;
+}
+
 static inline void
 hash_netiface6_data_zero_out(struct hash_netiface6_elem *elem)
 {
+       elem->cidr = 0;
 }
 
 static inline void
@@ -514,11 +553,13 @@ hash_netiface6_data_list(struct sk_buff *skb,
 {
        u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0;
 
+       if (data->nomatch)
+               flags |= IPSET_FLAG_NOMATCH;
        NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
        NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
        NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface);
        if (flags)
-               NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, flags);
+               NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
        return 0;
 
 nla_put_failure:
@@ -533,11 +574,13 @@ hash_netiface6_data_tlist(struct sk_buff *skb,
                (const struct hash_netiface6_telem *)data;
        u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0;
 
+       if (data->nomatch)
+               flags |= IPSET_FLAG_NOMATCH;
        NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
        NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
        NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface);
        if (flags)
-               NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, flags);
+               NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
        NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
                      htonl(ip_set_timeout_get(e->timeout)));
        return 0;
@@ -636,7 +679,7 @@ hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[],
 
        if (tb[IPSET_ATTR_CIDR])
                data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
-       if (!data.cidr)
+       if (!data.cidr || data.cidr > HOST_MASK)
                return -IPSET_ERR_INVALID_CIDR;
        ip6_netmask(&data.ip, data.cidr);
 
@@ -662,6 +705,8 @@ hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[],
                u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
                if (cadt_flags & IPSET_FLAG_PHYSDEV)
                        data.physdev = 1;
+               if (adt == IPSET_ADD && (cadt_flags & IPSET_FLAG_NOMATCH))
+                       flags |= (cadt_flags << 16);
        }
 
        ret = adtfn(set, &data, timeout, flags);
@@ -678,7 +723,7 @@ hash_netiface_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
        u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
        u8 hbits;
 
-       if (!(set->family == AF_INET || set->family == AF_INET6))
+       if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
                return -IPSET_ERR_INVALID_FAMILY;
 
        if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
@@ -697,7 +742,7 @@ hash_netiface_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
 
        h = kzalloc(sizeof(*h)
                    + sizeof(struct ip_set_hash_nets)
-                     * (set->family == AF_INET ? 32 : 128), GFP_KERNEL);
+                     * (set->family == NFPROTO_IPV4 ? 32 : 128), GFP_KERNEL);
        if (!h)
                return -ENOMEM;
 
@@ -722,15 +767,15 @@ hash_netiface_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
        if (tb[IPSET_ATTR_TIMEOUT]) {
                h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
 
-               set->variant = set->family == AF_INET
+               set->variant = set->family == NFPROTO_IPV4
                        ? &hash_netiface4_tvariant : &hash_netiface6_tvariant;
 
-               if (set->family == AF_INET)
+               if (set->family == NFPROTO_IPV4)
                        hash_netiface4_gc_init(set);
                else
                        hash_netiface6_gc_init(set);
        } else {
-               set->variant = set->family == AF_INET
+               set->variant = set->family == NFPROTO_IPV4
                        ? &hash_netiface4_variant : &hash_netiface6_variant;
        }
 
@@ -746,8 +791,9 @@ static struct ip_set_type hash_netiface_type __read_mostly = {
        .protocol       = IPSET_PROTOCOL,
        .features       = IPSET_TYPE_IP | IPSET_TYPE_IFACE,
        .dimension      = IPSET_DIM_TWO,
-       .family         = AF_UNSPEC,
+       .family         = NFPROTO_UNSPEC,
        .revision_min   = 0,
+       .revision_max   = 1,    /* nomatch flag support added */
        .create         = hash_netiface_create,
        .create_policy  = {
                [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
index 8f9de7207ec90806638e9c3fa4927ddfe42d25dd..ce2e77100b64ecb521db1cf45c0babd4902a374f 100644 (file)
@@ -40,12 +40,19 @@ hash_netport_same_set(const struct ip_set *a, const struct ip_set *b);
 
 /* The type variant functions: IPv4 */
 
+/* We squeeze the "nomatch" flag into cidr: we don't support cidr == 0
+ * However this way we have to store internally cidr - 1,
+ * dancing back and forth.
+ */
+#define IP_SET_HASH_WITH_NETS_PACKED
+
 /* Member elements without timeout */
 struct hash_netport4_elem {
        __be32 ip;
        __be16 port;
        u8 proto;
-       u8 cidr;
+       u8 cidr:7;
+       u8 nomatch:1;
 };
 
 /* Member elements with timeout support */
@@ -53,7 +60,8 @@ struct hash_netport4_telem {
        __be32 ip;
        __be16 port;
        u8 proto;
-       u8 cidr;
+       u8 cidr:7;
+       u8 nomatch:1;
        unsigned long timeout;
 };
 
@@ -82,13 +90,26 @@ hash_netport4_data_copy(struct hash_netport4_elem *dst,
        dst->port = src->port;
        dst->proto = src->proto;
        dst->cidr = src->cidr;
+       dst->nomatch = src->nomatch;
+}
+
+static inline void
+hash_netport4_data_flags(struct hash_netport4_elem *dst, u32 flags)
+{
+       dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH);
+}
+
+static inline bool
+hash_netport4_data_match(const struct hash_netport4_elem *elem)
+{
+       return !elem->nomatch;
 }
 
 static inline void
 hash_netport4_data_netmask(struct hash_netport4_elem *elem, u8 cidr)
 {
        elem->ip &= ip_set_netmask(cidr);
-       elem->cidr = cidr;
+       elem->cidr = cidr - 1;
 }
 
 static inline void
@@ -101,10 +122,14 @@ static bool
 hash_netport4_data_list(struct sk_buff *skb,
                        const struct hash_netport4_elem *data)
 {
+       u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
+
        NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
        NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
-       NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
+       NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr + 1);
        NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
+       if (flags)
+               NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
        return 0;
 
 nla_put_failure:
@@ -117,13 +142,16 @@ hash_netport4_data_tlist(struct sk_buff *skb,
 {
        const struct hash_netport4_telem *tdata =
                (const struct hash_netport4_telem *)data;
+       u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
 
        NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip);
        NLA_PUT_NET16(skb, IPSET_ATTR_PORT, tdata->port);
-       NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
+       NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr + 1);
        NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
        NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
                      htonl(ip_set_timeout_get(tdata->timeout)));
+       if (flags)
+               NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
 
        return 0;
 
@@ -154,20 +182,18 @@ hash_netport4_kadt(struct ip_set *set, const struct sk_buff *skb,
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_netport4_elem data = {
-               .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
+               .cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1
        };
 
-       if (data.cidr == 0)
-               return -EINVAL;
        if (adt == IPSET_TEST)
-               data.cidr = HOST_MASK;
+               data.cidr = HOST_MASK - 1;
 
        if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
                                 &data.port, &data.proto))
                return -EINVAL;
 
        ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
-       data.ip &= ip_set_netmask(data.cidr);
+       data.ip &= ip_set_netmask(data.cidr + 1);
 
        return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
 }
@@ -178,16 +204,18 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
 {
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
-       struct hash_netport4_elem data = { .cidr = HOST_MASK };
+       struct hash_netport4_elem data = { .cidr = HOST_MASK - 1 };
        u32 port, port_to, p = 0, ip = 0, ip_to, last;
        u32 timeout = h->timeout;
        bool with_ports = false;
+       u8 cidr;
        int ret;
 
        if (unlikely(!tb[IPSET_ATTR_IP] ||
                     !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
-                    !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
+                    !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
+                    !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
                return -IPSET_ERR_PROTOCOL;
 
        if (tb[IPSET_ATTR_LINENO])
@@ -198,9 +226,10 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
                return ret;
 
        if (tb[IPSET_ATTR_CIDR]) {
-               data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
-               if (!data.cidr)
+               cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
+               if (!cidr || cidr > HOST_MASK)
                        return -IPSET_ERR_INVALID_CIDR;
+               data.cidr = cidr - 1;
        }
 
        if (tb[IPSET_ATTR_PORT])
@@ -227,8 +256,15 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
        }
 
        with_ports = with_ports && tb[IPSET_ATTR_PORT_TO];
+
+       if (tb[IPSET_ATTR_CADT_FLAGS] && adt == IPSET_ADD) {
+               u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
+               if (cadt_flags & IPSET_FLAG_NOMATCH)
+                       flags |= (cadt_flags << 16);
+       }
+
        if (adt == IPSET_TEST || !(with_ports || tb[IPSET_ATTR_IP_TO])) {
-               data.ip = htonl(ip & ip_set_hostmask(data.cidr));
+               data.ip = htonl(ip & ip_set_hostmask(data.cidr + 1));
                ret = adtfn(set, &data, timeout, flags);
                return ip_set_eexist(ret, flags) ? 0 : ret;
        }
@@ -248,14 +284,15 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
                if (ip + UINT_MAX == ip_to)
                        return -IPSET_ERR_HASH_RANGE;
        } else {
-               ip_set_mask_from_to(ip, ip_to, data.cidr);
+               ip_set_mask_from_to(ip, ip_to, data.cidr + 1);
        }
 
        if (retried)
                ip = h->next.ip;
        while (!after(ip, ip_to)) {
                data.ip = htonl(ip);
-               last = ip_set_range_to_cidr(ip, ip_to, &data.cidr);
+               last = ip_set_range_to_cidr(ip, ip_to, &cidr);
+               data.cidr = cidr - 1;
                p = retried && ip == h->next.ip ? h->next.port : port;
                for (; p <= port_to; p++) {
                        data.port = htons(p);
@@ -288,14 +325,16 @@ struct hash_netport6_elem {
        union nf_inet_addr ip;
        __be16 port;
        u8 proto;
-       u8 cidr;
+       u8 cidr:7;
+       u8 nomatch:1;
 };
 
 struct hash_netport6_telem {
        union nf_inet_addr ip;
        __be16 port;
        u8 proto;
-       u8 cidr;
+       u8 cidr:7;
+       u8 nomatch:1;
        unsigned long timeout;
 };
 
@@ -323,6 +362,18 @@ hash_netport6_data_copy(struct hash_netport6_elem *dst,
        memcpy(dst, src, sizeof(*dst));
 }
 
+static inline void
+hash_netport6_data_flags(struct hash_netport6_elem *dst, u32 flags)
+{
+       dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH);
+}
+
+static inline bool
+hash_netport6_data_match(const struct hash_netport6_elem *elem)
+{
+       return !elem->nomatch;
+}
+
 static inline void
 hash_netport6_data_zero_out(struct hash_netport6_elem *elem)
 {
@@ -342,17 +393,21 @@ static inline void
 hash_netport6_data_netmask(struct hash_netport6_elem *elem, u8 cidr)
 {
        ip6_netmask(&elem->ip, cidr);
-       elem->cidr = cidr;
+       elem->cidr = cidr - 1;
 }
 
 static bool
 hash_netport6_data_list(struct sk_buff *skb,
                        const struct hash_netport6_elem *data)
 {
+       u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
+
        NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
        NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
-       NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
+       NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr + 1);
        NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
+       if (flags)
+               NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
        return 0;
 
 nla_put_failure:
@@ -365,13 +420,16 @@ hash_netport6_data_tlist(struct sk_buff *skb,
 {
        const struct hash_netport6_telem *e =
                (const struct hash_netport6_telem *)data;
+       u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
 
        NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
        NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
-       NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
+       NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr + 1);
        NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
        NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
                      htonl(ip_set_timeout_get(e->timeout)));
+       if (flags)
+               NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
        return 0;
 
 nla_put_failure:
@@ -400,20 +458,18 @@ hash_netport6_kadt(struct ip_set *set, const struct sk_buff *skb,
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_netport6_elem data = {
-               .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
+               .cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1,
        };
 
-       if (data.cidr == 0)
-               return -EINVAL;
        if (adt == IPSET_TEST)
-               data.cidr = HOST_MASK;
+               data.cidr = HOST_MASK - 1;
 
        if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
                                 &data.port, &data.proto))
                return -EINVAL;
 
        ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
-       ip6_netmask(&data.ip, data.cidr);
+       ip6_netmask(&data.ip, data.cidr + 1);
 
        return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
 }
@@ -424,16 +480,18 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
 {
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
-       struct hash_netport6_elem data = { .cidr = HOST_MASK };
+       struct hash_netport6_elem data = { .cidr = HOST_MASK  - 1 };
        u32 port, port_to;
        u32 timeout = h->timeout;
        bool with_ports = false;
+       u8 cidr;
        int ret;
 
        if (unlikely(!tb[IPSET_ATTR_IP] ||
                     !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
-                    !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
+                    !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
+                    !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
                return -IPSET_ERR_PROTOCOL;
        if (unlikely(tb[IPSET_ATTR_IP_TO]))
                return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
@@ -445,11 +503,13 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
        if (ret)
                return ret;
 
-       if (tb[IPSET_ATTR_CIDR])
-               data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
-       if (!data.cidr)
-               return -IPSET_ERR_INVALID_CIDR;
-       ip6_netmask(&data.ip, data.cidr);
+       if (tb[IPSET_ATTR_CIDR]) {
+               cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
+               if (!cidr || cidr > HOST_MASK)
+                       return -IPSET_ERR_INVALID_CIDR;
+               data.cidr = cidr - 1;
+       }
+       ip6_netmask(&data.ip, data.cidr + 1);
 
        if (tb[IPSET_ATTR_PORT])
                data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
@@ -474,6 +534,12 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
                timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
        }
 
+       if (tb[IPSET_ATTR_CADT_FLAGS] && adt == IPSET_ADD) {
+               u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
+               if (cadt_flags & IPSET_FLAG_NOMATCH)
+                       flags |= (cadt_flags << 16);
+       }
+
        if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
                ret = adtfn(set, &data, timeout, flags);
                return ip_set_eexist(ret, flags) ? 0 : ret;
@@ -507,7 +573,7 @@ hash_netport_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
        u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
        u8 hbits;
 
-       if (!(set->family == AF_INET || set->family == AF_INET6))
+       if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
                return -IPSET_ERR_INVALID_FAMILY;
 
        if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
@@ -526,7 +592,7 @@ hash_netport_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
 
        h = kzalloc(sizeof(*h)
                    + sizeof(struct ip_set_hash_nets)
-                     * (set->family == AF_INET ? 32 : 128), GFP_KERNEL);
+                     * (set->family == NFPROTO_IPV4 ? 32 : 128), GFP_KERNEL);
        if (!h)
                return -ENOMEM;
 
@@ -549,15 +615,15 @@ hash_netport_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
        if (tb[IPSET_ATTR_TIMEOUT]) {
                h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
 
-               set->variant = set->family == AF_INET
+               set->variant = set->family == NFPROTO_IPV4
                        ? &hash_netport4_tvariant : &hash_netport6_tvariant;
 
-               if (set->family == AF_INET)
+               if (set->family == NFPROTO_IPV4)
                        hash_netport4_gc_init(set);
                else
                        hash_netport6_gc_init(set);
        } else {
-               set->variant = set->family == AF_INET
+               set->variant = set->family == NFPROTO_IPV4
                        ? &hash_netport4_variant : &hash_netport6_variant;
        }
 
@@ -573,10 +639,11 @@ static struct ip_set_type hash_netport_type __read_mostly = {
        .protocol       = IPSET_PROTOCOL,
        .features       = IPSET_TYPE_IP | IPSET_TYPE_PORT,
        .dimension      = IPSET_DIM_TWO,
-       .family         = AF_UNSPEC,
+       .family         = NFPROTO_UNSPEC,
        .revision_min   = 0,
        /*                1        SCTP and UDPLITE support added */
-       .revision_max   = 2,    /* Range as input support for IPv4 added */
+       /*                2,       Range as input support for IPv4 added */
+       .revision_max   = 3,    /* nomatch flag support added */
        .create         = hash_netport_create,
        .create_policy  = {
                [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
@@ -595,6 +662,7 @@ static struct ip_set_type hash_netport_type __read_mostly = {
                [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
                [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
                [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
+               [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
        },
        .me             = THIS_MODULE,
 };
index 4d10819d462e6a9ede447305af10627f0ab671c5..7e095f9005f01f301cefe757533981e787b82ad5 100644 (file)
@@ -575,7 +575,7 @@ static struct ip_set_type list_set_type __read_mostly = {
        .protocol       = IPSET_PROTOCOL,
        .features       = IPSET_TYPE_NAME | IPSET_DUMP_LAST,
        .dimension      = IPSET_DIM_ONE,
-       .family         = AF_UNSPEC,
+       .family         = NFPROTO_UNSPEC,
        .revision_min   = 0,
        .revision_max   = 0,
        .create         = list_set_create,
index ed86a3be678ea28590d34018b5ec990cbf052e8d..7b48035826eeed8b1ae2ad3cefb97024dec84dab 100644 (file)
@@ -44,6 +44,7 @@
 #include <net/netfilter/nf_conntrack_ecache.h>
 #include <net/netfilter/nf_conntrack_zones.h>
 #include <net/netfilter/nf_conntrack_timestamp.h>
+#include <net/netfilter/nf_conntrack_timeout.h>
 #include <net/netfilter/nf_nat.h>
 #include <net/netfilter/nf_nat_core.h>
 
@@ -635,8 +636,12 @@ static noinline int early_drop(struct net *net, unsigned int hash)
 
        if (del_timer(&ct->timeout)) {
                death_by_timeout((unsigned long)ct);
-               dropped = 1;
-               NF_CT_STAT_INC_ATOMIC(net, early_drop);
+               /* Check if we indeed killed this entry. Reliable event
+                  delivery may have inserted it into the dying list. */
+               if (test_bit(IPS_DYING_BIT, &ct->status)) {
+                       dropped = 1;
+                       NF_CT_STAT_INC_ATOMIC(net, early_drop);
+               }
        }
        nf_ct_put(ct);
        return dropped;
@@ -763,7 +768,8 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
               struct nf_conntrack_l3proto *l3proto,
               struct nf_conntrack_l4proto *l4proto,
               struct sk_buff *skb,
-              unsigned int dataoff, u32 hash)
+              unsigned int dataoff, u32 hash,
+              unsigned int *timeouts)
 {
        struct nf_conn *ct;
        struct nf_conn_help *help;
@@ -782,7 +788,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
        if (IS_ERR(ct))
                return (struct nf_conntrack_tuple_hash *)ct;
 
-       if (!l4proto->new(ct, skb, dataoff)) {
+       if (!l4proto->new(ct, skb, dataoff, timeouts)) {
                nf_conntrack_free(ct);
                pr_debug("init conntrack: can't track with proto module\n");
                return NULL;
@@ -848,7 +854,8 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl,
                  struct nf_conntrack_l3proto *l3proto,
                  struct nf_conntrack_l4proto *l4proto,
                  int *set_reply,
-                 enum ip_conntrack_info *ctinfo)
+                 enum ip_conntrack_info *ctinfo,
+                 unsigned int *timeouts)
 {
        struct nf_conntrack_tuple tuple;
        struct nf_conntrack_tuple_hash *h;
@@ -868,7 +875,7 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl,
        h = __nf_conntrack_find_get(net, zone, &tuple, hash);
        if (!h) {
                h = init_conntrack(net, tmpl, &tuple, l3proto, l4proto,
-                                  skb, dataoff, hash);
+                                  skb, dataoff, hash, timeouts);
                if (!h)
                        return NULL;
                if (IS_ERR(h))
@@ -909,6 +916,8 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
        enum ip_conntrack_info ctinfo;
        struct nf_conntrack_l3proto *l3proto;
        struct nf_conntrack_l4proto *l4proto;
+       struct nf_conn_timeout *timeout_ext;
+       unsigned int *timeouts;
        unsigned int dataoff;
        u_int8_t protonum;
        int set_reply = 0;
@@ -955,8 +964,19 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
                        goto out;
        }
 
+       /* Decide what timeout policy we want to apply to this flow. */
+       if (tmpl) {
+               timeout_ext = nf_ct_timeout_find(tmpl);
+               if (timeout_ext)
+                       timeouts = NF_CT_TIMEOUT_EXT_DATA(timeout_ext);
+               else
+                       timeouts = l4proto->get_timeouts(net);
+       } else
+               timeouts = l4proto->get_timeouts(net);
+
        ct = resolve_normal_ct(net, tmpl, skb, dataoff, pf, protonum,
-                              l3proto, l4proto, &set_reply, &ctinfo);
+                              l3proto, l4proto, &set_reply, &ctinfo,
+                              timeouts);
        if (!ct) {
                /* Not valid part of a connection */
                NF_CT_STAT_INC_ATOMIC(net, invalid);
@@ -973,7 +993,7 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
 
        NF_CT_ASSERT(skb->nfct);
 
-       ret = l4proto->packet(ct, skb, dataoff, ctinfo, pf, hooknum);
+       ret = l4proto->packet(ct, skb, dataoff, ctinfo, pf, hooknum, timeouts);
        if (ret <= 0) {
                /* Invalid: inverse of the return code tells
                 * the netfilter core what to do */
@@ -1327,6 +1347,7 @@ static void nf_conntrack_cleanup_net(struct net *net)
        }
 
        nf_ct_free_hashtable(net->ct.hash, net->ct.htable_size);
+       nf_conntrack_timeout_fini(net);
        nf_conntrack_ecache_fini(net);
        nf_conntrack_tstamp_fini(net);
        nf_conntrack_acct_fini(net);
@@ -1558,9 +1579,14 @@ static int nf_conntrack_init_net(struct net *net)
        ret = nf_conntrack_ecache_init(net);
        if (ret < 0)
                goto err_ecache;
+       ret = nf_conntrack_timeout_init(net);
+       if (ret < 0)
+               goto err_timeout;
 
        return 0;
 
+err_timeout:
+       nf_conntrack_timeout_fini(net);
 err_ecache:
        nf_conntrack_tstamp_fini(net);
 err_tstamp:
index 14af6329bdda21843ada4be624093e1ac6f980fb..5bd3047ddeec5cf38b160931777fb6c63e6c59b4 100644 (file)
@@ -32,9 +32,11 @@ static DEFINE_MUTEX(nf_ct_ecache_mutex);
 void nf_ct_deliver_cached_events(struct nf_conn *ct)
 {
        struct net *net = nf_ct_net(ct);
-       unsigned long events;
+       unsigned long events, missed;
        struct nf_ct_event_notifier *notify;
        struct nf_conntrack_ecache *e;
+       struct nf_ct_event item;
+       int ret;
 
        rcu_read_lock();
        notify = rcu_dereference(net->ct.nf_conntrack_event_cb);
@@ -47,31 +49,32 @@ void nf_ct_deliver_cached_events(struct nf_conn *ct)
 
        events = xchg(&e->cache, 0);
 
-       if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct) && events) {
-               struct nf_ct_event item = {
-                       .ct     = ct,
-                       .pid    = 0,
-                       .report = 0
-               };
-               int ret;
-               /* We make a copy of the missed event cache without taking
-                * the lock, thus we may send missed events twice. However,
-                * this does not harm and it happens very rarely. */
-               unsigned long missed = e->missed;
-
-               if (!((events | missed) & e->ctmask))
-                       goto out_unlock;
-
-               ret = notify->fcn(events | missed, &item);
-               if (unlikely(ret < 0 || missed)) {
-                       spin_lock_bh(&ct->lock);
-                       if (ret < 0)
-                               e->missed |= events;
-                       else
-                               e->missed &= ~missed;
-                       spin_unlock_bh(&ct->lock);
-               } 
-       }
+       if (!nf_ct_is_confirmed(ct) || nf_ct_is_dying(ct) || !events)
+               goto out_unlock;
+
+       /* We make a copy of the missed event cache without taking
+        * the lock, thus we may send missed events twice. However,
+        * this does not harm and it happens very rarely. */
+       missed = e->missed;
+
+       if (!((events | missed) & e->ctmask))
+               goto out_unlock;
+
+       item.ct = ct;
+       item.pid = 0;
+       item.report = 0;
+
+       ret = notify->fcn(events | missed, &item);
+
+       if (likely(ret >= 0 && !missed))
+               goto out_unlock;
+
+       spin_lock_bh(&ct->lock);
+       if (ret < 0)
+               e->missed |= events;
+       else
+               e->missed &= ~missed;
+       spin_unlock_bh(&ct->lock);
 
 out_unlock:
        rcu_read_unlock();
index bbe23baa19b64f4df7b2532b1471614a5315cc26..436b7cb79ba43833018477832d3e4ffa185bcb97 100644 (file)
@@ -181,6 +181,60 @@ void nf_ct_helper_destroy(struct nf_conn *ct)
        }
 }
 
+static LIST_HEAD(nf_ct_helper_expectfn_list);
+
+void nf_ct_helper_expectfn_register(struct nf_ct_helper_expectfn *n)
+{
+       spin_lock_bh(&nf_conntrack_lock);
+       list_add_rcu(&n->head, &nf_ct_helper_expectfn_list);
+       spin_unlock_bh(&nf_conntrack_lock);
+}
+EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_register);
+
+void nf_ct_helper_expectfn_unregister(struct nf_ct_helper_expectfn *n)
+{
+       spin_lock_bh(&nf_conntrack_lock);
+       list_del_rcu(&n->head);
+       spin_unlock_bh(&nf_conntrack_lock);
+}
+EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_unregister);
+
+struct nf_ct_helper_expectfn *
+nf_ct_helper_expectfn_find_by_name(const char *name)
+{
+       struct nf_ct_helper_expectfn *cur;
+       bool found = false;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(cur, &nf_ct_helper_expectfn_list, head) {
+               if (!strcmp(cur->name, name)) {
+                       found = true;
+                       break;
+               }
+       }
+       rcu_read_unlock();
+       return found ? cur : NULL;
+}
+EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_find_by_name);
+
+struct nf_ct_helper_expectfn *
+nf_ct_helper_expectfn_find_by_symbol(const void *symbol)
+{
+       struct nf_ct_helper_expectfn *cur;
+       bool found = false;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(cur, &nf_ct_helper_expectfn_list, head) {
+               if (cur->expectfn == symbol) {
+                       found = true;
+                       break;
+               }
+       }
+       rcu_read_unlock();
+       return found ? cur : NULL;
+}
+EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_find_by_symbol);
+
 int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
 {
        unsigned int h = helper_hash(&me->tuple);
index 04fb409623d222182828b54cd675a7c67e77bc1e..2124977ac31d0a92a724ddf9122f3a7f5a6e9146 100644 (file)
@@ -110,15 +110,16 @@ ctnetlink_dump_tuples(struct sk_buff *skb,
        struct nf_conntrack_l3proto *l3proto;
        struct nf_conntrack_l4proto *l4proto;
 
+       rcu_read_lock();
        l3proto = __nf_ct_l3proto_find(tuple->src.l3num);
        ret = ctnetlink_dump_tuples_ip(skb, tuple, l3proto);
 
-       if (unlikely(ret < 0))
-               return ret;
-
-       l4proto = __nf_ct_l4proto_find(tuple->src.l3num, tuple->dst.protonum);
-       ret = ctnetlink_dump_tuples_proto(skb, tuple, l4proto);
-
+       if (ret >= 0) {
+               l4proto = __nf_ct_l4proto_find(tuple->src.l3num,
+                                              tuple->dst.protonum);
+               ret = ctnetlink_dump_tuples_proto(skb, tuple, l4proto);
+       }
+       rcu_read_unlock();
        return ret;
 }
 
@@ -712,9 +713,11 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
        struct hlist_nulls_node *n;
        struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
        u_int8_t l3proto = nfmsg->nfgen_family;
+       int res;
 #ifdef CONFIG_NF_CONNTRACK_MARK
        const struct ctnetlink_dump_filter *filter = cb->data;
 #endif
+
        spin_lock_bh(&nf_conntrack_lock);
        last = (struct nf_conn *)cb->args[1];
        for (; cb->args[0] < net->ct.htable_size; cb->args[0]++) {
@@ -740,11 +743,14 @@ restart:
                                continue;
                        }
 #endif
-                       if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid,
-                                               cb->nlh->nlmsg_seq,
-                                               NFNL_MSG_TYPE(
-                                                       cb->nlh->nlmsg_type),
-                                               ct) < 0) {
+                       rcu_read_lock();
+                       res =
+                       ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid,
+                                           cb->nlh->nlmsg_seq,
+                                           NFNL_MSG_TYPE(cb->nlh->nlmsg_type),
+                                           ct);
+                       rcu_read_unlock();
+                       if (res < 0) {
                                nf_conntrack_get(&ct->ct_general);
                                cb->args[1] = (unsigned long)ct;
                                goto out;
@@ -1078,16 +1084,13 @@ ctnetlink_parse_nat_setup(struct nf_conn *ct,
        if (!parse_nat_setup) {
 #ifdef CONFIG_MODULES
                rcu_read_unlock();
-               spin_unlock_bh(&nf_conntrack_lock);
                nfnl_unlock();
                if (request_module("nf-nat-ipv4") < 0) {
                        nfnl_lock();
-                       spin_lock_bh(&nf_conntrack_lock);
                        rcu_read_lock();
                        return -EOPNOTSUPP;
                }
                nfnl_lock();
-               spin_lock_bh(&nf_conntrack_lock);
                rcu_read_lock();
                if (nfnetlink_parse_nat_setup_hook)
                        return -EAGAIN;
@@ -1649,14 +1652,16 @@ ctnetlink_exp_dump_mask(struct sk_buff *skb,
        if (!nest_parms)
                goto nla_put_failure;
 
+       rcu_read_lock();
        l3proto = __nf_ct_l3proto_find(tuple->src.l3num);
        ret = ctnetlink_dump_tuples_ip(skb, &m, l3proto);
-
-       if (unlikely(ret < 0))
-               goto nla_put_failure;
-
-       l4proto = __nf_ct_l4proto_find(tuple->src.l3num, tuple->dst.protonum);
+       if (ret >= 0) {
+               l4proto = __nf_ct_l4proto_find(tuple->src.l3num,
+                                              tuple->dst.protonum);
        ret = ctnetlink_dump_tuples_proto(skb, &m, l4proto);
+       }
+       rcu_read_unlock();
+
        if (unlikely(ret < 0))
                goto nla_put_failure;
 
@@ -1675,6 +1680,11 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
        struct nf_conn *master = exp->master;
        long timeout = ((long)exp->timeout.expires - (long)jiffies) / HZ;
        struct nf_conn_help *help;
+#ifdef CONFIG_NF_NAT_NEEDED
+       struct nlattr *nest_parms;
+       struct nf_conntrack_tuple nat_tuple = {};
+#endif
+       struct nf_ct_helper_expectfn *expfn;
 
        if (timeout < 0)
                timeout = 0;
@@ -1688,9 +1698,29 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
                                 CTA_EXPECT_MASTER) < 0)
                goto nla_put_failure;
 
+#ifdef CONFIG_NF_NAT_NEEDED
+       if (exp->saved_ip || exp->saved_proto.all) {
+               nest_parms = nla_nest_start(skb, CTA_EXPECT_NAT | NLA_F_NESTED);
+               if (!nest_parms)
+                       goto nla_put_failure;
+
+               NLA_PUT_BE32(skb, CTA_EXPECT_NAT_DIR, htonl(exp->dir));
+
+               nat_tuple.src.l3num = nf_ct_l3num(master);
+               nat_tuple.src.u3.ip = exp->saved_ip;
+               nat_tuple.dst.protonum = nf_ct_protonum(master);
+               nat_tuple.src.u = exp->saved_proto;
+
+               if (ctnetlink_exp_dump_tuple(skb, &nat_tuple,
+                                               CTA_EXPECT_NAT_TUPLE) < 0)
+                       goto nla_put_failure;
+               nla_nest_end(skb, nest_parms);
+       }
+#endif
        NLA_PUT_BE32(skb, CTA_EXPECT_TIMEOUT, htonl(timeout));
        NLA_PUT_BE32(skb, CTA_EXPECT_ID, htonl((unsigned long)exp));
        NLA_PUT_BE32(skb, CTA_EXPECT_FLAGS, htonl(exp->flags));
+       NLA_PUT_BE32(skb, CTA_EXPECT_CLASS, htonl(exp->class));
        help = nfct_help(master);
        if (help) {
                struct nf_conntrack_helper *helper;
@@ -1699,6 +1729,9 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
                if (helper)
                        NLA_PUT_STRING(skb, CTA_EXPECT_HELP_NAME, helper->name);
        }
+       expfn = nf_ct_helper_expectfn_find_by_symbol(exp->expectfn);
+       if (expfn != NULL)
+               NLA_PUT_STRING(skb, CTA_EXPECT_FN, expfn->name);
 
        return 0;
 
@@ -1856,6 +1889,9 @@ static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = {
        [CTA_EXPECT_HELP_NAME]  = { .type = NLA_NUL_STRING },
        [CTA_EXPECT_ZONE]       = { .type = NLA_U16 },
        [CTA_EXPECT_FLAGS]      = { .type = NLA_U32 },
+       [CTA_EXPECT_CLASS]      = { .type = NLA_U32 },
+       [CTA_EXPECT_NAT]        = { .type = NLA_NESTED },
+       [CTA_EXPECT_FN]         = { .type = NLA_NUL_STRING },
 };
 
 static int
@@ -2031,6 +2067,41 @@ ctnetlink_change_expect(struct nf_conntrack_expect *x,
        return -EOPNOTSUPP;
 }
 
+static const struct nla_policy exp_nat_nla_policy[CTA_EXPECT_NAT_MAX+1] = {
+       [CTA_EXPECT_NAT_DIR]    = { .type = NLA_U32 },
+       [CTA_EXPECT_NAT_TUPLE]  = { .type = NLA_NESTED },
+};
+
+static int
+ctnetlink_parse_expect_nat(const struct nlattr *attr,
+                          struct nf_conntrack_expect *exp,
+                          u_int8_t u3)
+{
+#ifdef CONFIG_NF_NAT_NEEDED
+       struct nlattr *tb[CTA_EXPECT_NAT_MAX+1];
+       struct nf_conntrack_tuple nat_tuple = {};
+       int err;
+
+       nla_parse_nested(tb, CTA_EXPECT_NAT_MAX, attr, exp_nat_nla_policy);
+
+       if (!tb[CTA_EXPECT_NAT_DIR] || !tb[CTA_EXPECT_NAT_TUPLE])
+               return -EINVAL;
+
+       err = ctnetlink_parse_tuple((const struct nlattr * const *)tb,
+                                       &nat_tuple, CTA_EXPECT_NAT_TUPLE, u3);
+       if (err < 0)
+               return err;
+
+       exp->saved_ip = nat_tuple.src.u3.ip;
+       exp->saved_proto = nat_tuple.src.u;
+       exp->dir = ntohl(nla_get_be32(tb[CTA_EXPECT_NAT_DIR]));
+
+       return 0;
+#else
+       return -EOPNOTSUPP;
+#endif
+}
+
 static int
 ctnetlink_create_expect(struct net *net, u16 zone,
                        const struct nlattr * const cda[],
@@ -2042,6 +2113,8 @@ ctnetlink_create_expect(struct net *net, u16 zone,
        struct nf_conntrack_expect *exp;
        struct nf_conn *ct;
        struct nf_conn_help *help;
+       struct nf_conntrack_helper *helper = NULL;
+       u_int32_t class = 0;
        int err = 0;
 
        /* caller guarantees that those three CTA_EXPECT_* exist */
@@ -2060,6 +2133,40 @@ ctnetlink_create_expect(struct net *net, u16 zone,
        if (!h)
                return -ENOENT;
        ct = nf_ct_tuplehash_to_ctrack(h);
+
+       /* Look for helper of this expectation */
+       if (cda[CTA_EXPECT_HELP_NAME]) {
+               const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]);
+
+               helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct),
+                                                   nf_ct_protonum(ct));
+               if (helper == NULL) {
+#ifdef CONFIG_MODULES
+                       if (request_module("nfct-helper-%s", helpname) < 0) {
+                               err = -EOPNOTSUPP;
+                               goto out;
+                       }
+
+                       helper = __nf_conntrack_helper_find(helpname,
+                                                           nf_ct_l3num(ct),
+                                                           nf_ct_protonum(ct));
+                       if (helper) {
+                               err = -EAGAIN;
+                               goto out;
+                       }
+#endif
+                       err = -EOPNOTSUPP;
+                       goto out;
+               }
+       }
+
+       if (cda[CTA_EXPECT_CLASS] && helper) {
+               class = ntohl(nla_get_be32(cda[CTA_EXPECT_CLASS]));
+               if (class > helper->expect_class_max) {
+                       err = -EINVAL;
+                       goto out;
+               }
+       }
        exp = nf_ct_expect_alloc(ct);
        if (!exp) {
                err = -ENOMEM;
@@ -2086,18 +2193,35 @@ ctnetlink_create_expect(struct net *net, u16 zone,
                } else
                        exp->flags = 0;
        }
+       if (cda[CTA_EXPECT_FN]) {
+               const char *name = nla_data(cda[CTA_EXPECT_FN]);
+               struct nf_ct_helper_expectfn *expfn;
 
-       exp->class = 0;
-       exp->expectfn = NULL;
+               expfn = nf_ct_helper_expectfn_find_by_name(name);
+               if (expfn == NULL) {
+                       err = -EINVAL;
+                       goto err_out;
+               }
+               exp->expectfn = expfn->expectfn;
+       } else
+               exp->expectfn = NULL;
+
+       exp->class = class;
        exp->master = ct;
-       exp->helper = NULL;
+       exp->helper = helper;
        memcpy(&exp->tuple, &tuple, sizeof(struct nf_conntrack_tuple));
        memcpy(&exp->mask.src.u3, &mask.src.u3, sizeof(exp->mask.src.u3));
        exp->mask.src.u.all = mask.src.u.all;
 
+       if (cda[CTA_EXPECT_NAT]) {
+               err = ctnetlink_parse_expect_nat(cda[CTA_EXPECT_NAT],
+                                                exp, u3);
+               if (err < 0)
+                       goto err_out;
+       }
        err = nf_ct_expect_related_report(exp, pid, report);
+err_out:
        nf_ct_expect_put(exp);
-
 out:
        nf_ct_put(nf_ct_tuplehash_to_ctrack(h));
        return err;
index d6dde6dc09e6679cf1206237d1456f1ecc2f21c0..24fdce256cb0a65ee9996dfa7fa2569e499eebd0 100644 (file)
@@ -423,7 +423,7 @@ static bool dccp_invert_tuple(struct nf_conntrack_tuple *inv,
 }
 
 static bool dccp_new(struct nf_conn *ct, const struct sk_buff *skb,
-                    unsigned int dataoff)
+                    unsigned int dataoff, unsigned int *timeouts)
 {
        struct net *net = nf_ct_net(ct);
        struct dccp_net *dn;
@@ -472,12 +472,17 @@ static u64 dccp_ack_seq(const struct dccp_hdr *dh)
                     ntohl(dhack->dccph_ack_nr_low);
 }
 
+static unsigned int *dccp_get_timeouts(struct net *net)
+{
+       return dccp_pernet(net)->dccp_timeout;
+}
+
 static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb,
                       unsigned int dataoff, enum ip_conntrack_info ctinfo,
-                      u_int8_t pf, unsigned int hooknum)
+                      u_int8_t pf, unsigned int hooknum,
+                      unsigned int *timeouts)
 {
        struct net *net = nf_ct_net(ct);
-       struct dccp_net *dn;
        enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
        struct dccp_hdr _dh, *dh;
        u_int8_t type, old_state, new_state;
@@ -559,8 +564,7 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb,
        if (new_state != old_state)
                nf_conntrack_event_cache(IPCT_PROTOINFO, ct);
 
-       dn = dccp_pernet(net);
-       nf_ct_refresh_acct(ct, ctinfo, skb, dn->dccp_timeout[new_state]);
+       nf_ct_refresh_acct(ct, ctinfo, skb, timeouts[new_state]);
 
        return NF_ACCEPT;
 }
@@ -702,8 +706,60 @@ static int dccp_nlattr_size(void)
        return nla_total_size(0)        /* CTA_PROTOINFO_DCCP */
                + nla_policy_len(dccp_nla_policy, CTA_PROTOINFO_DCCP_MAX + 1);
 }
+
 #endif
 
+#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
+
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nfnetlink_cttimeout.h>
+
+static int dccp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
+{
+       struct dccp_net *dn = dccp_pernet(&init_net);
+       unsigned int *timeouts = data;
+       int i;
+
+       /* set default DCCP timeouts. */
+       for (i=0; i<CT_DCCP_MAX; i++)
+               timeouts[i] = dn->dccp_timeout[i];
+
+       /* there's a 1:1 mapping between attributes and protocol states. */
+       for (i=CTA_TIMEOUT_DCCP_UNSPEC+1; i<CTA_TIMEOUT_DCCP_MAX+1; i++) {
+               if (tb[i]) {
+                       timeouts[i] = ntohl(nla_get_be32(tb[i])) * HZ;
+               }
+       }
+       return 0;
+}
+
+static int
+dccp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
+{
+        const unsigned int *timeouts = data;
+       int i;
+
+       for (i=CTA_TIMEOUT_DCCP_UNSPEC+1; i<CTA_TIMEOUT_DCCP_MAX+1; i++)
+               NLA_PUT_BE32(skb, i, htonl(timeouts[i] / HZ));
+
+       return 0;
+
+nla_put_failure:
+       return -ENOSPC;
+}
+
+static const struct nla_policy
+dccp_timeout_nla_policy[CTA_TIMEOUT_DCCP_MAX+1] = {
+       [CTA_TIMEOUT_DCCP_REQUEST]      = { .type = NLA_U32 },
+       [CTA_TIMEOUT_DCCP_RESPOND]      = { .type = NLA_U32 },
+       [CTA_TIMEOUT_DCCP_PARTOPEN]     = { .type = NLA_U32 },
+       [CTA_TIMEOUT_DCCP_OPEN]         = { .type = NLA_U32 },
+       [CTA_TIMEOUT_DCCP_CLOSEREQ]     = { .type = NLA_U32 },
+       [CTA_TIMEOUT_DCCP_CLOSING]      = { .type = NLA_U32 },
+       [CTA_TIMEOUT_DCCP_TIMEWAIT]     = { .type = NLA_U32 },
+};
+#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
+
 #ifdef CONFIG_SYSCTL
 /* template, data assigned later */
 static struct ctl_table dccp_sysctl_table[] = {
@@ -767,6 +823,7 @@ static struct nf_conntrack_l4proto dccp_proto4 __read_mostly = {
        .invert_tuple           = dccp_invert_tuple,
        .new                    = dccp_new,
        .packet                 = dccp_packet,
+       .get_timeouts           = dccp_get_timeouts,
        .error                  = dccp_error,
        .print_tuple            = dccp_print_tuple,
        .print_conntrack        = dccp_print_conntrack,
@@ -779,6 +836,15 @@ static struct nf_conntrack_l4proto dccp_proto4 __read_mostly = {
        .nlattr_to_tuple        = nf_ct_port_nlattr_to_tuple,
        .nla_policy             = nf_ct_port_nla_policy,
 #endif
+#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
+       .ctnl_timeout           = {
+               .nlattr_to_obj  = dccp_timeout_nlattr_to_obj,
+               .obj_to_nlattr  = dccp_timeout_obj_to_nlattr,
+               .nlattr_max     = CTA_TIMEOUT_DCCP_MAX,
+               .obj_size       = sizeof(unsigned int) * CT_DCCP_MAX,
+               .nla_policy     = dccp_timeout_nla_policy,
+       },
+#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 };
 
 static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = {
@@ -789,6 +855,7 @@ static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = {
        .invert_tuple           = dccp_invert_tuple,
        .new                    = dccp_new,
        .packet                 = dccp_packet,
+       .get_timeouts           = dccp_get_timeouts,
        .error                  = dccp_error,
        .print_tuple            = dccp_print_tuple,
        .print_conntrack        = dccp_print_conntrack,
@@ -801,6 +868,15 @@ static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = {
        .nlattr_to_tuple        = nf_ct_port_nlattr_to_tuple,
        .nla_policy             = nf_ct_port_nla_policy,
 #endif
+#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
+       .ctnl_timeout           = {
+               .nlattr_to_obj  = dccp_timeout_nlattr_to_obj,
+               .obj_to_nlattr  = dccp_timeout_obj_to_nlattr,
+               .nlattr_max     = CTA_TIMEOUT_DCCP_MAX,
+               .obj_size       = sizeof(unsigned int) * CT_DCCP_MAX,
+               .nla_policy     = dccp_timeout_nla_policy,
+       },
+#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 };
 
 static __net_init int dccp_net_init(struct net *net)
index e2091d0c7a2fb7b232d606a3f6940b1150e4cfb8..835e24c58f0de3ab67977aad017d456a840e28ce 100644 (file)
@@ -40,25 +40,70 @@ static int generic_print_tuple(struct seq_file *s,
        return 0;
 }
 
+static unsigned int *generic_get_timeouts(struct net *net)
+{
+       return &nf_ct_generic_timeout;
+}
+
 /* Returns verdict for packet, or -1 for invalid. */
-static int packet(struct nf_conn *ct,
-                 const struct sk_buff *skb,
-                 unsigned int dataoff,
-                 enum ip_conntrack_info ctinfo,
-                 u_int8_t pf,
-                 unsigned int hooknum)
+static int generic_packet(struct nf_conn *ct,
+                         const struct sk_buff *skb,
+                         unsigned int dataoff,
+                         enum ip_conntrack_info ctinfo,
+                         u_int8_t pf,
+                         unsigned int hooknum,
+                         unsigned int *timeout)
 {
-       nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_generic_timeout);
+       nf_ct_refresh_acct(ct, ctinfo, skb, *timeout);
        return NF_ACCEPT;
 }
 
 /* Called when a new connection for this protocol found. */
-static bool new(struct nf_conn *ct, const struct sk_buff *skb,
-               unsigned int dataoff)
+static bool generic_new(struct nf_conn *ct, const struct sk_buff *skb,
+                       unsigned int dataoff, unsigned int *timeouts)
 {
        return true;
 }
 
+#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
+
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nfnetlink_cttimeout.h>
+
+static int generic_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
+{
+       unsigned int *timeout = data;
+
+       if (tb[CTA_TIMEOUT_GENERIC_TIMEOUT])
+               *timeout =
+                   ntohl(nla_get_be32(tb[CTA_TIMEOUT_GENERIC_TIMEOUT])) * HZ;
+       else {
+               /* Set default generic timeout. */
+               *timeout = nf_ct_generic_timeout;
+       }
+
+       return 0;
+}
+
+static int
+generic_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
+{
+       const unsigned int *timeout = data;
+
+       NLA_PUT_BE32(skb, CTA_TIMEOUT_GENERIC_TIMEOUT, htonl(*timeout / HZ));
+
+       return 0;
+
+nla_put_failure:
+        return -ENOSPC;
+}
+
+static const struct nla_policy
+generic_timeout_nla_policy[CTA_TIMEOUT_GENERIC_MAX+1] = {
+       [CTA_TIMEOUT_GENERIC_TIMEOUT]   = { .type = NLA_U32 },
+};
+#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
+
 #ifdef CONFIG_SYSCTL
 static struct ctl_table_header *generic_sysctl_header;
 static struct ctl_table generic_sysctl_table[] = {
@@ -93,8 +138,18 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_generic __read_mostly =
        .pkt_to_tuple           = generic_pkt_to_tuple,
        .invert_tuple           = generic_invert_tuple,
        .print_tuple            = generic_print_tuple,
-       .packet                 = packet,
-       .new                    = new,
+       .packet                 = generic_packet,
+       .get_timeouts           = generic_get_timeouts,
+       .new                    = generic_new,
+#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
+       .ctnl_timeout           = {
+               .nlattr_to_obj  = generic_timeout_nlattr_to_obj,
+               .obj_to_nlattr  = generic_timeout_obj_to_nlattr,
+               .nlattr_max     = CTA_TIMEOUT_GENERIC_MAX,
+               .obj_size       = sizeof(unsigned int),
+               .nla_policy     = generic_timeout_nla_policy,
+       },
+#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 #ifdef CONFIG_SYSCTL
        .ctl_table_header       = &generic_sysctl_header,
        .ctl_table              = generic_sysctl_table,
index f0338791b822d238d926486e78084afe5089b1a5..659648c4b14ad50331c996ab6a401e379b23b700 100644 (file)
 #include <linux/netfilter/nf_conntrack_proto_gre.h>
 #include <linux/netfilter/nf_conntrack_pptp.h>
 
-#define GRE_TIMEOUT            (30 * HZ)
-#define GRE_STREAM_TIMEOUT     (180 * HZ)
+enum grep_conntrack {
+       GRE_CT_UNREPLIED,
+       GRE_CT_REPLIED,
+       GRE_CT_MAX
+};
+
+static unsigned int gre_timeouts[GRE_CT_MAX] = {
+       [GRE_CT_UNREPLIED]      = 30*HZ,
+       [GRE_CT_REPLIED]        = 180*HZ,
+};
 
 static int proto_gre_net_id __read_mostly;
 struct netns_proto_gre {
@@ -227,13 +235,19 @@ static int gre_print_conntrack(struct seq_file *s, struct nf_conn *ct)
                          (ct->proto.gre.stream_timeout / HZ));
 }
 
+static unsigned int *gre_get_timeouts(struct net *net)
+{
+       return gre_timeouts;
+}
+
 /* Returns verdict for packet, and may modify conntrack */
 static int gre_packet(struct nf_conn *ct,
                      const struct sk_buff *skb,
                      unsigned int dataoff,
                      enum ip_conntrack_info ctinfo,
                      u_int8_t pf,
-                     unsigned int hooknum)
+                     unsigned int hooknum,
+                     unsigned int *timeouts)
 {
        /* If we've seen traffic both ways, this is a GRE connection.
         * Extend timeout. */
@@ -252,15 +266,15 @@ static int gre_packet(struct nf_conn *ct,
 
 /* Called when a new connection for this protocol found. */
 static bool gre_new(struct nf_conn *ct, const struct sk_buff *skb,
-                   unsigned int dataoff)
+                   unsigned int dataoff, unsigned int *timeouts)
 {
        pr_debug(": ");
        nf_ct_dump_tuple(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
 
        /* initialize to sane value.  Ideally a conntrack helper
         * (e.g. in case of pptp) is increasing them */
-       ct->proto.gre.stream_timeout = GRE_STREAM_TIMEOUT;
-       ct->proto.gre.timeout = GRE_TIMEOUT;
+       ct->proto.gre.stream_timeout = timeouts[GRE_CT_REPLIED];
+       ct->proto.gre.timeout = timeouts[GRE_CT_UNREPLIED];
 
        return true;
 }
@@ -278,6 +292,52 @@ static void gre_destroy(struct nf_conn *ct)
                nf_ct_gre_keymap_destroy(master);
 }
 
+#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
+
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nfnetlink_cttimeout.h>
+
+static int gre_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
+{
+       unsigned int *timeouts = data;
+
+       /* set default timeouts for GRE. */
+       timeouts[GRE_CT_UNREPLIED] = gre_timeouts[GRE_CT_UNREPLIED];
+       timeouts[GRE_CT_REPLIED] = gre_timeouts[GRE_CT_REPLIED];
+
+       if (tb[CTA_TIMEOUT_GRE_UNREPLIED]) {
+               timeouts[GRE_CT_UNREPLIED] =
+                       ntohl(nla_get_be32(tb[CTA_TIMEOUT_GRE_UNREPLIED])) * HZ;
+       }
+       if (tb[CTA_TIMEOUT_GRE_REPLIED]) {
+               timeouts[GRE_CT_REPLIED] =
+                       ntohl(nla_get_be32(tb[CTA_TIMEOUT_GRE_REPLIED])) * HZ;
+       }
+       return 0;
+}
+
+static int
+gre_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
+{
+       const unsigned int *timeouts = data;
+
+       NLA_PUT_BE32(skb, CTA_TIMEOUT_GRE_UNREPLIED,
+                       htonl(timeouts[GRE_CT_UNREPLIED] / HZ));
+       NLA_PUT_BE32(skb, CTA_TIMEOUT_GRE_REPLIED,
+                       htonl(timeouts[GRE_CT_REPLIED] / HZ));
+       return 0;
+
+nla_put_failure:
+       return -ENOSPC;
+}
+
+static const struct nla_policy
+gre_timeout_nla_policy[CTA_TIMEOUT_GRE_MAX+1] = {
+       [CTA_TIMEOUT_GRE_UNREPLIED]     = { .type = NLA_U32 },
+       [CTA_TIMEOUT_GRE_REPLIED]       = { .type = NLA_U32 },
+};
+#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
+
 /* protocol helper struct */
 static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = {
        .l3proto         = AF_INET,
@@ -287,6 +347,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = {
        .invert_tuple    = gre_invert_tuple,
        .print_tuple     = gre_print_tuple,
        .print_conntrack = gre_print_conntrack,
+       .get_timeouts    = gre_get_timeouts,
        .packet          = gre_packet,
        .new             = gre_new,
        .destroy         = gre_destroy,
@@ -297,6 +358,15 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = {
        .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple,
        .nla_policy      = nf_ct_port_nla_policy,
 #endif
+#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
+       .ctnl_timeout    = {
+               .nlattr_to_obj  = gre_timeout_nlattr_to_obj,
+               .obj_to_nlattr  = gre_timeout_obj_to_nlattr,
+               .nlattr_max     = CTA_TIMEOUT_GRE_MAX,
+               .obj_size       = sizeof(unsigned int) * GRE_CT_MAX,
+               .nla_policy     = gre_timeout_nla_policy,
+       },
+#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 };
 
 static int proto_gre_net_init(struct net *net)
index afa69136061ac18c7b9e1f1067f9679ddcbf0984..72b5088592dc8557b264c4b0f7de4e72fa3e3b76 100644 (file)
@@ -279,13 +279,19 @@ static int sctp_new_state(enum ip_conntrack_dir dir,
        return sctp_conntracks[dir][i][cur_state];
 }
 
+static unsigned int *sctp_get_timeouts(struct net *net)
+{
+       return sctp_timeouts;
+}
+
 /* Returns verdict for packet, or -NF_ACCEPT for invalid. */
 static int sctp_packet(struct nf_conn *ct,
                       const struct sk_buff *skb,
                       unsigned int dataoff,
                       enum ip_conntrack_info ctinfo,
                       u_int8_t pf,
-                      unsigned int hooknum)
+                      unsigned int hooknum,
+                      unsigned int *timeouts)
 {
        enum sctp_conntrack new_state, old_state;
        enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
@@ -370,7 +376,7 @@ static int sctp_packet(struct nf_conn *ct,
        }
        spin_unlock_bh(&ct->lock);
 
-       nf_ct_refresh_acct(ct, ctinfo, skb, sctp_timeouts[new_state]);
+       nf_ct_refresh_acct(ct, ctinfo, skb, timeouts[new_state]);
 
        if (old_state == SCTP_CONNTRACK_COOKIE_ECHOED &&
            dir == IP_CT_DIR_REPLY &&
@@ -390,7 +396,7 @@ out:
 
 /* Called when a new connection for this protocol found. */
 static bool sctp_new(struct nf_conn *ct, const struct sk_buff *skb,
-                    unsigned int dataoff)
+                    unsigned int dataoff, unsigned int *timeouts)
 {
        enum sctp_conntrack new_state;
        const struct sctphdr *sh;
@@ -543,6 +549,57 @@ static int sctp_nlattr_size(void)
 }
 #endif
 
+#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
+
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nfnetlink_cttimeout.h>
+
+static int sctp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
+{
+       unsigned int *timeouts = data;
+       int i;
+
+       /* set default SCTP timeouts. */
+       for (i=0; i<SCTP_CONNTRACK_MAX; i++)
+               timeouts[i] = sctp_timeouts[i];
+
+       /* there's a 1:1 mapping between attributes and protocol states. */
+       for (i=CTA_TIMEOUT_SCTP_UNSPEC+1; i<CTA_TIMEOUT_SCTP_MAX+1; i++) {
+               if (tb[i]) {
+                       timeouts[i] = ntohl(nla_get_be32(tb[i])) * HZ;
+               }
+       }
+       return 0;
+}
+
+static int
+sctp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
+{
+        const unsigned int *timeouts = data;
+       int i;
+
+       for (i=CTA_TIMEOUT_SCTP_UNSPEC+1; i<CTA_TIMEOUT_SCTP_MAX+1; i++)
+               NLA_PUT_BE32(skb, i, htonl(timeouts[i] / HZ));
+
+        return 0;
+
+nla_put_failure:
+        return -ENOSPC;
+}
+
+static const struct nla_policy
+sctp_timeout_nla_policy[CTA_TIMEOUT_SCTP_MAX+1] = {
+       [CTA_TIMEOUT_SCTP_CLOSED]               = { .type = NLA_U32 },
+       [CTA_TIMEOUT_SCTP_COOKIE_WAIT]          = { .type = NLA_U32 },
+       [CTA_TIMEOUT_SCTP_COOKIE_ECHOED]        = { .type = NLA_U32 },
+       [CTA_TIMEOUT_SCTP_ESTABLISHED]          = { .type = NLA_U32 },
+       [CTA_TIMEOUT_SCTP_SHUTDOWN_SENT]        = { .type = NLA_U32 },
+       [CTA_TIMEOUT_SCTP_SHUTDOWN_RECD]        = { .type = NLA_U32 },
+       [CTA_TIMEOUT_SCTP_SHUTDOWN_ACK_SENT]    = { .type = NLA_U32 },
+};
+#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
+
+
 #ifdef CONFIG_SYSCTL
 static unsigned int sctp_sysctl_table_users;
 static struct ctl_table_header *sctp_sysctl_header;
@@ -664,6 +721,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 __read_mostly = {
        .print_tuple            = sctp_print_tuple,
        .print_conntrack        = sctp_print_conntrack,
        .packet                 = sctp_packet,
+       .get_timeouts           = sctp_get_timeouts,
        .new                    = sctp_new,
        .me                     = THIS_MODULE,
 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
@@ -675,6 +733,15 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 __read_mostly = {
        .nlattr_to_tuple        = nf_ct_port_nlattr_to_tuple,
        .nla_policy             = nf_ct_port_nla_policy,
 #endif
+#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
+       .ctnl_timeout           = {
+               .nlattr_to_obj  = sctp_timeout_nlattr_to_obj,
+               .obj_to_nlattr  = sctp_timeout_obj_to_nlattr,
+               .nlattr_max     = CTA_TIMEOUT_SCTP_MAX,
+               .obj_size       = sizeof(unsigned int) * SCTP_CONNTRACK_MAX,
+               .nla_policy     = sctp_timeout_nla_policy,
+       },
+#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 #ifdef CONFIG_SYSCTL
        .ctl_table_users        = &sctp_sysctl_table_users,
        .ctl_table_header       = &sctp_sysctl_header,
@@ -694,6 +761,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 __read_mostly = {
        .print_tuple            = sctp_print_tuple,
        .print_conntrack        = sctp_print_conntrack,
        .packet                 = sctp_packet,
+       .get_timeouts           = sctp_get_timeouts,
        .new                    = sctp_new,
        .me                     = THIS_MODULE,
 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
@@ -704,6 +772,15 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 __read_mostly = {
        .nlattr_tuple_size      = nf_ct_port_nlattr_tuple_size,
        .nlattr_to_tuple        = nf_ct_port_nlattr_to_tuple,
        .nla_policy             = nf_ct_port_nla_policy,
+#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
+       .ctnl_timeout           = {
+               .nlattr_to_obj  = sctp_timeout_nlattr_to_obj,
+               .obj_to_nlattr  = sctp_timeout_obj_to_nlattr,
+               .nlattr_max     = CTA_TIMEOUT_SCTP_MAX,
+               .obj_size       = sizeof(unsigned int) * SCTP_CONNTRACK_MAX,
+               .nla_policy     = sctp_timeout_nla_policy,
+       },
+#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 #endif
 #ifdef CONFIG_SYSCTL
        .ctl_table_users        = &sctp_sysctl_table_users,
index 97b9f3ebf28c2113be8ea5bfa015c75af0df9dbf..361eade62a09e58e06194fb78d8c6b07333f015a 100644 (file)
@@ -64,13 +64,7 @@ static const char *const tcp_conntrack_names[] = {
 #define HOURS * 60 MINS
 #define DAYS * 24 HOURS
 
-/* RFC1122 says the R2 limit should be at least 100 seconds.
-   Linux uses 15 packets as limit, which corresponds
-   to ~13-30min depending on RTO. */
-static unsigned int nf_ct_tcp_timeout_max_retrans __read_mostly    =   5 MINS;
-static unsigned int nf_ct_tcp_timeout_unacknowledged __read_mostly =   5 MINS;
-
-static unsigned int tcp_timeouts[TCP_CONNTRACK_MAX] __read_mostly = {
+static unsigned int tcp_timeouts[TCP_CONNTRACK_TIMEOUT_MAX] __read_mostly = {
        [TCP_CONNTRACK_SYN_SENT]        = 2 MINS,
        [TCP_CONNTRACK_SYN_RECV]        = 60 SECS,
        [TCP_CONNTRACK_ESTABLISHED]     = 5 DAYS,
@@ -80,6 +74,11 @@ static unsigned int tcp_timeouts[TCP_CONNTRACK_MAX] __read_mostly = {
        [TCP_CONNTRACK_TIME_WAIT]       = 2 MINS,
        [TCP_CONNTRACK_CLOSE]           = 10 SECS,
        [TCP_CONNTRACK_SYN_SENT2]       = 2 MINS,
+/* RFC1122 says the R2 limit should be at least 100 seconds.
+   Linux uses 15 packets as limit, which corresponds
+   to ~13-30min depending on RTO. */
+       [TCP_CONNTRACK_RETRANS]         = 5 MINS,
+       [TCP_CONNTRACK_UNACK]           = 5 MINS,
 };
 
 #define sNO TCP_CONNTRACK_NONE
@@ -814,13 +813,19 @@ static int tcp_error(struct net *net, struct nf_conn *tmpl,
        return NF_ACCEPT;
 }
 
+static unsigned int *tcp_get_timeouts(struct net *net)
+{
+       return tcp_timeouts;
+}
+
 /* Returns verdict for packet, or -1 for invalid. */
 static int tcp_packet(struct nf_conn *ct,
                      const struct sk_buff *skb,
                      unsigned int dataoff,
                      enum ip_conntrack_info ctinfo,
                      u_int8_t pf,
-                     unsigned int hooknum)
+                     unsigned int hooknum,
+                     unsigned int *timeouts)
 {
        struct net *net = nf_ct_net(ct);
        struct nf_conntrack_tuple *tuple;
@@ -1015,14 +1020,14 @@ static int tcp_packet(struct nf_conn *ct,
                ct->proto.tcp.seen[dir].flags |= IP_CT_TCP_FLAG_CLOSE_INIT;
 
        if (ct->proto.tcp.retrans >= nf_ct_tcp_max_retrans &&
-           tcp_timeouts[new_state] > nf_ct_tcp_timeout_max_retrans)
-               timeout = nf_ct_tcp_timeout_max_retrans;
+           timeouts[new_state] > timeouts[TCP_CONNTRACK_RETRANS])
+               timeout = timeouts[TCP_CONNTRACK_RETRANS];
        else if ((ct->proto.tcp.seen[0].flags | ct->proto.tcp.seen[1].flags) &
                 IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED &&
-                tcp_timeouts[new_state] > nf_ct_tcp_timeout_unacknowledged)
-               timeout = nf_ct_tcp_timeout_unacknowledged;
+                timeouts[new_state] > timeouts[TCP_CONNTRACK_UNACK])
+               timeout = timeouts[TCP_CONNTRACK_UNACK];
        else
-               timeout = tcp_timeouts[new_state];
+               timeout = timeouts[new_state];
        spin_unlock_bh(&ct->lock);
 
        if (new_state != old_state)
@@ -1054,7 +1059,7 @@ static int tcp_packet(struct nf_conn *ct,
 
 /* Called when a new connection for this protocol found. */
 static bool tcp_new(struct nf_conn *ct, const struct sk_buff *skb,
-                   unsigned int dataoff)
+                   unsigned int dataoff, unsigned int *timeouts)
 {
        enum tcp_conntrack new_state;
        const struct tcphdr *th;
@@ -1239,6 +1244,113 @@ static int tcp_nlattr_tuple_size(void)
 }
 #endif
 
+#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
+
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nfnetlink_cttimeout.h>
+
+static int tcp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
+{
+       unsigned int *timeouts = data;
+       int i;
+
+       /* set default TCP timeouts. */
+       for (i=0; i<TCP_CONNTRACK_TIMEOUT_MAX; i++)
+               timeouts[i] = tcp_timeouts[i];
+
+       if (tb[CTA_TIMEOUT_TCP_SYN_SENT]) {
+               timeouts[TCP_CONNTRACK_SYN_SENT] =
+                       ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_SYN_SENT]))*HZ;
+       }
+       if (tb[CTA_TIMEOUT_TCP_SYN_RECV]) {
+               timeouts[TCP_CONNTRACK_SYN_RECV] =
+                       ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_SYN_RECV]))*HZ;
+       }
+       if (tb[CTA_TIMEOUT_TCP_ESTABLISHED]) {
+               timeouts[TCP_CONNTRACK_ESTABLISHED] =
+                       ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_ESTABLISHED]))*HZ;
+       }
+       if (tb[CTA_TIMEOUT_TCP_FIN_WAIT]) {
+               timeouts[TCP_CONNTRACK_FIN_WAIT] =
+                       ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_FIN_WAIT]))*HZ;
+       }
+       if (tb[CTA_TIMEOUT_TCP_CLOSE_WAIT]) {
+               timeouts[TCP_CONNTRACK_CLOSE_WAIT] =
+                       ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_CLOSE_WAIT]))*HZ;
+       }
+       if (tb[CTA_TIMEOUT_TCP_LAST_ACK]) {
+               timeouts[TCP_CONNTRACK_LAST_ACK] =
+                       ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_LAST_ACK]))*HZ;
+       }
+       if (tb[CTA_TIMEOUT_TCP_TIME_WAIT]) {
+               timeouts[TCP_CONNTRACK_TIME_WAIT] =
+                       ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_TIME_WAIT]))*HZ;
+       }
+       if (tb[CTA_TIMEOUT_TCP_CLOSE]) {
+               timeouts[TCP_CONNTRACK_CLOSE] =
+                       ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_CLOSE]))*HZ;
+       }
+       if (tb[CTA_TIMEOUT_TCP_SYN_SENT2]) {
+               timeouts[TCP_CONNTRACK_SYN_SENT2] =
+                       ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_SYN_SENT2]))*HZ;
+       }
+       if (tb[CTA_TIMEOUT_TCP_RETRANS]) {
+               timeouts[TCP_CONNTRACK_RETRANS] =
+                       ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_RETRANS]))*HZ;
+       }
+       if (tb[CTA_TIMEOUT_TCP_UNACK]) {
+               timeouts[TCP_CONNTRACK_UNACK] =
+                       ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_UNACK]))*HZ;
+       }
+       return 0;
+}
+
+static int
+tcp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
+{
+       const unsigned int *timeouts = data;
+
+       NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_SYN_SENT,
+                       htonl(timeouts[TCP_CONNTRACK_SYN_SENT] / HZ));
+       NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_SYN_RECV,
+                       htonl(timeouts[TCP_CONNTRACK_SYN_RECV] / HZ));
+       NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_ESTABLISHED,
+                       htonl(timeouts[TCP_CONNTRACK_ESTABLISHED] / HZ));
+       NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_FIN_WAIT,
+                       htonl(timeouts[TCP_CONNTRACK_FIN_WAIT] / HZ));
+       NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_CLOSE_WAIT,
+                       htonl(timeouts[TCP_CONNTRACK_CLOSE_WAIT] / HZ));
+       NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_LAST_ACK,
+                       htonl(timeouts[TCP_CONNTRACK_LAST_ACK] / HZ));
+       NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_TIME_WAIT,
+                       htonl(timeouts[TCP_CONNTRACK_TIME_WAIT] / HZ));
+       NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_CLOSE,
+                       htonl(timeouts[TCP_CONNTRACK_CLOSE] / HZ));
+       NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_SYN_SENT2,
+                       htonl(timeouts[TCP_CONNTRACK_SYN_SENT2] / HZ));
+       NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_RETRANS,
+                       htonl(timeouts[TCP_CONNTRACK_RETRANS] / HZ));
+       NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_UNACK,
+                       htonl(timeouts[TCP_CONNTRACK_UNACK] / HZ));
+       return 0;
+
+nla_put_failure:
+       return -ENOSPC;
+}
+
+static const struct nla_policy tcp_timeout_nla_policy[CTA_TIMEOUT_TCP_MAX+1] = {
+       [CTA_TIMEOUT_TCP_SYN_SENT]      = { .type = NLA_U32 },
+       [CTA_TIMEOUT_TCP_SYN_RECV]      = { .type = NLA_U32 },
+       [CTA_TIMEOUT_TCP_ESTABLISHED]   = { .type = NLA_U32 },
+       [CTA_TIMEOUT_TCP_FIN_WAIT]      = { .type = NLA_U32 },
+       [CTA_TIMEOUT_TCP_CLOSE_WAIT]    = { .type = NLA_U32 },
+       [CTA_TIMEOUT_TCP_LAST_ACK]      = { .type = NLA_U32 },
+       [CTA_TIMEOUT_TCP_TIME_WAIT]     = { .type = NLA_U32 },
+       [CTA_TIMEOUT_TCP_CLOSE]         = { .type = NLA_U32 },
+       [CTA_TIMEOUT_TCP_SYN_SENT2]     = { .type = NLA_U32 },
+};
+#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
+
 #ifdef CONFIG_SYSCTL
 static unsigned int tcp_sysctl_table_users;
 static struct ctl_table_header *tcp_sysctl_header;
@@ -1301,14 +1413,14 @@ static struct ctl_table tcp_sysctl_table[] = {
        },
        {
                .procname       = "nf_conntrack_tcp_timeout_max_retrans",
-               .data           = &nf_ct_tcp_timeout_max_retrans,
+               .data           = &tcp_timeouts[TCP_CONNTRACK_RETRANS],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "nf_conntrack_tcp_timeout_unacknowledged",
-               .data           = &nf_ct_tcp_timeout_unacknowledged,
+               .data           = &tcp_timeouts[TCP_CONNTRACK_UNACK],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
@@ -1404,7 +1516,7 @@ static struct ctl_table tcp_compat_sysctl_table[] = {
        },
        {
                .procname       = "ip_conntrack_tcp_timeout_max_retrans",
-               .data           = &nf_ct_tcp_timeout_max_retrans,
+               .data           = &tcp_timeouts[TCP_CONNTRACK_RETRANS],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
@@ -1445,6 +1557,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 __read_mostly =
        .print_tuple            = tcp_print_tuple,
        .print_conntrack        = tcp_print_conntrack,
        .packet                 = tcp_packet,
+       .get_timeouts           = tcp_get_timeouts,
        .new                    = tcp_new,
        .error                  = tcp_error,
 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
@@ -1456,6 +1569,16 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 __read_mostly =
        .nlattr_tuple_size      = tcp_nlattr_tuple_size,
        .nla_policy             = nf_ct_port_nla_policy,
 #endif
+#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
+       .ctnl_timeout           = {
+               .nlattr_to_obj  = tcp_timeout_nlattr_to_obj,
+               .obj_to_nlattr  = tcp_timeout_obj_to_nlattr,
+               .nlattr_max     = CTA_TIMEOUT_TCP_MAX,
+               .obj_size       = sizeof(unsigned int) *
+                                       TCP_CONNTRACK_TIMEOUT_MAX,
+               .nla_policy     = tcp_timeout_nla_policy,
+       },
+#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 #ifdef CONFIG_SYSCTL
        .ctl_table_users        = &tcp_sysctl_table_users,
        .ctl_table_header       = &tcp_sysctl_header,
@@ -1477,6 +1600,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6 __read_mostly =
        .print_tuple            = tcp_print_tuple,
        .print_conntrack        = tcp_print_conntrack,
        .packet                 = tcp_packet,
+       .get_timeouts           = tcp_get_timeouts,
        .new                    = tcp_new,
        .error                  = tcp_error,
 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
@@ -1488,6 +1612,16 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6 __read_mostly =
        .nlattr_tuple_size      = tcp_nlattr_tuple_size,
        .nla_policy             = nf_ct_port_nla_policy,
 #endif
+#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
+       .ctnl_timeout           = {
+               .nlattr_to_obj  = tcp_timeout_nlattr_to_obj,
+               .obj_to_nlattr  = tcp_timeout_obj_to_nlattr,
+               .nlattr_max     = CTA_TIMEOUT_TCP_MAX,
+               .obj_size       = sizeof(unsigned int) *
+                                       TCP_CONNTRACK_TIMEOUT_MAX,
+               .nla_policy     = tcp_timeout_nla_policy,
+       },
+#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 #ifdef CONFIG_SYSCTL
        .ctl_table_users        = &tcp_sysctl_table_users,
        .ctl_table_header       = &tcp_sysctl_header,
index 5f35757fbff031ab224e758c0c3d8c502c86db55..a9073dc1548d087fbe694f898ff30072792bc2e6 100644 (file)
 #include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
 #include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
 
-static unsigned int nf_ct_udp_timeout __read_mostly = 30*HZ;
-static unsigned int nf_ct_udp_timeout_stream __read_mostly = 180*HZ;
+enum udp_conntrack {
+       UDP_CT_UNREPLIED,
+       UDP_CT_REPLIED,
+       UDP_CT_MAX
+};
+
+static unsigned int udp_timeouts[UDP_CT_MAX] = {
+       [UDP_CT_UNREPLIED]      = 30*HZ,
+       [UDP_CT_REPLIED]        = 180*HZ,
+};
 
 static bool udp_pkt_to_tuple(const struct sk_buff *skb,
                             unsigned int dataoff,
@@ -63,30 +71,38 @@ static int udp_print_tuple(struct seq_file *s,
                          ntohs(tuple->dst.u.udp.port));
 }
 
+static unsigned int *udp_get_timeouts(struct net *net)
+{
+       return udp_timeouts;
+}
+
 /* Returns verdict for packet, and may modify conntracktype */
 static int udp_packet(struct nf_conn *ct,
                      const struct sk_buff *skb,
                      unsigned int dataoff,
                      enum ip_conntrack_info ctinfo,
                      u_int8_t pf,
-                     unsigned int hooknum)
+                     unsigned int hooknum,
+                     unsigned int *timeouts)
 {
        /* If we've seen traffic both ways, this is some kind of UDP
           stream.  Extend timeout. */
        if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
-               nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_udp_timeout_stream);
+               nf_ct_refresh_acct(ct, ctinfo, skb,
+                                  timeouts[UDP_CT_REPLIED]);
                /* Also, more likely to be important, and not a probe */
                if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status))
                        nf_conntrack_event_cache(IPCT_ASSURED, ct);
-       } else
-               nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_udp_timeout);
-
+       } else {
+               nf_ct_refresh_acct(ct, ctinfo, skb,
+                                  timeouts[UDP_CT_UNREPLIED]);
+       }
        return NF_ACCEPT;
 }
 
 /* Called when a new connection for this protocol found. */
 static bool udp_new(struct nf_conn *ct, const struct sk_buff *skb,
-                   unsigned int dataoff)
+                   unsigned int dataoff, unsigned int *timeouts)
 {
        return true;
 }
@@ -136,20 +152,66 @@ static int udp_error(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb,
        return NF_ACCEPT;
 }
 
+#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
+
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nfnetlink_cttimeout.h>
+
+static int udp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
+{
+       unsigned int *timeouts = data;
+
+       /* set default timeouts for UDP. */
+       timeouts[UDP_CT_UNREPLIED] = udp_timeouts[UDP_CT_UNREPLIED];
+       timeouts[UDP_CT_REPLIED] = udp_timeouts[UDP_CT_REPLIED];
+
+       if (tb[CTA_TIMEOUT_UDP_UNREPLIED]) {
+               timeouts[UDP_CT_UNREPLIED] =
+                       ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDP_UNREPLIED])) * HZ;
+       }
+       if (tb[CTA_TIMEOUT_UDP_REPLIED]) {
+               timeouts[UDP_CT_REPLIED] =
+                       ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDP_REPLIED])) * HZ;
+       }
+       return 0;
+}
+
+static int
+udp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
+{
+       const unsigned int *timeouts = data;
+
+       NLA_PUT_BE32(skb, CTA_TIMEOUT_UDP_UNREPLIED,
+                       htonl(timeouts[UDP_CT_UNREPLIED] / HZ));
+       NLA_PUT_BE32(skb, CTA_TIMEOUT_UDP_REPLIED,
+                       htonl(timeouts[UDP_CT_REPLIED] / HZ));
+       return 0;
+
+nla_put_failure:
+       return -ENOSPC;
+}
+
+static const struct nla_policy
+udp_timeout_nla_policy[CTA_TIMEOUT_UDP_MAX+1] = {
+       [CTA_TIMEOUT_UDP_UNREPLIED]     = { .type = NLA_U32 },
+       [CTA_TIMEOUT_UDP_REPLIED]       = { .type = NLA_U32 },
+};
+#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
+
 #ifdef CONFIG_SYSCTL
 static unsigned int udp_sysctl_table_users;
 static struct ctl_table_header *udp_sysctl_header;
 static struct ctl_table udp_sysctl_table[] = {
        {
                .procname       = "nf_conntrack_udp_timeout",
-               .data           = &nf_ct_udp_timeout,
+               .data           = &udp_timeouts[UDP_CT_UNREPLIED],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "nf_conntrack_udp_timeout_stream",
-               .data           = &nf_ct_udp_timeout_stream,
+               .data           = &udp_timeouts[UDP_CT_REPLIED],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
@@ -160,14 +222,14 @@ static struct ctl_table udp_sysctl_table[] = {
 static struct ctl_table udp_compat_sysctl_table[] = {
        {
                .procname       = "ip_conntrack_udp_timeout",
-               .data           = &nf_ct_udp_timeout,
+               .data           = &udp_timeouts[UDP_CT_UNREPLIED],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "ip_conntrack_udp_timeout_stream",
-               .data           = &nf_ct_udp_timeout_stream,
+               .data           = &udp_timeouts[UDP_CT_REPLIED],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
@@ -186,6 +248,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly =
        .invert_tuple           = udp_invert_tuple,
        .print_tuple            = udp_print_tuple,
        .packet                 = udp_packet,
+       .get_timeouts           = udp_get_timeouts,
        .new                    = udp_new,
        .error                  = udp_error,
 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
@@ -194,6 +257,15 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly =
        .nlattr_tuple_size      = nf_ct_port_nlattr_tuple_size,
        .nla_policy             = nf_ct_port_nla_policy,
 #endif
+#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
+       .ctnl_timeout           = {
+               .nlattr_to_obj  = udp_timeout_nlattr_to_obj,
+               .obj_to_nlattr  = udp_timeout_obj_to_nlattr,
+               .nlattr_max     = CTA_TIMEOUT_UDP_MAX,
+               .obj_size       = sizeof(unsigned int) * CTA_TIMEOUT_UDP_MAX,
+               .nla_policy     = udp_timeout_nla_policy,
+       },
+#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 #ifdef CONFIG_SYSCTL
        .ctl_table_users        = &udp_sysctl_table_users,
        .ctl_table_header       = &udp_sysctl_header,
@@ -214,6 +286,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 __read_mostly =
        .invert_tuple           = udp_invert_tuple,
        .print_tuple            = udp_print_tuple,
        .packet                 = udp_packet,
+       .get_timeouts           = udp_get_timeouts,
        .new                    = udp_new,
        .error                  = udp_error,
 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
@@ -222,6 +295,15 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 __read_mostly =
        .nlattr_tuple_size      = nf_ct_port_nlattr_tuple_size,
        .nla_policy             = nf_ct_port_nla_policy,
 #endif
+#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
+       .ctnl_timeout           = {
+               .nlattr_to_obj  = udp_timeout_nlattr_to_obj,
+               .obj_to_nlattr  = udp_timeout_obj_to_nlattr,
+               .nlattr_max     = CTA_TIMEOUT_UDP_MAX,
+               .obj_size       = sizeof(unsigned int) * CTA_TIMEOUT_UDP_MAX,
+               .nla_policy     = udp_timeout_nla_policy,
+       },
+#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 #ifdef CONFIG_SYSCTL
        .ctl_table_users        = &udp_sysctl_table_users,
        .ctl_table_header       = &udp_sysctl_header,
index f52ca1181013e9881d6c2c34d6bccbd4e366d0e2..e0606392cda053a9d1345d465d503e5e6ab20d42 100644 (file)
 #include <net/netfilter/nf_conntrack_ecache.h>
 #include <net/netfilter/nf_log.h>
 
-static unsigned int nf_ct_udplite_timeout __read_mostly = 30*HZ;
-static unsigned int nf_ct_udplite_timeout_stream __read_mostly = 180*HZ;
+enum udplite_conntrack {
+       UDPLITE_CT_UNREPLIED,
+       UDPLITE_CT_REPLIED,
+       UDPLITE_CT_MAX
+};
+
+static unsigned int udplite_timeouts[UDPLITE_CT_MAX] = {
+       [UDPLITE_CT_UNREPLIED]  = 30*HZ,
+       [UDPLITE_CT_REPLIED]    = 180*HZ,
+};
 
 static bool udplite_pkt_to_tuple(const struct sk_buff *skb,
                                 unsigned int dataoff,
@@ -60,31 +68,38 @@ static int udplite_print_tuple(struct seq_file *s,
                          ntohs(tuple->dst.u.udp.port));
 }
 
+static unsigned int *udplite_get_timeouts(struct net *net)
+{
+       return udplite_timeouts;
+}
+
 /* Returns verdict for packet, and may modify conntracktype */
 static int udplite_packet(struct nf_conn *ct,
                          const struct sk_buff *skb,
                          unsigned int dataoff,
                          enum ip_conntrack_info ctinfo,
                          u_int8_t pf,
-                         unsigned int hooknum)
+                         unsigned int hooknum,
+                         unsigned int *timeouts)
 {
        /* If we've seen traffic both ways, this is some kind of UDP
           stream.  Extend timeout. */
        if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
                nf_ct_refresh_acct(ct, ctinfo, skb,
-                                  nf_ct_udplite_timeout_stream);
+                                  timeouts[UDPLITE_CT_REPLIED]);
                /* Also, more likely to be important, and not a probe */
                if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status))
                        nf_conntrack_event_cache(IPCT_ASSURED, ct);
-       } else
-               nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_udplite_timeout);
-
+       } else {
+               nf_ct_refresh_acct(ct, ctinfo, skb,
+                                  timeouts[UDPLITE_CT_UNREPLIED]);
+       }
        return NF_ACCEPT;
 }
 
 /* Called when a new connection for this protocol found. */
 static bool udplite_new(struct nf_conn *ct, const struct sk_buff *skb,
-                       unsigned int dataoff)
+                       unsigned int dataoff, unsigned int *timeouts)
 {
        return true;
 }
@@ -141,20 +156,66 @@ static int udplite_error(struct net *net, struct nf_conn *tmpl,
        return NF_ACCEPT;
 }
 
+#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
+
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nfnetlink_cttimeout.h>
+
+static int udplite_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
+{
+       unsigned int *timeouts = data;
+
+       /* set default timeouts for UDPlite. */
+       timeouts[UDPLITE_CT_UNREPLIED] = udplite_timeouts[UDPLITE_CT_UNREPLIED];
+       timeouts[UDPLITE_CT_REPLIED] = udplite_timeouts[UDPLITE_CT_REPLIED];
+
+       if (tb[CTA_TIMEOUT_UDPLITE_UNREPLIED]) {
+               timeouts[UDPLITE_CT_UNREPLIED] =
+                 ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDPLITE_UNREPLIED])) * HZ;
+       }
+       if (tb[CTA_TIMEOUT_UDPLITE_REPLIED]) {
+               timeouts[UDPLITE_CT_REPLIED] =
+                 ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDPLITE_REPLIED])) * HZ;
+       }
+       return 0;
+}
+
+static int
+udplite_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
+{
+       const unsigned int *timeouts = data;
+
+       NLA_PUT_BE32(skb, CTA_TIMEOUT_UDPLITE_UNREPLIED,
+                       htonl(timeouts[UDPLITE_CT_UNREPLIED] / HZ));
+       NLA_PUT_BE32(skb, CTA_TIMEOUT_UDPLITE_REPLIED,
+                       htonl(timeouts[UDPLITE_CT_REPLIED] / HZ));
+       return 0;
+
+nla_put_failure:
+       return -ENOSPC;
+}
+
+static const struct nla_policy
+udplite_timeout_nla_policy[CTA_TIMEOUT_UDPLITE_MAX+1] = {
+       [CTA_TIMEOUT_UDPLITE_UNREPLIED] = { .type = NLA_U32 },
+       [CTA_TIMEOUT_UDPLITE_REPLIED]   = { .type = NLA_U32 },
+};
+#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
+
 #ifdef CONFIG_SYSCTL
 static unsigned int udplite_sysctl_table_users;
 static struct ctl_table_header *udplite_sysctl_header;
 static struct ctl_table udplite_sysctl_table[] = {
        {
                .procname       = "nf_conntrack_udplite_timeout",
-               .data           = &nf_ct_udplite_timeout,
+               .data           = &udplite_timeouts[UDPLITE_CT_UNREPLIED],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "nf_conntrack_udplite_timeout_stream",
-               .data           = &nf_ct_udplite_timeout_stream,
+               .data           = &udplite_timeouts[UDPLITE_CT_REPLIED],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
@@ -172,6 +233,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 __read_mostly =
        .invert_tuple           = udplite_invert_tuple,
        .print_tuple            = udplite_print_tuple,
        .packet                 = udplite_packet,
+       .get_timeouts           = udplite_get_timeouts,
        .new                    = udplite_new,
        .error                  = udplite_error,
 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
@@ -180,6 +242,16 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 __read_mostly =
        .nlattr_to_tuple        = nf_ct_port_nlattr_to_tuple,
        .nla_policy             = nf_ct_port_nla_policy,
 #endif
+#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
+       .ctnl_timeout           = {
+               .nlattr_to_obj  = udplite_timeout_nlattr_to_obj,
+               .obj_to_nlattr  = udplite_timeout_obj_to_nlattr,
+               .nlattr_max     = CTA_TIMEOUT_UDPLITE_MAX,
+               .obj_size       = sizeof(unsigned int) *
+                                       CTA_TIMEOUT_UDPLITE_MAX,
+               .nla_policy     = udplite_timeout_nla_policy,
+       },
+#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 #ifdef CONFIG_SYSCTL
        .ctl_table_users        = &udplite_sysctl_table_users,
        .ctl_table_header       = &udplite_sysctl_header,
@@ -196,6 +268,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6 __read_mostly =
        .invert_tuple           = udplite_invert_tuple,
        .print_tuple            = udplite_print_tuple,
        .packet                 = udplite_packet,
+       .get_timeouts           = udplite_get_timeouts,
        .new                    = udplite_new,
        .error                  = udplite_error,
 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
@@ -204,6 +277,16 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6 __read_mostly =
        .nlattr_to_tuple        = nf_ct_port_nlattr_to_tuple,
        .nla_policy             = nf_ct_port_nla_policy,
 #endif
+#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
+       .ctnl_timeout           = {
+               .nlattr_to_obj  = udplite_timeout_nlattr_to_obj,
+               .obj_to_nlattr  = udplite_timeout_obj_to_nlattr,
+               .nlattr_max     = CTA_TIMEOUT_UDPLITE_MAX,
+               .obj_size       = sizeof(unsigned int) *
+                                       CTA_TIMEOUT_UDPLITE_MAX,
+               .nla_policy     = udplite_timeout_nla_policy,
+       },
+#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 #ifdef CONFIG_SYSCTL
        .ctl_table_users        = &udplite_sysctl_table_users,
        .ctl_table_header       = &udplite_sysctl_header,
diff --git a/net/netfilter/nf_conntrack_timeout.c b/net/netfilter/nf_conntrack_timeout.c
new file mode 100644 (file)
index 0000000..a878ce5
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
+ * (C) 2012 by Vyatta Inc. <http://www.vyatta.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation (or any later at your option).
+ */
+
+#include <linux/types.h>
+#include <linux/netfilter.h>
+#include <linux/skbuff.h>
+#include <linux/vmalloc.h>
+#include <linux/stddef.h>
+#include <linux/err.h>
+#include <linux/percpu.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/slab.h>
+#include <linux/export.h>
+
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_core.h>
+#include <net/netfilter/nf_conntrack_extend.h>
+#include <net/netfilter/nf_conntrack_timeout.h>
+
+struct ctnl_timeout *
+(*nf_ct_timeout_find_get_hook)(const char *name) __read_mostly;
+EXPORT_SYMBOL_GPL(nf_ct_timeout_find_get_hook);
+
+void (*nf_ct_timeout_put_hook)(struct ctnl_timeout *timeout) __read_mostly;
+EXPORT_SYMBOL_GPL(nf_ct_timeout_put_hook);
+
+static struct nf_ct_ext_type timeout_extend __read_mostly = {
+       .len    = sizeof(struct nf_conn_timeout),
+       .align  = __alignof__(struct nf_conn_timeout),
+       .id     = NF_CT_EXT_TIMEOUT,
+};
+
+int nf_conntrack_timeout_init(struct net *net)
+{
+       int ret = 0;
+
+       if (net_eq(net, &init_net)) {
+               ret = nf_ct_extend_register(&timeout_extend);
+               if (ret < 0) {
+                       printk(KERN_ERR "nf_ct_timeout: Unable to register "
+                                       "timeout extension.\n");
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+void nf_conntrack_timeout_fini(struct net *net)
+{
+       if (net_eq(net, &init_net))
+               nf_ct_extend_unregister(&timeout_extend);
+}
diff --git a/net/netfilter/nfnetlink_cttimeout.c b/net/netfilter/nfnetlink_cttimeout.c
new file mode 100644 (file)
index 0000000..fec29a4
--- /dev/null
@@ -0,0 +1,429 @@
+/*
+ * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
+ * (C) 2012 by Vyatta Inc. <http://www.vyatta.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation (or any later at your option).
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/rculist.h>
+#include <linux/rculist_nulls.h>
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <linux/security.h>
+#include <linux/skbuff.h>
+#include <linux/errno.h>
+#include <linux/netlink.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+
+#include <linux/netfilter.h>
+#include <net/netlink.h>
+#include <net/sock.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_core.h>
+#include <net/netfilter/nf_conntrack_l3proto.h>
+#include <net/netfilter/nf_conntrack_l4proto.h>
+#include <net/netfilter/nf_conntrack_tuple.h>
+#include <net/netfilter/nf_conntrack_timeout.h>
+
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nfnetlink_cttimeout.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
+MODULE_DESCRIPTION("cttimeout: Extended Netfilter Connection Tracking timeout tuning");
+
+static LIST_HEAD(cttimeout_list);
+
+static const struct nla_policy cttimeout_nla_policy[CTA_TIMEOUT_MAX+1] = {
+       [CTA_TIMEOUT_NAME]      = { .type = NLA_NUL_STRING },
+       [CTA_TIMEOUT_L3PROTO]   = { .type = NLA_U16 },
+       [CTA_TIMEOUT_L4PROTO]   = { .type = NLA_U8 },
+       [CTA_TIMEOUT_DATA]      = { .type = NLA_NESTED },
+};
+
+static int
+ctnl_timeout_parse_policy(struct ctnl_timeout *timeout,
+                              struct nf_conntrack_l4proto *l4proto,
+                              const struct nlattr *attr)
+{
+       int ret = 0;
+
+       if (likely(l4proto->ctnl_timeout.nlattr_to_obj)) {
+               struct nlattr *tb[l4proto->ctnl_timeout.nlattr_max+1];
+
+               nla_parse_nested(tb, l4proto->ctnl_timeout.nlattr_max,
+                                attr, l4proto->ctnl_timeout.nla_policy);
+
+               ret = l4proto->ctnl_timeout.nlattr_to_obj(tb, &timeout->data);
+       }
+       return ret;
+}
+
+static int
+cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb,
+                     const struct nlmsghdr *nlh,
+                     const struct nlattr * const cda[])
+{
+       __u16 l3num;
+       __u8 l4num;
+       struct nf_conntrack_l4proto *l4proto;
+       struct ctnl_timeout *timeout, *matching = NULL;
+       char *name;
+       int ret;
+
+       if (!cda[CTA_TIMEOUT_NAME] ||
+           !cda[CTA_TIMEOUT_L3PROTO] ||
+           !cda[CTA_TIMEOUT_L4PROTO] ||
+           !cda[CTA_TIMEOUT_DATA])
+               return -EINVAL;
+
+       name = nla_data(cda[CTA_TIMEOUT_NAME]);
+       l3num = ntohs(nla_get_be16(cda[CTA_TIMEOUT_L3PROTO]));
+       l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]);
+
+       list_for_each_entry(timeout, &cttimeout_list, head) {
+               if (strncmp(timeout->name, name, CTNL_TIMEOUT_NAME_MAX) != 0)
+                       continue;
+
+               if (nlh->nlmsg_flags & NLM_F_EXCL)
+                       return -EEXIST;
+
+               matching = timeout;
+               break;
+       }
+
+       l4proto = __nf_ct_l4proto_find(l3num, l4num);
+
+       /* This protocol is not supportted, skip. */
+       if (l4proto->l4proto != l4num)
+               return -EOPNOTSUPP;
+
+       if (matching) {
+               if (nlh->nlmsg_flags & NLM_F_REPLACE) {
+                       /* You cannot replace one timeout policy by another of
+                        * different kind, sorry.
+                        */
+                       if (matching->l3num != l3num ||
+                           matching->l4num != l4num)
+                               return -EINVAL;
+
+                       ret = ctnl_timeout_parse_policy(matching, l4proto,
+                                                       cda[CTA_TIMEOUT_DATA]);
+                       return ret;
+               }
+               return -EBUSY;
+       }
+
+       timeout = kzalloc(sizeof(struct ctnl_timeout) +
+                         l4proto->ctnl_timeout.obj_size, GFP_KERNEL);
+       if (timeout == NULL)
+               return -ENOMEM;
+
+       ret = ctnl_timeout_parse_policy(timeout, l4proto,
+                                       cda[CTA_TIMEOUT_DATA]);
+       if (ret < 0)
+               goto err;
+
+       strcpy(timeout->name, nla_data(cda[CTA_TIMEOUT_NAME]));
+       timeout->l3num = l3num;
+       timeout->l4num = l4num;
+       atomic_set(&timeout->refcnt, 1);
+       list_add_tail_rcu(&timeout->head, &cttimeout_list);
+
+       return 0;
+err:
+       kfree(timeout);
+       return ret;
+}
+
+static int
+ctnl_timeout_fill_info(struct sk_buff *skb, u32 pid, u32 seq, u32 type,
+                      int event, struct ctnl_timeout *timeout)
+{
+       struct nlmsghdr *nlh;
+       struct nfgenmsg *nfmsg;
+       unsigned int flags = pid ? NLM_F_MULTI : 0;
+       struct nf_conntrack_l4proto *l4proto;
+
+       event |= NFNL_SUBSYS_CTNETLINK_TIMEOUT << 8;
+       nlh = nlmsg_put(skb, pid, seq, event, sizeof(*nfmsg), flags);
+       if (nlh == NULL)
+               goto nlmsg_failure;
+
+       nfmsg = nlmsg_data(nlh);
+       nfmsg->nfgen_family = AF_UNSPEC;
+       nfmsg->version = NFNETLINK_V0;
+       nfmsg->res_id = 0;
+
+       NLA_PUT_STRING(skb, CTA_TIMEOUT_NAME, timeout->name);
+       NLA_PUT_BE16(skb, CTA_TIMEOUT_L3PROTO, htons(timeout->l3num));
+       NLA_PUT_U8(skb, CTA_TIMEOUT_L4PROTO, timeout->l4num);
+       NLA_PUT_BE32(skb, CTA_TIMEOUT_USE,
+                       htonl(atomic_read(&timeout->refcnt)));
+
+       l4proto = __nf_ct_l4proto_find(timeout->l3num, timeout->l4num);
+
+       /* If the timeout object does not match the layer 4 protocol tracker,
+        * then skip dumping the data part since we don't know how to
+        * interpret it. This may happen for UPDlite, SCTP and DCCP since
+        * you can unload the module.
+        */
+       if (timeout->l4num != l4proto->l4proto)
+               goto out;
+
+       if (likely(l4proto->ctnl_timeout.obj_to_nlattr)) {
+               struct nlattr *nest_parms;
+               int ret;
+
+               nest_parms = nla_nest_start(skb,
+                                           CTA_TIMEOUT_DATA | NLA_F_NESTED);
+               if (!nest_parms)
+                       goto nla_put_failure;
+
+               ret = l4proto->ctnl_timeout.obj_to_nlattr(skb, &timeout->data);
+               if (ret < 0)
+                       goto nla_put_failure;
+
+               nla_nest_end(skb, nest_parms);
+       }
+out:
+       nlmsg_end(skb, nlh);
+       return skb->len;
+
+nlmsg_failure:
+nla_put_failure:
+       nlmsg_cancel(skb, nlh);
+       return -1;
+}
+
+static int
+ctnl_timeout_dump(struct sk_buff *skb, struct netlink_callback *cb)
+{
+       struct ctnl_timeout *cur, *last;
+
+       if (cb->args[2])
+               return 0;
+
+       last = (struct ctnl_timeout *)cb->args[1];
+       if (cb->args[1])
+               cb->args[1] = 0;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(cur, &cttimeout_list, head) {
+               if (last && cur != last)
+                       continue;
+
+               if (ctnl_timeout_fill_info(skb, NETLINK_CB(cb->skb).pid,
+                                          cb->nlh->nlmsg_seq,
+                                          NFNL_MSG_TYPE(cb->nlh->nlmsg_type),
+                                          IPCTNL_MSG_TIMEOUT_NEW, cur) < 0) {
+                       cb->args[1] = (unsigned long)cur;
+                       break;
+               }
+       }
+       if (!cb->args[1])
+               cb->args[2] = 1;
+       rcu_read_unlock();
+       return skb->len;
+}
+
+static int
+cttimeout_get_timeout(struct sock *ctnl, struct sk_buff *skb,
+                     const struct nlmsghdr *nlh,
+                     const struct nlattr * const cda[])
+{
+       int ret = -ENOENT;
+       char *name;
+       struct ctnl_timeout *cur;
+
+       if (nlh->nlmsg_flags & NLM_F_DUMP) {
+               struct netlink_dump_control c = {
+                       .dump = ctnl_timeout_dump,
+               };
+               return netlink_dump_start(ctnl, skb, nlh, &c);
+       }
+
+       if (!cda[CTA_TIMEOUT_NAME])
+               return -EINVAL;
+       name = nla_data(cda[CTA_TIMEOUT_NAME]);
+
+       list_for_each_entry(cur, &cttimeout_list, head) {
+               struct sk_buff *skb2;
+
+               if (strncmp(cur->name, name, CTNL_TIMEOUT_NAME_MAX) != 0)
+                       continue;
+
+               skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+               if (skb2 == NULL) {
+                       ret = -ENOMEM;
+                       break;
+               }
+
+               ret = ctnl_timeout_fill_info(skb2, NETLINK_CB(skb).pid,
+                                            nlh->nlmsg_seq,
+                                            NFNL_MSG_TYPE(nlh->nlmsg_type),
+                                            IPCTNL_MSG_TIMEOUT_NEW, cur);
+               if (ret <= 0) {
+                       kfree_skb(skb2);
+                       break;
+               }
+               ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid,
+                                       MSG_DONTWAIT);
+               if (ret > 0)
+                       ret = 0;
+
+               /* this avoids a loop in nfnetlink. */
+               return ret == -EAGAIN ? -ENOBUFS : ret;
+       }
+       return ret;
+}
+
+/* try to delete object, fail if it is still in use. */
+static int ctnl_timeout_try_del(struct ctnl_timeout *timeout)
+{
+       int ret = 0;
+
+       /* we want to avoid races with nf_ct_timeout_find_get. */
+       if (atomic_dec_and_test(&timeout->refcnt)) {
+               /* We are protected by nfnl mutex. */
+               list_del_rcu(&timeout->head);
+               kfree_rcu(timeout, rcu_head);
+       } else {
+               /* still in use, restore reference counter. */
+               atomic_inc(&timeout->refcnt);
+               ret = -EBUSY;
+       }
+       return ret;
+}
+
+static int
+cttimeout_del_timeout(struct sock *ctnl, struct sk_buff *skb,
+                     const struct nlmsghdr *nlh,
+                     const struct nlattr * const cda[])
+{
+       char *name;
+       struct ctnl_timeout *cur;
+       int ret = -ENOENT;
+
+       if (!cda[CTA_TIMEOUT_NAME]) {
+               list_for_each_entry(cur, &cttimeout_list, head)
+                       ctnl_timeout_try_del(cur);
+
+               return 0;
+       }
+       name = nla_data(cda[CTA_TIMEOUT_NAME]);
+
+       list_for_each_entry(cur, &cttimeout_list, head) {
+               if (strncmp(cur->name, name, CTNL_TIMEOUT_NAME_MAX) != 0)
+                       continue;
+
+               ret = ctnl_timeout_try_del(cur);
+               if (ret < 0)
+                       return ret;
+
+               break;
+       }
+       return ret;
+}
+
+#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
+static struct ctnl_timeout *ctnl_timeout_find_get(const char *name)
+{
+       struct ctnl_timeout *timeout, *matching = NULL;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(timeout, &cttimeout_list, head) {
+               if (strncmp(timeout->name, name, CTNL_TIMEOUT_NAME_MAX) != 0)
+                       continue;
+
+               if (!try_module_get(THIS_MODULE))
+                       goto err;
+
+               if (!atomic_inc_not_zero(&timeout->refcnt)) {
+                       module_put(THIS_MODULE);
+                       goto err;
+               }
+               matching = timeout;
+               break;
+       }
+err:
+       rcu_read_unlock();
+       return matching;
+}
+
+static void ctnl_timeout_put(struct ctnl_timeout *timeout)
+{
+       atomic_dec(&timeout->refcnt);
+       module_put(THIS_MODULE);
+}
+#endif /* CONFIG_NF_CONNTRACK_TIMEOUT */
+
+static const struct nfnl_callback cttimeout_cb[IPCTNL_MSG_TIMEOUT_MAX] = {
+       [IPCTNL_MSG_TIMEOUT_NEW]        = { .call = cttimeout_new_timeout,
+                                           .attr_count = CTA_TIMEOUT_MAX,
+                                           .policy = cttimeout_nla_policy },
+       [IPCTNL_MSG_TIMEOUT_GET]        = { .call = cttimeout_get_timeout,
+                                           .attr_count = CTA_TIMEOUT_MAX,
+                                           .policy = cttimeout_nla_policy },
+       [IPCTNL_MSG_TIMEOUT_DELETE]     = { .call = cttimeout_del_timeout,
+                                           .attr_count = CTA_TIMEOUT_MAX,
+                                           .policy = cttimeout_nla_policy },
+};
+
+static const struct nfnetlink_subsystem cttimeout_subsys = {
+       .name                           = "conntrack_timeout",
+       .subsys_id                      = NFNL_SUBSYS_CTNETLINK_TIMEOUT,
+       .cb_count                       = IPCTNL_MSG_TIMEOUT_MAX,
+       .cb                             = cttimeout_cb,
+};
+
+MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK_TIMEOUT);
+
+static int __init cttimeout_init(void)
+{
+       int ret;
+
+       ret = nfnetlink_subsys_register(&cttimeout_subsys);
+       if (ret < 0) {
+               pr_err("cttimeout_init: cannot register cttimeout with "
+                       "nfnetlink.\n");
+               goto err_out;
+       }
+#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
+       RCU_INIT_POINTER(nf_ct_timeout_find_get_hook, ctnl_timeout_find_get);
+       RCU_INIT_POINTER(nf_ct_timeout_put_hook, ctnl_timeout_put);
+#endif /* CONFIG_NF_CONNTRACK_TIMEOUT */
+       return 0;
+
+err_out:
+       return ret;
+}
+
+static void __exit cttimeout_exit(void)
+{
+       struct ctnl_timeout *cur, *tmp;
+
+       pr_info("cttimeout: unregistering from nfnetlink.\n");
+
+       nfnetlink_subsys_unregister(&cttimeout_subsys);
+       list_for_each_entry_safe(cur, tmp, &cttimeout_list, head) {
+               list_del_rcu(&cur->head);
+               /* We are sure that our objects have no clients at this point,
+                * it's safe to release them all without checking refcnt.
+                */
+               kfree_rcu(cur, rcu_head);
+       }
+#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
+       RCU_INIT_POINTER(nf_ct_timeout_find_get_hook, NULL);
+       RCU_INIT_POINTER(nf_ct_timeout_put_hook, NULL);
+#endif /* CONFIG_NF_CONNTRACK_TIMEOUT */
+}
+
+module_init(cttimeout_init);
+module_exit(cttimeout_exit);
index 0221d10de75a517dbc4c5e5c7d40b432abef15a3..b873445df444e6230965bc8ec3c544b94d4236c0 100644 (file)
 #include <net/netfilter/nf_conntrack.h>
 #include <net/netfilter/nf_conntrack_helper.h>
 #include <net/netfilter/nf_conntrack_ecache.h>
+#include <net/netfilter/nf_conntrack_timeout.h>
 #include <net/netfilter/nf_conntrack_zones.h>
 
-static unsigned int xt_ct_target(struct sk_buff *skb,
-                                const struct xt_action_param *par)
+static unsigned int xt_ct_target_v0(struct sk_buff *skb,
+                                   const struct xt_action_param *par)
 {
        const struct xt_ct_target_info *info = par->targinfo;
        struct nf_conn *ct = info->ct;
@@ -35,6 +36,23 @@ static unsigned int xt_ct_target(struct sk_buff *skb,
        return XT_CONTINUE;
 }
 
+static unsigned int xt_ct_target_v1(struct sk_buff *skb,
+                                   const struct xt_action_param *par)
+{
+       const struct xt_ct_target_info_v1 *info = par->targinfo;
+       struct nf_conn *ct = info->ct;
+
+       /* Previously seen (loopback)? Ignore. */
+       if (skb->nfct != NULL)
+               return XT_CONTINUE;
+
+       atomic_inc(&ct->ct_general.use);
+       skb->nfct = &ct->ct_general;
+       skb->nfctinfo = IP_CT_NEW;
+
+       return XT_CONTINUE;
+}
+
 static u8 xt_ct_find_proto(const struct xt_tgchk_param *par)
 {
        if (par->family == NFPROTO_IPV4) {
@@ -53,7 +71,7 @@ static u8 xt_ct_find_proto(const struct xt_tgchk_param *par)
                return 0;
 }
 
-static int xt_ct_tg_check(const struct xt_tgchk_param *par)
+static int xt_ct_tg_check_v0(const struct xt_tgchk_param *par)
 {
        struct xt_ct_target_info *info = par->targinfo;
        struct nf_conntrack_tuple t;
@@ -130,7 +148,137 @@ err1:
        return ret;
 }
 
-static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par)
+static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par)
+{
+       struct xt_ct_target_info_v1 *info = par->targinfo;
+       struct nf_conntrack_tuple t;
+       struct nf_conn_help *help;
+       struct nf_conn *ct;
+       int ret = 0;
+       u8 proto;
+
+       if (info->flags & ~XT_CT_NOTRACK)
+               return -EINVAL;
+
+       if (info->flags & XT_CT_NOTRACK) {
+               ct = nf_ct_untracked_get();
+               atomic_inc(&ct->ct_general.use);
+               goto out;
+       }
+
+#ifndef CONFIG_NF_CONNTRACK_ZONES
+       if (info->zone)
+               goto err1;
+#endif
+
+       ret = nf_ct_l3proto_try_module_get(par->family);
+       if (ret < 0)
+               goto err1;
+
+       memset(&t, 0, sizeof(t));
+       ct = nf_conntrack_alloc(par->net, info->zone, &t, &t, GFP_KERNEL);
+       ret = PTR_ERR(ct);
+       if (IS_ERR(ct))
+               goto err2;
+
+       ret = 0;
+       if ((info->ct_events || info->exp_events) &&
+           !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events,
+                                 GFP_KERNEL))
+               goto err3;
+
+       if (info->helper[0]) {
+               ret = -ENOENT;
+               proto = xt_ct_find_proto(par);
+               if (!proto) {
+                       pr_info("You must specify a L4 protocol, "
+                               "and not use inversions on it.\n");
+                       goto err3;
+               }
+
+               ret = -ENOMEM;
+               help = nf_ct_helper_ext_add(ct, GFP_KERNEL);
+               if (help == NULL)
+                       goto err3;
+
+               ret = -ENOENT;
+               help->helper = nf_conntrack_helper_try_module_get(info->helper,
+                                                                 par->family,
+                                                                 proto);
+               if (help->helper == NULL) {
+                       pr_info("No such helper \"%s\"\n", info->helper);
+                       goto err3;
+               }
+       }
+
+#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
+       if (info->timeout) {
+               typeof(nf_ct_timeout_find_get_hook) timeout_find_get;
+               struct ctnl_timeout *timeout;
+               struct nf_conn_timeout *timeout_ext;
+
+               timeout_find_get =
+                       rcu_dereference(nf_ct_timeout_find_get_hook);
+
+               if (timeout_find_get) {
+                       const struct ipt_entry *e = par->entryinfo;
+
+                       if (e->ip.invflags & IPT_INV_PROTO) {
+                               ret = -EINVAL;
+                               pr_info("You cannot use inversion on "
+                                        "L4 protocol\n");
+                               goto err3;
+                       }
+                       timeout = timeout_find_get(info->timeout);
+                       if (timeout == NULL) {
+                               ret = -ENOENT;
+                               pr_info("No such timeout policy \"%s\"\n",
+                                       info->timeout);
+                               goto err3;
+                       }
+                       if (timeout->l3num != par->family) {
+                               ret = -EINVAL;
+                               pr_info("Timeout policy `%s' can only be "
+                                       "used by L3 protocol number %d\n",
+                                       info->timeout, timeout->l3num);
+                               goto err3;
+                       }
+                       if (timeout->l4num != e->ip.proto) {
+                               ret = -EINVAL;
+                               pr_info("Timeout policy `%s' can only be "
+                                       "used by L4 protocol number %d\n",
+                                       info->timeout, timeout->l4num);
+                               goto err3;
+                       }
+                       timeout_ext = nf_ct_timeout_ext_add(ct, timeout,
+                                                           GFP_KERNEL);
+                       if (timeout_ext == NULL) {
+                               ret = -ENOMEM;
+                               goto err3;
+                       }
+               } else {
+                       ret = -ENOENT;
+                       pr_info("Timeout policy base is empty\n");
+                       goto err3;
+               }
+       }
+#endif
+
+       __set_bit(IPS_TEMPLATE_BIT, &ct->status);
+       __set_bit(IPS_CONFIRMED_BIT, &ct->status);
+out:
+       info->ct = ct;
+       return 0;
+
+err3:
+       nf_conntrack_free(ct);
+err2:
+       nf_ct_l3proto_module_put(par->family);
+err1:
+       return ret;
+}
+
+static void xt_ct_tg_destroy_v0(const struct xt_tgdtor_param *par)
 {
        struct xt_ct_target_info *info = par->targinfo;
        struct nf_conn *ct = info->ct;
@@ -146,25 +294,67 @@ static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par)
        nf_ct_put(info->ct);
 }
 
-static struct xt_target xt_ct_tg __read_mostly = {
-       .name           = "CT",
-       .family         = NFPROTO_UNSPEC,
-       .targetsize     = sizeof(struct xt_ct_target_info),
-       .checkentry     = xt_ct_tg_check,
-       .destroy        = xt_ct_tg_destroy,
-       .target         = xt_ct_target,
-       .table          = "raw",
-       .me             = THIS_MODULE,
+static void xt_ct_tg_destroy_v1(const struct xt_tgdtor_param *par)
+{
+       struct xt_ct_target_info_v1 *info = par->targinfo;
+       struct nf_conn *ct = info->ct;
+       struct nf_conn_help *help;
+#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
+       struct nf_conn_timeout *timeout_ext;
+       typeof(nf_ct_timeout_put_hook) timeout_put;
+#endif
+       if (!nf_ct_is_untracked(ct)) {
+               help = nfct_help(ct);
+               if (help)
+                       module_put(help->helper->me);
+
+               nf_ct_l3proto_module_put(par->family);
+
+#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
+               timeout_put = rcu_dereference(nf_ct_timeout_put_hook);
+
+               if (timeout_put) {
+                       timeout_ext = nf_ct_timeout_find(ct);
+                       if (timeout_ext)
+                               timeout_put(timeout_ext->timeout);
+               }
+#endif
+       }
+       nf_ct_put(info->ct);
+}
+
+static struct xt_target xt_ct_tg_reg[] __read_mostly = {
+       {
+               .name           = "CT",
+               .family         = NFPROTO_UNSPEC,
+               .targetsize     = sizeof(struct xt_ct_target_info),
+               .checkentry     = xt_ct_tg_check_v0,
+               .destroy        = xt_ct_tg_destroy_v0,
+               .target         = xt_ct_target_v0,
+               .table          = "raw",
+               .me             = THIS_MODULE,
+       },
+       {
+               .name           = "CT",
+               .family         = NFPROTO_UNSPEC,
+               .revision       = 1,
+               .targetsize     = sizeof(struct xt_ct_target_info_v1),
+               .checkentry     = xt_ct_tg_check_v1,
+               .destroy        = xt_ct_tg_destroy_v1,
+               .target         = xt_ct_target_v1,
+               .table          = "raw",
+               .me             = THIS_MODULE,
+       },
 };
 
 static int __init xt_ct_tg_init(void)
 {
-       return xt_register_target(&xt_ct_tg);
+       return xt_register_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg));
 }
 
 static void __exit xt_ct_tg_exit(void)
 {
-       xt_unregister_target(&xt_ct_tg);
+       xt_unregister_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg));
 }
 
 module_init(xt_ct_tg_init);
diff --git a/net/netfilter/xt_LOG.c b/net/netfilter/xt_LOG.c
new file mode 100644 (file)
index 0000000..f99f8de
--- /dev/null
@@ -0,0 +1,925 @@
+/*
+ * This is a module which is used for logging packets.
+ */
+
+/* (C) 1999-2001 Paul `Rusty' Russell
+ * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/ip.h>
+#include <net/ipv6.h>
+#include <net/icmp.h>
+#include <net/udp.h>
+#include <net/tcp.h>
+#include <net/route.h>
+
+#include <linux/netfilter.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_LOG.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <net/netfilter/nf_log.h>
+#include <net/netfilter/xt_log.h>
+
+static struct nf_loginfo default_loginfo = {
+       .type   = NF_LOG_TYPE_LOG,
+       .u = {
+               .log = {
+                       .level    = 5,
+                       .logflags = NF_LOG_MASK,
+               },
+       },
+};
+
+static int dump_udp_header(struct sbuff *m, const struct sk_buff *skb,
+                          u8 proto, int fragment, unsigned int offset)
+{
+       struct udphdr _udph;
+       const struct udphdr *uh;
+
+       if (proto == IPPROTO_UDP)
+               /* Max length: 10 "PROTO=UDP "     */
+               sb_add(m, "PROTO=UDP ");
+       else    /* Max length: 14 "PROTO=UDPLITE " */
+               sb_add(m, "PROTO=UDPLITE ");
+
+       if (fragment)
+               goto out;
+
+       /* Max length: 25 "INCOMPLETE [65535 bytes] " */
+       uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
+       if (uh == NULL) {
+               sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - offset);
+
+               return 1;
+       }
+
+       /* Max length: 20 "SPT=65535 DPT=65535 " */
+       sb_add(m, "SPT=%u DPT=%u LEN=%u ", ntohs(uh->source), ntohs(uh->dest),
+               ntohs(uh->len));
+
+out:
+       return 0;
+}
+
+static int dump_tcp_header(struct sbuff *m, const struct sk_buff *skb,
+                          u8 proto, int fragment, unsigned int offset,
+                          unsigned int logflags)
+{
+       struct tcphdr _tcph;
+       const struct tcphdr *th;
+
+       /* Max length: 10 "PROTO=TCP " */
+       sb_add(m, "PROTO=TCP ");
+
+       if (fragment)
+               return 0;
+
+       /* Max length: 25 "INCOMPLETE [65535 bytes] " */
+       th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
+       if (th == NULL) {
+               sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - offset);
+               return 1;
+       }
+
+       /* Max length: 20 "SPT=65535 DPT=65535 " */
+       sb_add(m, "SPT=%u DPT=%u ", ntohs(th->source), ntohs(th->dest));
+       /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */
+       if (logflags & XT_LOG_TCPSEQ)
+               sb_add(m, "SEQ=%u ACK=%u ", ntohl(th->seq), ntohl(th->ack_seq));
+
+       /* Max length: 13 "WINDOW=65535 " */
+       sb_add(m, "WINDOW=%u ", ntohs(th->window));
+       /* Max length: 9 "RES=0x3C " */
+       sb_add(m, "RES=0x%02x ", (u_int8_t)(ntohl(tcp_flag_word(th) &
+                                           TCP_RESERVED_BITS) >> 22));
+       /* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */
+       if (th->cwr)
+               sb_add(m, "CWR ");
+       if (th->ece)
+               sb_add(m, "ECE ");
+       if (th->urg)
+               sb_add(m, "URG ");
+       if (th->ack)
+               sb_add(m, "ACK ");
+       if (th->psh)
+               sb_add(m, "PSH ");
+       if (th->rst)
+               sb_add(m, "RST ");
+       if (th->syn)
+               sb_add(m, "SYN ");
+       if (th->fin)
+               sb_add(m, "FIN ");
+       /* Max length: 11 "URGP=65535 " */
+       sb_add(m, "URGP=%u ", ntohs(th->urg_ptr));
+
+       if ((logflags & XT_LOG_TCPOPT) && th->doff*4 > sizeof(struct tcphdr)) {
+               u_int8_t _opt[60 - sizeof(struct tcphdr)];
+               const u_int8_t *op;
+               unsigned int i;
+               unsigned int optsize = th->doff*4 - sizeof(struct tcphdr);
+
+               op = skb_header_pointer(skb, offset + sizeof(struct tcphdr),
+                                       optsize, _opt);
+               if (op == NULL) {
+                       sb_add(m, "OPT (TRUNCATED)");
+                       return 1;
+               }
+
+               /* Max length: 127 "OPT (" 15*4*2chars ") " */
+               sb_add(m, "OPT (");
+               for (i = 0; i < optsize; i++)
+                       sb_add(m, "%02X", op[i]);
+
+               sb_add(m, ") ");
+       }
+
+       return 0;
+}
+
+/* One level of recursion won't kill us */
+static void dump_ipv4_packet(struct sbuff *m,
+                       const struct nf_loginfo *info,
+                       const struct sk_buff *skb,
+                       unsigned int iphoff)
+{
+       struct iphdr _iph;
+       const struct iphdr *ih;
+       unsigned int logflags;
+
+       if (info->type == NF_LOG_TYPE_LOG)
+               logflags = info->u.log.logflags;
+       else
+               logflags = NF_LOG_MASK;
+
+       ih = skb_header_pointer(skb, iphoff, sizeof(_iph), &_iph);
+       if (ih == NULL) {
+               sb_add(m, "TRUNCATED");
+               return;
+       }
+
+       /* Important fields:
+        * TOS, len, DF/MF, fragment offset, TTL, src, dst, options. */
+       /* Max length: 40 "SRC=255.255.255.255 DST=255.255.255.255 " */
+       sb_add(m, "SRC=%pI4 DST=%pI4 ",
+              &ih->saddr, &ih->daddr);
+
+       /* Max length: 46 "LEN=65535 TOS=0xFF PREC=0xFF TTL=255 ID=65535 " */
+       sb_add(m, "LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ",
+              ntohs(ih->tot_len), ih->tos & IPTOS_TOS_MASK,
+              ih->tos & IPTOS_PREC_MASK, ih->ttl, ntohs(ih->id));
+
+       /* Max length: 6 "CE DF MF " */
+       if (ntohs(ih->frag_off) & IP_CE)
+               sb_add(m, "CE ");
+       if (ntohs(ih->frag_off) & IP_DF)
+               sb_add(m, "DF ");
+       if (ntohs(ih->frag_off) & IP_MF)
+               sb_add(m, "MF ");
+
+       /* Max length: 11 "FRAG:65535 " */
+       if (ntohs(ih->frag_off) & IP_OFFSET)
+               sb_add(m, "FRAG:%u ", ntohs(ih->frag_off) & IP_OFFSET);
+
+       if ((logflags & XT_LOG_IPOPT) &&
+           ih->ihl * 4 > sizeof(struct iphdr)) {
+               const unsigned char *op;
+               unsigned char _opt[4 * 15 - sizeof(struct iphdr)];
+               unsigned int i, optsize;
+
+               optsize = ih->ihl * 4 - sizeof(struct iphdr);
+               op = skb_header_pointer(skb, iphoff+sizeof(_iph),
+                                       optsize, _opt);
+               if (op == NULL) {
+                       sb_add(m, "TRUNCATED");
+                       return;
+               }
+
+               /* Max length: 127 "OPT (" 15*4*2chars ") " */
+               sb_add(m, "OPT (");
+               for (i = 0; i < optsize; i++)
+                       sb_add(m, "%02X", op[i]);
+               sb_add(m, ") ");
+       }
+
+       switch (ih->protocol) {
+       case IPPROTO_TCP:
+               if (dump_tcp_header(m, skb, ih->protocol,
+                                   ntohs(ih->frag_off) & IP_OFFSET,
+                                   iphoff+ih->ihl*4, logflags))
+                       return;
+               break;
+       case IPPROTO_UDP:
+       case IPPROTO_UDPLITE:
+               if (dump_udp_header(m, skb, ih->protocol,
+                                   ntohs(ih->frag_off) & IP_OFFSET,
+                                   iphoff+ih->ihl*4))
+                       return;
+               break;
+       case IPPROTO_ICMP: {
+               struct icmphdr _icmph;
+               const struct icmphdr *ich;
+               static const size_t required_len[NR_ICMP_TYPES+1]
+                       = { [ICMP_ECHOREPLY] = 4,
+                           [ICMP_DEST_UNREACH]
+                           = 8 + sizeof(struct iphdr),
+                           [ICMP_SOURCE_QUENCH]
+                           = 8 + sizeof(struct iphdr),
+                           [ICMP_REDIRECT]
+                           = 8 + sizeof(struct iphdr),
+                           [ICMP_ECHO] = 4,
+                           [ICMP_TIME_EXCEEDED]
+                           = 8 + sizeof(struct iphdr),
+                           [ICMP_PARAMETERPROB]
+                           = 8 + sizeof(struct iphdr),
+                           [ICMP_TIMESTAMP] = 20,
+                           [ICMP_TIMESTAMPREPLY] = 20,
+                           [ICMP_ADDRESS] = 12,
+                           [ICMP_ADDRESSREPLY] = 12 };
+
+               /* Max length: 11 "PROTO=ICMP " */
+               sb_add(m, "PROTO=ICMP ");
+
+               if (ntohs(ih->frag_off) & IP_OFFSET)
+                       break;
+
+               /* Max length: 25 "INCOMPLETE [65535 bytes] " */
+               ich = skb_header_pointer(skb, iphoff + ih->ihl * 4,
+                                        sizeof(_icmph), &_icmph);
+               if (ich == NULL) {
+                       sb_add(m, "INCOMPLETE [%u bytes] ",
+                              skb->len - iphoff - ih->ihl*4);
+                       break;
+               }
+
+               /* Max length: 18 "TYPE=255 CODE=255 " */
+               sb_add(m, "TYPE=%u CODE=%u ", ich->type, ich->code);
+
+               /* Max length: 25 "INCOMPLETE [65535 bytes] " */
+               if (ich->type <= NR_ICMP_TYPES &&
+                   required_len[ich->type] &&
+                   skb->len-iphoff-ih->ihl*4 < required_len[ich->type]) {
+                       sb_add(m, "INCOMPLETE [%u bytes] ",
+                              skb->len - iphoff - ih->ihl*4);
+                       break;
+               }
+
+               switch (ich->type) {
+               case ICMP_ECHOREPLY:
+               case ICMP_ECHO:
+                       /* Max length: 19 "ID=65535 SEQ=65535 " */
+                       sb_add(m, "ID=%u SEQ=%u ",
+                              ntohs(ich->un.echo.id),
+                              ntohs(ich->un.echo.sequence));
+                       break;
+
+               case ICMP_PARAMETERPROB:
+                       /* Max length: 14 "PARAMETER=255 " */
+                       sb_add(m, "PARAMETER=%u ",
+                              ntohl(ich->un.gateway) >> 24);
+                       break;
+               case ICMP_REDIRECT:
+                       /* Max length: 24 "GATEWAY=255.255.255.255 " */
+                       sb_add(m, "GATEWAY=%pI4 ", &ich->un.gateway);
+                       /* Fall through */
+               case ICMP_DEST_UNREACH:
+               case ICMP_SOURCE_QUENCH:
+               case ICMP_TIME_EXCEEDED:
+                       /* Max length: 3+maxlen */
+                       if (!iphoff) { /* Only recurse once. */
+                               sb_add(m, "[");
+                               dump_ipv4_packet(m, info, skb,
+                                           iphoff + ih->ihl*4+sizeof(_icmph));
+                               sb_add(m, "] ");
+                       }
+
+                       /* Max length: 10 "MTU=65535 " */
+                       if (ich->type == ICMP_DEST_UNREACH &&
+                           ich->code == ICMP_FRAG_NEEDED)
+                               sb_add(m, "MTU=%u ", ntohs(ich->un.frag.mtu));
+               }
+               break;
+       }
+       /* Max Length */
+       case IPPROTO_AH: {
+               struct ip_auth_hdr _ahdr;
+               const struct ip_auth_hdr *ah;
+
+               if (ntohs(ih->frag_off) & IP_OFFSET)
+                       break;
+
+               /* Max length: 9 "PROTO=AH " */
+               sb_add(m, "PROTO=AH ");
+
+               /* Max length: 25 "INCOMPLETE [65535 bytes] " */
+               ah = skb_header_pointer(skb, iphoff+ih->ihl*4,
+                                       sizeof(_ahdr), &_ahdr);
+               if (ah == NULL) {
+                       sb_add(m, "INCOMPLETE [%u bytes] ",
+                              skb->len - iphoff - ih->ihl*4);
+                       break;
+               }
+
+               /* Length: 15 "SPI=0xF1234567 " */
+               sb_add(m, "SPI=0x%x ", ntohl(ah->spi));
+               break;
+       }
+       case IPPROTO_ESP: {
+               struct ip_esp_hdr _esph;
+               const struct ip_esp_hdr *eh;
+
+               /* Max length: 10 "PROTO=ESP " */
+               sb_add(m, "PROTO=ESP ");
+
+               if (ntohs(ih->frag_off) & IP_OFFSET)
+                       break;
+
+               /* Max length: 25 "INCOMPLETE [65535 bytes] " */
+               eh = skb_header_pointer(skb, iphoff+ih->ihl*4,
+                                       sizeof(_esph), &_esph);
+               if (eh == NULL) {
+                       sb_add(m, "INCOMPLETE [%u bytes] ",
+                              skb->len - iphoff - ih->ihl*4);
+                       break;
+               }
+
+               /* Length: 15 "SPI=0xF1234567 " */
+               sb_add(m, "SPI=0x%x ", ntohl(eh->spi));
+               break;
+       }
+       /* Max length: 10 "PROTO 255 " */
+       default:
+               sb_add(m, "PROTO=%u ", ih->protocol);
+       }
+
+       /* Max length: 15 "UID=4294967295 " */
+       if ((logflags & XT_LOG_UID) && !iphoff && skb->sk) {
+               read_lock_bh(&skb->sk->sk_callback_lock);
+               if (skb->sk->sk_socket && skb->sk->sk_socket->file)
+                       sb_add(m, "UID=%u GID=%u ",
+                               skb->sk->sk_socket->file->f_cred->fsuid,
+                               skb->sk->sk_socket->file->f_cred->fsgid);
+               read_unlock_bh(&skb->sk->sk_callback_lock);
+       }
+
+       /* Max length: 16 "MARK=0xFFFFFFFF " */
+       if (!iphoff && skb->mark)
+               sb_add(m, "MARK=0x%x ", skb->mark);
+
+       /* Proto    Max log string length */
+       /* IP:      40+46+6+11+127 = 230 */
+       /* TCP:     10+max(25,20+30+13+9+32+11+127) = 252 */
+       /* UDP:     10+max(25,20) = 35 */
+       /* UDPLITE: 14+max(25,20) = 39 */
+       /* ICMP:    11+max(25, 18+25+max(19,14,24+3+n+10,3+n+10)) = 91+n */
+       /* ESP:     10+max(25)+15 = 50 */
+       /* AH:      9+max(25)+15 = 49 */
+       /* unknown: 10 */
+
+       /* (ICMP allows recursion one level deep) */
+       /* maxlen =  IP + ICMP +  IP + max(TCP,UDP,ICMP,unknown) */
+       /* maxlen = 230+   91  + 230 + 252 = 803 */
+}
+
+static void dump_ipv4_mac_header(struct sbuff *m,
+                           const struct nf_loginfo *info,
+                           const struct sk_buff *skb)
+{
+       struct net_device *dev = skb->dev;
+       unsigned int logflags = 0;
+
+       if (info->type == NF_LOG_TYPE_LOG)
+               logflags = info->u.log.logflags;
+
+       if (!(logflags & XT_LOG_MACDECODE))
+               goto fallback;
+
+       switch (dev->type) {
+       case ARPHRD_ETHER:
+               sb_add(m, "MACSRC=%pM MACDST=%pM MACPROTO=%04x ",
+                      eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest,
+                      ntohs(eth_hdr(skb)->h_proto));
+               return;
+       default:
+               break;
+       }
+
+fallback:
+       sb_add(m, "MAC=");
+       if (dev->hard_header_len &&
+           skb->mac_header != skb->network_header) {
+               const unsigned char *p = skb_mac_header(skb);
+               unsigned int i;
+
+               sb_add(m, "%02x", *p++);
+               for (i = 1; i < dev->hard_header_len; i++, p++)
+                       sb_add(m, ":%02x", *p);
+       }
+       sb_add(m, " ");
+}
+
+static void
+log_packet_common(struct sbuff *m,
+                 u_int8_t pf,
+                 unsigned int hooknum,
+                 const struct sk_buff *skb,
+                 const struct net_device *in,
+                 const struct net_device *out,
+                 const struct nf_loginfo *loginfo,
+                 const char *prefix)
+{
+       sb_add(m, "<%d>%sIN=%s OUT=%s ", loginfo->u.log.level,
+              prefix,
+              in ? in->name : "",
+              out ? out->name : "");
+#ifdef CONFIG_BRIDGE_NETFILTER
+       if (skb->nf_bridge) {
+               const struct net_device *physindev;
+               const struct net_device *physoutdev;
+
+               physindev = skb->nf_bridge->physindev;
+               if (physindev && in != physindev)
+                       sb_add(m, "PHYSIN=%s ", physindev->name);
+               physoutdev = skb->nf_bridge->physoutdev;
+               if (physoutdev && out != physoutdev)
+                       sb_add(m, "PHYSOUT=%s ", physoutdev->name);
+       }
+#endif
+}
+
+
+static void
+ipt_log_packet(u_int8_t pf,
+              unsigned int hooknum,
+              const struct sk_buff *skb,
+              const struct net_device *in,
+              const struct net_device *out,
+              const struct nf_loginfo *loginfo,
+              const char *prefix)
+{
+       struct sbuff *m = sb_open();
+
+       if (!loginfo)
+               loginfo = &default_loginfo;
+
+       log_packet_common(m, pf, hooknum, skb, in, out, loginfo, prefix);
+
+       if (in != NULL)
+               dump_ipv4_mac_header(m, loginfo, skb);
+
+       dump_ipv4_packet(m, loginfo, skb, 0);
+
+       sb_close(m);
+}
+
+#if IS_ENABLED(CONFIG_IPV6)
+/* One level of recursion won't kill us */
+static void dump_ipv6_packet(struct sbuff *m,
+                       const struct nf_loginfo *info,
+                       const struct sk_buff *skb, unsigned int ip6hoff,
+                       int recurse)
+{
+       u_int8_t currenthdr;
+       int fragment;
+       struct ipv6hdr _ip6h;
+       const struct ipv6hdr *ih;
+       unsigned int ptr;
+       unsigned int hdrlen = 0;
+       unsigned int logflags;
+
+       if (info->type == NF_LOG_TYPE_LOG)
+               logflags = info->u.log.logflags;
+       else
+               logflags = NF_LOG_MASK;
+
+       ih = skb_header_pointer(skb, ip6hoff, sizeof(_ip6h), &_ip6h);
+       if (ih == NULL) {
+               sb_add(m, "TRUNCATED");
+               return;
+       }
+
+       /* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000 " */
+       sb_add(m, "SRC=%pI6 DST=%pI6 ", &ih->saddr, &ih->daddr);
+
+       /* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */
+       sb_add(m, "LEN=%Zu TC=%u HOPLIMIT=%u FLOWLBL=%u ",
+              ntohs(ih->payload_len) + sizeof(struct ipv6hdr),
+              (ntohl(*(__be32 *)ih) & 0x0ff00000) >> 20,
+              ih->hop_limit,
+              (ntohl(*(__be32 *)ih) & 0x000fffff));
+
+       fragment = 0;
+       ptr = ip6hoff + sizeof(struct ipv6hdr);
+       currenthdr = ih->nexthdr;
+       while (currenthdr != NEXTHDR_NONE && ip6t_ext_hdr(currenthdr)) {
+               struct ipv6_opt_hdr _hdr;
+               const struct ipv6_opt_hdr *hp;
+
+               hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
+               if (hp == NULL) {
+                       sb_add(m, "TRUNCATED");
+                       return;
+               }
+
+               /* Max length: 48 "OPT (...) " */
+               if (logflags & XT_LOG_IPOPT)
+                       sb_add(m, "OPT ( ");
+
+               switch (currenthdr) {
+               case IPPROTO_FRAGMENT: {
+                       struct frag_hdr _fhdr;
+                       const struct frag_hdr *fh;
+
+                       sb_add(m, "FRAG:");
+                       fh = skb_header_pointer(skb, ptr, sizeof(_fhdr),
+                                               &_fhdr);
+                       if (fh == NULL) {
+                               sb_add(m, "TRUNCATED ");
+                               return;
+                       }
+
+                       /* Max length: 6 "65535 " */
+                       sb_add(m, "%u ", ntohs(fh->frag_off) & 0xFFF8);
+
+                       /* Max length: 11 "INCOMPLETE " */
+                       if (fh->frag_off & htons(0x0001))
+                               sb_add(m, "INCOMPLETE ");
+
+                       sb_add(m, "ID:%08x ", ntohl(fh->identification));
+
+                       if (ntohs(fh->frag_off) & 0xFFF8)
+                               fragment = 1;
+
+                       hdrlen = 8;
+
+                       break;
+               }
+               case IPPROTO_DSTOPTS:
+               case IPPROTO_ROUTING:
+               case IPPROTO_HOPOPTS:
+                       if (fragment) {
+                               if (logflags & XT_LOG_IPOPT)
+                                       sb_add(m, ")");
+                               return;
+                       }
+                       hdrlen = ipv6_optlen(hp);
+                       break;
+               /* Max Length */
+               case IPPROTO_AH:
+                       if (logflags & XT_LOG_IPOPT) {
+                               struct ip_auth_hdr _ahdr;
+                               const struct ip_auth_hdr *ah;
+
+                               /* Max length: 3 "AH " */
+                               sb_add(m, "AH ");
+
+                               if (fragment) {
+                                       sb_add(m, ")");
+                                       return;
+                               }
+
+                               ah = skb_header_pointer(skb, ptr, sizeof(_ahdr),
+                                                       &_ahdr);
+                               if (ah == NULL) {
+                                       /*
+                                        * Max length: 26 "INCOMPLETE [65535
+                                        *  bytes] )"
+                                        */
+                                       sb_add(m, "INCOMPLETE [%u bytes] )",
+                                              skb->len - ptr);
+                                       return;
+                               }
+
+                               /* Length: 15 "SPI=0xF1234567 */
+                               sb_add(m, "SPI=0x%x ", ntohl(ah->spi));
+
+                       }
+
+                       hdrlen = (hp->hdrlen+2)<<2;
+                       break;
+               case IPPROTO_ESP:
+                       if (logflags & XT_LOG_IPOPT) {
+                               struct ip_esp_hdr _esph;
+                               const struct ip_esp_hdr *eh;
+
+                               /* Max length: 4 "ESP " */
+                               sb_add(m, "ESP ");
+
+                               if (fragment) {
+                                       sb_add(m, ")");
+                                       return;
+                               }
+
+                               /*
+                                * Max length: 26 "INCOMPLETE [65535 bytes] )"
+                                */
+                               eh = skb_header_pointer(skb, ptr, sizeof(_esph),
+                                                       &_esph);
+                               if (eh == NULL) {
+                                       sb_add(m, "INCOMPLETE [%u bytes] )",
+                                              skb->len - ptr);
+                                       return;
+                               }
+
+                               /* Length: 16 "SPI=0xF1234567 )" */
+                               sb_add(m, "SPI=0x%x )", ntohl(eh->spi));
+
+                       }
+                       return;
+               default:
+                       /* Max length: 20 "Unknown Ext Hdr 255" */
+                       sb_add(m, "Unknown Ext Hdr %u", currenthdr);
+                       return;
+               }
+               if (logflags & XT_LOG_IPOPT)
+                       sb_add(m, ") ");
+
+               currenthdr = hp->nexthdr;
+               ptr += hdrlen;
+       }
+
+       switch (currenthdr) {
+       case IPPROTO_TCP:
+               if (dump_tcp_header(m, skb, currenthdr, fragment, ptr,
+                   logflags))
+                       return;
+               break;
+       case IPPROTO_UDP:
+       case IPPROTO_UDPLITE:
+               if (dump_udp_header(m, skb, currenthdr, fragment, ptr))
+                       return;
+               break;
+       case IPPROTO_ICMPV6: {
+               struct icmp6hdr _icmp6h;
+               const struct icmp6hdr *ic;
+
+               /* Max length: 13 "PROTO=ICMPv6 " */
+               sb_add(m, "PROTO=ICMPv6 ");
+
+               if (fragment)
+                       break;
+
+               /* Max length: 25 "INCOMPLETE [65535 bytes] " */
+               ic = skb_header_pointer(skb, ptr, sizeof(_icmp6h), &_icmp6h);
+               if (ic == NULL) {
+                       sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - ptr);
+                       return;
+               }
+
+               /* Max length: 18 "TYPE=255 CODE=255 " */
+               sb_add(m, "TYPE=%u CODE=%u ", ic->icmp6_type, ic->icmp6_code);
+
+               switch (ic->icmp6_type) {
+               case ICMPV6_ECHO_REQUEST:
+               case ICMPV6_ECHO_REPLY:
+                       /* Max length: 19 "ID=65535 SEQ=65535 " */
+                       sb_add(m, "ID=%u SEQ=%u ",
+                               ntohs(ic->icmp6_identifier),
+                               ntohs(ic->icmp6_sequence));
+                       break;
+               case ICMPV6_MGM_QUERY:
+               case ICMPV6_MGM_REPORT:
+               case ICMPV6_MGM_REDUCTION:
+                       break;
+
+               case ICMPV6_PARAMPROB:
+                       /* Max length: 17 "POINTER=ffffffff " */
+                       sb_add(m, "POINTER=%08x ", ntohl(ic->icmp6_pointer));
+                       /* Fall through */
+               case ICMPV6_DEST_UNREACH:
+               case ICMPV6_PKT_TOOBIG:
+               case ICMPV6_TIME_EXCEED:
+                       /* Max length: 3+maxlen */
+                       if (recurse) {
+                               sb_add(m, "[");
+                               dump_ipv6_packet(m, info, skb,
+                                           ptr + sizeof(_icmp6h), 0);
+                               sb_add(m, "] ");
+                       }
+
+                       /* Max length: 10 "MTU=65535 " */
+                       if (ic->icmp6_type == ICMPV6_PKT_TOOBIG)
+                               sb_add(m, "MTU=%u ", ntohl(ic->icmp6_mtu));
+               }
+               break;
+       }
+       /* Max length: 10 "PROTO=255 " */
+       default:
+               sb_add(m, "PROTO=%u ", currenthdr);
+       }
+
+       /* Max length: 15 "UID=4294967295 " */
+       if ((logflags & XT_LOG_UID) && recurse && skb->sk) {
+               read_lock_bh(&skb->sk->sk_callback_lock);
+               if (skb->sk->sk_socket && skb->sk->sk_socket->file)
+                       sb_add(m, "UID=%u GID=%u ",
+                               skb->sk->sk_socket->file->f_cred->fsuid,
+                               skb->sk->sk_socket->file->f_cred->fsgid);
+               read_unlock_bh(&skb->sk->sk_callback_lock);
+       }
+
+       /* Max length: 16 "MARK=0xFFFFFFFF " */
+       if (!recurse && skb->mark)
+               sb_add(m, "MARK=0x%x ", skb->mark);
+}
+
+static void dump_ipv6_mac_header(struct sbuff *m,
+                           const struct nf_loginfo *info,
+                           const struct sk_buff *skb)
+{
+       struct net_device *dev = skb->dev;
+       unsigned int logflags = 0;
+
+       if (info->type == NF_LOG_TYPE_LOG)
+               logflags = info->u.log.logflags;
+
+       if (!(logflags & XT_LOG_MACDECODE))
+               goto fallback;
+
+       switch (dev->type) {
+       case ARPHRD_ETHER:
+               sb_add(m, "MACSRC=%pM MACDST=%pM MACPROTO=%04x ",
+                      eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest,
+                      ntohs(eth_hdr(skb)->h_proto));
+               return;
+       default:
+               break;
+       }
+
+fallback:
+       sb_add(m, "MAC=");
+       if (dev->hard_header_len &&
+           skb->mac_header != skb->network_header) {
+               const unsigned char *p = skb_mac_header(skb);
+               unsigned int len = dev->hard_header_len;
+               unsigned int i;
+
+               if (dev->type == ARPHRD_SIT) {
+                       p -= ETH_HLEN;
+
+                       if (p < skb->head)
+                               p = NULL;
+               }
+
+               if (p != NULL) {
+                       sb_add(m, "%02x", *p++);
+                       for (i = 1; i < len; i++)
+                               sb_add(m, ":%02x", *p++);
+               }
+               sb_add(m, " ");
+
+               if (dev->type == ARPHRD_SIT) {
+                       const struct iphdr *iph =
+                               (struct iphdr *)skb_mac_header(skb);
+                       sb_add(m, "TUNNEL=%pI4->%pI4 ", &iph->saddr,
+                              &iph->daddr);
+               }
+       } else
+               sb_add(m, " ");
+}
+
+static void
+ip6t_log_packet(u_int8_t pf,
+               unsigned int hooknum,
+               const struct sk_buff *skb,
+               const struct net_device *in,
+               const struct net_device *out,
+               const struct nf_loginfo *loginfo,
+               const char *prefix)
+{
+       struct sbuff *m = sb_open();
+
+       if (!loginfo)
+               loginfo = &default_loginfo;
+
+       log_packet_common(m, pf, hooknum, skb, in, out, loginfo, prefix);
+
+       if (in != NULL)
+               dump_ipv6_mac_header(m, loginfo, skb);
+
+       dump_ipv6_packet(m, loginfo, skb, skb_network_offset(skb), 1);
+
+       sb_close(m);
+}
+#endif
+
+static unsigned int
+log_tg(struct sk_buff *skb, const struct xt_action_param *par)
+{
+       const struct xt_log_info *loginfo = par->targinfo;
+       struct nf_loginfo li;
+
+       li.type = NF_LOG_TYPE_LOG;
+       li.u.log.level = loginfo->level;
+       li.u.log.logflags = loginfo->logflags;
+
+       if (par->family == NFPROTO_IPV4)
+               ipt_log_packet(NFPROTO_IPV4, par->hooknum, skb, par->in,
+                              par->out, &li, loginfo->prefix);
+#if IS_ENABLED(CONFIG_IPV6)
+       else if (par->family == NFPROTO_IPV6)
+               ip6t_log_packet(NFPROTO_IPV6, par->hooknum, skb, par->in,
+                               par->out, &li, loginfo->prefix);
+#endif
+       else
+               WARN_ON_ONCE(1);
+
+       return XT_CONTINUE;
+}
+
+static int log_tg_check(const struct xt_tgchk_param *par)
+{
+       const struct xt_log_info *loginfo = par->targinfo;
+
+       if (par->family != NFPROTO_IPV4 && par->family != NFPROTO_IPV6)
+               return -EINVAL;
+
+       if (loginfo->level >= 8) {
+               pr_debug("level %u >= 8\n", loginfo->level);
+               return -EINVAL;
+       }
+
+       if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') {
+               pr_debug("prefix is not null-terminated\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static struct xt_target log_tg_regs[] __read_mostly = {
+       {
+               .name           = "LOG",
+               .family         = NFPROTO_IPV4,
+               .target         = log_tg,
+               .targetsize     = sizeof(struct xt_log_info),
+               .checkentry     = log_tg_check,
+               .me             = THIS_MODULE,
+       },
+#if IS_ENABLED(CONFIG_IPV6)
+       {
+               .name           = "LOG",
+               .family         = NFPROTO_IPV6,
+               .target         = log_tg,
+               .targetsize     = sizeof(struct xt_log_info),
+               .checkentry     = log_tg_check,
+               .me             = THIS_MODULE,
+       },
+#endif
+};
+
+static struct nf_logger ipt_log_logger __read_mostly = {
+       .name           = "ipt_LOG",
+       .logfn          = &ipt_log_packet,
+       .me             = THIS_MODULE,
+};
+
+#if IS_ENABLED(CONFIG_IPV6)
+static struct nf_logger ip6t_log_logger __read_mostly = {
+       .name           = "ip6t_LOG",
+       .logfn          = &ip6t_log_packet,
+       .me             = THIS_MODULE,
+};
+#endif
+
+static int __init log_tg_init(void)
+{
+       int ret;
+
+       ret = xt_register_targets(log_tg_regs, ARRAY_SIZE(log_tg_regs));
+       if (ret < 0)
+               return ret;
+
+       nf_log_register(NFPROTO_IPV4, &ipt_log_logger);
+#if IS_ENABLED(CONFIG_IPV6)
+       nf_log_register(NFPROTO_IPV6, &ip6t_log_logger);
+#endif
+       return 0;
+}
+
+static void __exit log_tg_exit(void)
+{
+       nf_log_unregister(&ipt_log_logger);
+#if IS_ENABLED(CONFIG_IPV6)
+       nf_log_unregister(&ip6t_log_logger);
+#endif
+       xt_unregister_targets(log_tg_regs, ARRAY_SIZE(log_tg_regs));
+}
+
+module_init(log_tg_init);
+module_exit(log_tg_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
+MODULE_AUTHOR("Jan Rekorajski <baggins@pld.org.pl>");
+MODULE_DESCRIPTION("Xtables: IPv4/IPv6 packet logging");
+MODULE_ALIAS("ipt_LOG");
+MODULE_ALIAS("ip6t_LOG");
index da67756425ce927f233bd9f490e58befbefd4390..9d68441e2a5ab571ab5e5d20891251bedd3b2d7b 100644 (file)
@@ -30,7 +30,7 @@ static DEFINE_RWLOCK(proto_tab_lock);
 static const struct nfc_protocol *proto_tab[NFC_SOCKPROTO_MAX];
 
 static int nfc_sock_create(struct net *net, struct socket *sock, int proto,
-                                                               int kern)
+                          int kern)
 {
        int rc = -EPROTONOSUPPORT;
 
index 6089aca67b14de1b3396d3eea1d8baa83c676547..295d129864d246cb6c1a3b993dfbc54ebc826bad 100644 (file)
@@ -181,13 +181,13 @@ error:
        return rc;
 }
 
-int nfc_dep_link_up(struct nfc_dev *dev, int target_index,
-                                       u8 comm_mode, u8 rf_mode)
+int nfc_dep_link_up(struct nfc_dev *dev, int target_index, u8 comm_mode)
 {
        int rc = 0;
+       u8 *gb;
+       size_t gb_len;
 
-       pr_debug("dev_name=%s comm:%d rf:%d\n",
-                       dev_name(&dev->dev), comm_mode, rf_mode);
+       pr_debug("dev_name=%s comm %d\n", dev_name(&dev->dev), comm_mode);
 
        if (!dev->ops->dep_link_up)
                return -EOPNOTSUPP;
@@ -204,7 +204,13 @@ int nfc_dep_link_up(struct nfc_dev *dev, int target_index,
                goto error;
        }
 
-       rc = dev->ops->dep_link_up(dev, target_index, comm_mode, rf_mode);
+       gb = nfc_llcp_general_bytes(dev, &gb_len);
+       if (gb_len > NFC_MAX_GT_LEN) {
+               rc = -EINVAL;
+               goto error;
+       }
+
+       rc = dev->ops->dep_link_up(dev, target_index, comm_mode, gb, gb_len);
 
 error:
        device_unlock(&dev->dev);
@@ -250,7 +256,7 @@ error:
 }
 
 int nfc_dep_link_is_up(struct nfc_dev *dev, u32 target_idx,
-                                       u8 comm_mode, u8 rf_mode)
+                      u8 comm_mode, u8 rf_mode)
 {
        dev->dep_link_up = true;
        dev->dep_rf_mode = rf_mode;
@@ -330,10 +336,8 @@ error:
  *
  * The user must wait for the callback before calling this function again.
  */
-int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx,
-                                       struct sk_buff *skb,
-                                       data_exchange_cb_t cb,
-                                       void *cb_context)
+int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, struct sk_buff *skb,
+                     data_exchange_cb_t cb, void *cb_context)
 {
        int rc;
 
@@ -357,8 +361,7 @@ error:
 
 int nfc_set_remote_general_bytes(struct nfc_dev *dev, u8 *gb, u8 gb_len)
 {
-       pr_debug("dev_name=%s gb_len=%d\n",
-                       dev_name(&dev->dev), gb_len);
+       pr_debug("dev_name=%s gb_len=%d\n", dev_name(&dev->dev), gb_len);
 
        if (gb_len > NFC_MAX_GT_LEN)
                return -EINVAL;
@@ -367,12 +370,6 @@ int nfc_set_remote_general_bytes(struct nfc_dev *dev, u8 *gb, u8 gb_len)
 }
 EXPORT_SYMBOL(nfc_set_remote_general_bytes);
 
-u8 *nfc_get_local_general_bytes(struct nfc_dev *dev, u8 *gt_len)
-{
-       return nfc_llcp_general_bytes(dev, gt_len);
-}
-EXPORT_SYMBOL(nfc_get_local_general_bytes);
-
 /**
  * nfc_alloc_send_skb - allocate a skb for data exchange responses
  *
@@ -380,8 +377,8 @@ EXPORT_SYMBOL(nfc_get_local_general_bytes);
  * @gfp: gfp flags
  */
 struct sk_buff *nfc_alloc_send_skb(struct nfc_dev *dev, struct sock *sk,
-                                       unsigned int flags, unsigned int size,
-                                       unsigned int *err)
+                                  unsigned int flags, unsigned int size,
+                                  unsigned int *err)
 {
        struct sk_buff *skb;
        unsigned int total_size;
@@ -428,8 +425,8 @@ EXPORT_SYMBOL(nfc_alloc_recv_skb);
  * are found. After calling this function, the device driver must stop
  * polling for targets.
  */
-int nfc_targets_found(struct nfc_dev *dev, struct nfc_target *targets,
-                                                       int n_targets)
+int nfc_targets_found(struct nfc_dev *dev,
+                     struct nfc_target *targets, int n_targets)
 {
        pr_debug("dev_name=%s n_targets=%d\n", dev_name(&dev->dev), n_targets);
 
@@ -441,7 +438,7 @@ int nfc_targets_found(struct nfc_dev *dev, struct nfc_target *targets,
 
        kfree(dev->targets);
        dev->targets = kmemdup(targets, n_targets * sizeof(struct nfc_target),
-                                                               GFP_ATOMIC);
+                              GFP_ATOMIC);
 
        if (!dev->targets) {
                dev->n_targets = 0;
@@ -501,15 +498,14 @@ struct nfc_dev *nfc_get_device(unsigned idx)
  * @supported_protocols: NFC protocols supported by the device
  */
 struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
-                                       u32 supported_protocols,
-                                       int tx_headroom,
-                                       int tx_tailroom)
+                                   u32 supported_protocols,
+                                   int tx_headroom, int tx_tailroom)
 {
        static atomic_t dev_no = ATOMIC_INIT(0);
        struct nfc_dev *dev;
 
        if (!ops->start_poll || !ops->stop_poll || !ops->activate_target ||
-               !ops->deactivate_target || !ops->data_exchange)
+           !ops->deactivate_target || !ops->data_exchange)
                return NULL;
 
        if (!supported_protocols)
index 151f2ef429c4cf93708bdb6d1524ccf6f2b1cb55..7b76eb7192f37fc50167d39ff6d2a1d7ffc400e4 100644 (file)
@@ -118,7 +118,7 @@ u8 *nfc_llcp_build_tlv(u8 type, u8 *value, u8 value_length, u8 *tlv_length)
 }
 
 int nfc_llcp_parse_tlv(struct nfc_llcp_local *local,
-                       u8 *tlv_array, u16 tlv_array_len)
+                      u8 *tlv_array, u16 tlv_array_len)
 {
        u8 *tlv = tlv_array, type, length, offset = 0;
 
@@ -152,6 +152,8 @@ int nfc_llcp_parse_tlv(struct nfc_llcp_local *local,
                case LLCP_TLV_RW:
                        local->remote_rw = llcp_tlv_rw(tlv);
                        break;
+               case LLCP_TLV_SN:
+                       break;
                default:
                        pr_err("Invalid gt tlv value 0x%x\n", type);
                        break;
@@ -162,15 +164,15 @@ int nfc_llcp_parse_tlv(struct nfc_llcp_local *local,
        }
 
        pr_debug("version 0x%x miu %d lto %d opt 0x%x wks 0x%x rw %d\n",
-               local->remote_version, local->remote_miu,
-               local->remote_lto, local->remote_opt,
-               local->remote_wks, local->remote_rw);
+                local->remote_version, local->remote_miu,
+                local->remote_lto, local->remote_opt,
+                local->remote_wks, local->remote_rw);
 
        return 0;
 }
 
 static struct sk_buff *llcp_add_header(struct sk_buff *pdu,
-                                       u8 dsap, u8 ssap, u8 ptype)
+                                      u8 dsap, u8 ssap, u8 ptype)
 {
        u8 header[2];
 
@@ -186,7 +188,8 @@ static struct sk_buff *llcp_add_header(struct sk_buff *pdu,
        return pdu;
 }
 
-static struct sk_buff *llcp_add_tlv(struct sk_buff *pdu, u8 *tlv, u8 tlv_length)
+static struct sk_buff *llcp_add_tlv(struct sk_buff *pdu, u8 *tlv,
+                                   u8 tlv_length)
 {
        /* XXX Add an skb length check */
 
@@ -199,7 +202,7 @@ static struct sk_buff *llcp_add_tlv(struct sk_buff *pdu, u8 *tlv, u8 tlv_length)
 }
 
 static struct sk_buff *llcp_allocate_pdu(struct nfc_llcp_sock *sock,
-                                                       u8 cmd, u16 size)
+                                        u8 cmd, u16 size)
 {
        struct sk_buff *skb;
        int err;
@@ -208,7 +211,7 @@ static struct sk_buff *llcp_allocate_pdu(struct nfc_llcp_sock *sock,
                return NULL;
 
        skb = nfc_alloc_send_skb(sock->dev, &sock->sk, MSG_DONTWAIT,
-                                       size + LLCP_HEADER_SIZE, &err);
+                                size + LLCP_HEADER_SIZE, &err);
        if (skb == NULL) {
                pr_err("Could not allocate PDU\n");
                return NULL;
@@ -276,7 +279,7 @@ int nfc_llcp_send_symm(struct nfc_dev *dev)
        skb = llcp_add_header(skb, 0, 0, LLCP_PDU_SYMM);
 
        return nfc_data_exchange(dev, local->target_idx, skb,
-                                       nfc_llcp_recv, local);
+                                nfc_llcp_recv, local);
 }
 
 int nfc_llcp_send_connect(struct nfc_llcp_sock *sock)
@@ -284,6 +287,9 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock)
        struct nfc_llcp_local *local;
        struct sk_buff *skb;
        u8 *service_name_tlv = NULL, service_name_tlv_length;
+       u8 *miux_tlv = NULL, miux_tlv_length;
+       u8 *rw_tlv = NULL, rw_tlv_length, rw;
+       __be16 miux;
        int err;
        u16 size = 0;
 
@@ -295,12 +301,21 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock)
 
        if (sock->service_name != NULL) {
                service_name_tlv = nfc_llcp_build_tlv(LLCP_TLV_SN,
-                                       sock->service_name,
-                                       sock->service_name_len,
-                                       &service_name_tlv_length);
+                                                     sock->service_name,
+                                                     sock->service_name_len,
+                                                     &service_name_tlv_length);
                size += service_name_tlv_length;
        }
 
+       miux = cpu_to_be16(LLCP_MAX_MIUX);
+       miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0,
+                                     &miux_tlv_length);
+       size += miux_tlv_length;
+
+       rw = LLCP_MAX_RW;
+       rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &rw, 0, &rw_tlv_length);
+       size += rw_tlv_length;
+
        pr_debug("SKB size %d SN length %zu\n", size, sock->service_name_len);
 
        skb = llcp_allocate_pdu(sock, LLCP_PDU_CONNECT, size);
@@ -311,7 +326,10 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock)
 
        if (service_name_tlv != NULL)
                skb = llcp_add_tlv(skb, service_name_tlv,
-                                       service_name_tlv_length);
+                                  service_name_tlv_length);
+
+       skb = llcp_add_tlv(skb, miux_tlv, miux_tlv_length);
+       skb = llcp_add_tlv(skb, rw_tlv, rw_tlv_length);
 
        skb_queue_tail(&local->tx_queue, skb);
 
@@ -321,6 +339,8 @@ error_tlv:
        pr_err("error %d\n", err);
 
        kfree(service_name_tlv);
+       kfree(miux_tlv);
+       kfree(rw_tlv);
 
        return err;
 }
@@ -329,6 +349,11 @@ int nfc_llcp_send_cc(struct nfc_llcp_sock *sock)
 {
        struct nfc_llcp_local *local;
        struct sk_buff *skb;
+       u8 *miux_tlv = NULL, miux_tlv_length;
+       u8 *rw_tlv = NULL, rw_tlv_length, rw;
+       __be16 miux;
+       int err;
+       u16 size = 0;
 
        pr_debug("Sending CC\n");
 
@@ -336,13 +361,35 @@ int nfc_llcp_send_cc(struct nfc_llcp_sock *sock)
        if (local == NULL)
                return -ENODEV;
 
-       skb = llcp_allocate_pdu(sock, LLCP_PDU_CC, 0);
-       if (skb == NULL)
-               return -ENOMEM;
+       miux = cpu_to_be16(LLCP_MAX_MIUX);
+       miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0,
+                                     &miux_tlv_length);
+       size += miux_tlv_length;
+
+       rw = LLCP_MAX_RW;
+       rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &rw, 0, &rw_tlv_length);
+       size += rw_tlv_length;
+
+       skb = llcp_allocate_pdu(sock, LLCP_PDU_CC, size);
+       if (skb == NULL) {
+               err = -ENOMEM;
+               goto error_tlv;
+       }
+
+       skb = llcp_add_tlv(skb, miux_tlv, miux_tlv_length);
+       skb = llcp_add_tlv(skb, rw_tlv, rw_tlv_length);
 
        skb_queue_tail(&local->tx_queue, skb);
 
        return 0;
+
+error_tlv:
+       pr_err("error %d\n", err);
+
+       kfree(miux_tlv);
+       kfree(rw_tlv);
+
+       return err;
 }
 
 int nfc_llcp_send_dm(struct nfc_llcp_local *local, u8 ssap, u8 dsap, u8 reason)
@@ -397,3 +444,87 @@ int nfc_llcp_send_disconnect(struct nfc_llcp_sock *sock)
 
        return 0;
 }
+
+int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
+                         struct msghdr *msg, size_t len)
+{
+       struct sk_buff *pdu;
+       struct sock *sk = &sock->sk;
+       struct nfc_llcp_local *local;
+       size_t frag_len = 0, remaining_len;
+       u8 *msg_data, *msg_ptr;
+
+       pr_debug("Send I frame len %zd\n", len);
+
+       local = sock->local;
+       if (local == NULL)
+               return -ENODEV;
+
+       msg_data = kzalloc(len, GFP_KERNEL);
+       if (msg_data == NULL)
+               return -ENOMEM;
+
+       if (memcpy_fromiovec(msg_data, msg->msg_iov, len)) {
+               kfree(msg_data);
+               return -EFAULT;
+       }
+
+       remaining_len = len;
+       msg_ptr = msg_data;
+
+       while (remaining_len > 0) {
+
+               frag_len = min_t(u16, local->remote_miu, remaining_len);
+
+               pr_debug("Fragment %zd bytes remaining %zd",
+                        frag_len, remaining_len);
+
+               pdu = llcp_allocate_pdu(sock, LLCP_PDU_I,
+                                       frag_len + LLCP_SEQUENCE_SIZE);
+               if (pdu == NULL)
+                       return -ENOMEM;
+
+               skb_put(pdu, LLCP_SEQUENCE_SIZE);
+
+               memcpy(skb_put(pdu, frag_len), msg_ptr, frag_len);
+
+               skb_queue_head(&sock->tx_queue, pdu);
+
+               lock_sock(sk);
+
+               nfc_llcp_queue_i_frames(sock);
+
+               release_sock(sk);
+
+               remaining_len -= frag_len;
+               msg_ptr += len;
+       }
+
+       kfree(msg_data);
+
+       return 0;
+}
+
+int nfc_llcp_send_rr(struct nfc_llcp_sock *sock)
+{
+       struct sk_buff *skb;
+       struct nfc_llcp_local *local;
+
+       pr_debug("Send rr nr %d\n", sock->recv_n);
+
+       local = sock->local;
+       if (local == NULL)
+               return -ENODEV;
+
+       skb = llcp_allocate_pdu(sock, LLCP_PDU_RR, LLCP_SEQUENCE_SIZE);
+       if (skb == NULL)
+               return -ENOMEM;
+
+       skb_put(skb, LLCP_SEQUENCE_SIZE);
+
+       skb->data[2] = sock->recv_n % 16;
+
+       skb_queue_head(&local->tx_queue, skb);
+
+       return 0;
+}
index 1d32680807d67f3729bb19724d9c09ba2f4cc599..17a578f641f12f8bf5b98a58996af292e5ef50a0 100644 (file)
@@ -37,7 +37,6 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local)
        struct sock *sk, *parent_sk;
        int i;
 
-
        mutex_lock(&local->socket_lock);
 
        for (i = 0; i < LLCP_MAX_SAP; i++) {
@@ -47,7 +46,7 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local)
 
                /* Release all child sockets */
                list_for_each_entry_safe(s, n, &parent->list, list) {
-                       list_del(&s->list);
+                       list_del_init(&s->list);
                        sk = &s->sk;
 
                        lock_sock(sk);
@@ -56,9 +55,12 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local)
                                nfc_put_device(s->dev);
 
                        sk->sk_state = LLCP_CLOSED;
-                       sock_set_flag(sk, SOCK_DEAD);
 
                        release_sock(sk);
+
+                       sock_orphan(sk);
+
+                       s->local = NULL;
                }
 
                parent_sk = &parent->sk;
@@ -70,18 +72,19 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local)
                        struct sock *accept_sk;
 
                        list_for_each_entry_safe(lsk, n, &parent->accept_queue,
-                                                               accept_queue) {
+                                                accept_queue) {
                                accept_sk = &lsk->sk;
                                lock_sock(accept_sk);
 
                                nfc_llcp_accept_unlink(accept_sk);
 
                                accept_sk->sk_state = LLCP_CLOSED;
-                               sock_set_flag(accept_sk, SOCK_DEAD);
 
                                release_sock(accept_sk);
 
                                sock_orphan(accept_sk);
+
+                               lsk->local = NULL;
                        }
                }
 
@@ -89,18 +92,32 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local)
                        nfc_put_device(parent->dev);
 
                parent_sk->sk_state = LLCP_CLOSED;
-               sock_set_flag(parent_sk, SOCK_DEAD);
 
                release_sock(parent_sk);
+
+               sock_orphan(parent_sk);
+
+               parent->local = NULL;
        }
 
        mutex_unlock(&local->socket_lock);
 }
 
+static void nfc_llcp_clear_sdp(struct nfc_llcp_local *local)
+{
+       mutex_lock(&local->sdp_lock);
+
+       local->local_wks = 0;
+       local->local_sdp = 0;
+       local->local_sap = 0;
+
+       mutex_unlock(&local->sdp_lock);
+}
+
 static void nfc_llcp_timeout_work(struct work_struct *work)
 {
        struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local,
-                                                       timeout_work);
+                                                   timeout_work);
 
        nfc_dep_link_down(local->dev);
 }
@@ -146,7 +163,7 @@ static int nfc_llcp_wks_sap(char *service_name, size_t service_name_len)
 
        num_wks = ARRAY_SIZE(wks);
 
-       for (sap = 0 ; sap < num_wks; sap++) {
+       for (sap = 0; sap < num_wks; sap++) {
                if (wks[sap] == NULL)
                        continue;
 
@@ -158,13 +175,13 @@ static int nfc_llcp_wks_sap(char *service_name, size_t service_name_len)
 }
 
 u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local,
-                               struct nfc_llcp_sock *sock)
+                        struct nfc_llcp_sock *sock)
 {
        mutex_lock(&local->sdp_lock);
 
        if (sock->service_name != NULL && sock->service_name_len > 0) {
                int ssap = nfc_llcp_wks_sap(sock->service_name,
-                                               sock->service_name_len);
+                                           sock->service_name_len);
 
                if (ssap > 0) {
                        pr_debug("WKS %d\n", ssap);
@@ -176,7 +193,7 @@ u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local,
                                return LLCP_SAP_MAX;
                        }
 
-                       set_bit(BIT(ssap), &local->local_wks);
+                       set_bit(ssap, &local->local_wks);
                        mutex_unlock(&local->sdp_lock);
 
                        return ssap;
@@ -195,25 +212,25 @@ u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local,
 
                pr_debug("SDP ssap %d\n", LLCP_WKS_NUM_SAP + ssap);
 
-               set_bit(BIT(ssap), &local->local_sdp);
+               set_bit(ssap, &local->local_sdp);
                mutex_unlock(&local->sdp_lock);
 
                return LLCP_WKS_NUM_SAP + ssap;
 
        } else if (sock->ssap != 0) {
                if (sock->ssap < LLCP_WKS_NUM_SAP) {
-                       if (!(local->local_wks & BIT(sock->ssap))) {
-                               set_bit(BIT(sock->ssap), &local->local_wks);
+                       if (!test_bit(sock->ssap, &local->local_wks)) {
+                               set_bit(sock->ssap, &local->local_wks);
                                mutex_unlock(&local->sdp_lock);
 
                                return sock->ssap;
                        }
 
                } else if (sock->ssap < LLCP_SDP_NUM_SAP) {
-                       if (!(local->local_sdp &
-                               BIT(sock->ssap - LLCP_WKS_NUM_SAP))) {
-                               set_bit(BIT(sock->ssap - LLCP_WKS_NUM_SAP),
-                                                       &local->local_sdp);
+                       if (!test_bit(sock->ssap - LLCP_WKS_NUM_SAP,
+                                     &local->local_sdp)) {
+                               set_bit(sock->ssap - LLCP_WKS_NUM_SAP,
+                                       &local->local_sdp);
                                mutex_unlock(&local->sdp_lock);
 
                                return sock->ssap;
@@ -238,7 +255,7 @@ u8 nfc_llcp_get_local_ssap(struct nfc_llcp_local *local)
                return LLCP_SAP_MAX;
        }
 
-       set_bit(BIT(local_ssap), &local->local_sap);
+       set_bit(local_ssap, &local->local_sap);
 
        mutex_unlock(&local->sdp_lock);
 
@@ -265,12 +282,12 @@ void nfc_llcp_put_ssap(struct nfc_llcp_local *local, u8 ssap)
 
        mutex_lock(&local->sdp_lock);
 
-       clear_bit(1 << local_ssap, sdp);
+       clear_bit(local_ssap, sdp);
 
        mutex_unlock(&local->sdp_lock);
 }
 
-u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, u8 *general_bytes_len)
+u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *general_bytes_len)
 {
        struct nfc_llcp_local *local;
 
@@ -294,7 +311,7 @@ static int nfc_llcp_build_gb(struct nfc_llcp_local *local)
 
        version = LLCP_VERSION_11;
        version_tlv = nfc_llcp_build_tlv(LLCP_TLV_VERSION, &version,
-                                                       1, &version_length);
+                                        1, &version_length);
        gb_len += version_length;
 
        /* 1500 ms */
@@ -304,7 +321,7 @@ static int nfc_llcp_build_gb(struct nfc_llcp_local *local)
 
        pr_debug("Local wks 0x%lx\n", local->local_wks);
        wks_tlv = nfc_llcp_build_tlv(LLCP_TLV_WKS, (u8 *)&local->local_wks, 2,
-                                                               &wks_length);
+                                    &wks_length);
        gb_len += wks_length;
 
        gb_len += ARRAY_SIZE(llcp_magic);
@@ -349,8 +366,7 @@ int nfc_llcp_set_remote_gb(struct nfc_dev *dev, u8 *gb, u8 gb_len)
        memcpy(local->remote_gb, gb, gb_len);
        local->remote_gb_len = gb_len;
 
-       if (local->remote_gb == NULL ||
-                       local->remote_gb_len == 0)
+       if (local->remote_gb == NULL || local->remote_gb_len == 0)
                return -ENODEV;
 
        if (memcmp(local->remote_gb, llcp_magic, 3)) {
@@ -359,26 +375,27 @@ int nfc_llcp_set_remote_gb(struct nfc_dev *dev, u8 *gb, u8 gb_len)
        }
 
        return nfc_llcp_parse_tlv(local,
-                       &local->remote_gb[3], local->remote_gb_len - 3);
+                                 &local->remote_gb[3],
+                                 local->remote_gb_len - 3);
 }
 
 static void nfc_llcp_tx_work(struct work_struct *work)
 {
        struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local,
-                                                       tx_work);
+                                                   tx_work);
        struct sk_buff *skb;
 
        skb = skb_dequeue(&local->tx_queue);
        if (skb != NULL) {
                pr_debug("Sending pending skb\n");
                nfc_data_exchange(local->dev, local->target_idx,
-                                       skb, nfc_llcp_recv, local);
+                                 skb, nfc_llcp_recv, local);
        } else {
                nfc_llcp_send_symm(local->dev);
        }
 
        mod_timer(&local->link_timer,
-                       jiffies + msecs_to_jiffies(local->remote_lto));
+                 jiffies + msecs_to_jiffies(local->remote_lto));
 }
 
 static u8 nfc_llcp_dsap(struct sk_buff *pdu)
@@ -408,13 +425,13 @@ static u8 nfc_llcp_nr(struct sk_buff *pdu)
 
 static void nfc_llcp_set_nrns(struct nfc_llcp_sock *sock, struct sk_buff *pdu)
 {
-       pdu->data[2] = (sock->send_n << 4) | ((sock->recv_n - 1) % 16);
+       pdu->data[2] = (sock->send_n << 4) | (sock->recv_n % 16);
        sock->send_n = (sock->send_n + 1) % 16;
        sock->recv_ack_n = (sock->recv_n - 1) % 16;
 }
 
 static struct nfc_llcp_sock *nfc_llcp_sock_get(struct nfc_llcp_local *local,
-                                               u8 ssap, u8 dsap)
+                                              u8 ssap, u8 dsap)
 {
        struct nfc_llcp_sock *sock, *llcp_sock, *n;
 
@@ -438,7 +455,7 @@ static struct nfc_llcp_sock *nfc_llcp_sock_get(struct nfc_llcp_local *local,
 
        list_for_each_entry_safe(llcp_sock, n, &sock->list, list) {
                pr_debug("llcp_sock %p sk %p dsap %d\n", llcp_sock,
-                               &llcp_sock->sk, llcp_sock->dsap);
+                        &llcp_sock->sk, llcp_sock->dsap);
                if (llcp_sock->dsap == dsap) {
                        sock_hold(&llcp_sock->sk);
                        mutex_unlock(&local->socket_lock);
@@ -482,7 +499,7 @@ static u8 *nfc_llcp_connect_sn(struct sk_buff *skb, size_t *sn_len)
 }
 
 static void nfc_llcp_recv_connect(struct nfc_llcp_local *local,
-                               struct sk_buff *skb)
+                                 struct sk_buff *skb)
 {
        struct sock *new_sk, *parent;
        struct nfc_llcp_sock *sock, *new_sock;
@@ -494,7 +511,7 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local,
        pr_debug("%d %d\n", dsap, ssap);
 
        nfc_llcp_parse_tlv(local, &skb->data[LLCP_HEADER_SIZE],
-                               skb->len - LLCP_HEADER_SIZE);
+                          skb->len - LLCP_HEADER_SIZE);
 
        if (dsap != LLCP_SAP_SDP) {
                bound_sap = dsap;
@@ -513,7 +530,7 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local,
                lock_sock(&sock->sk);
 
                if (sock->dsap == LLCP_SAP_SDP &&
-                               sock->sk.sk_state == LLCP_LISTEN)
+                   sock->sk.sk_state == LLCP_LISTEN)
                        goto enqueue;
        } else {
                u8 *sn;
@@ -529,23 +546,23 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local,
 
                mutex_lock(&local->socket_lock);
                for (bound_sap = 0; bound_sap < LLCP_LOCAL_SAP_OFFSET;
-                                                               bound_sap++) {
+                    bound_sap++) {
                        sock = local->sockets[bound_sap];
                        if (sock == NULL)
                                continue;
 
                        if (sock->service_name == NULL ||
-                               sock->service_name_len == 0)
+                           sock->service_name_len == 0)
                                        continue;
 
                        if (sock->service_name_len != sn_len)
                                continue;
 
                        if (sock->dsap == LLCP_SAP_SDP &&
-                                       sock->sk.sk_state == LLCP_LISTEN &&
-                                       !memcmp(sn, sock->service_name, sn_len)) {
+                           sock->sk.sk_state == LLCP_LISTEN &&
+                           !memcmp(sn, sock->service_name, sn_len)) {
                                pr_debug("Found service name at SAP %d\n",
-                                                               bound_sap);
+                                        bound_sap);
                                sock_hold(&sock->sk);
                                mutex_unlock(&local->socket_lock);
 
@@ -570,8 +587,7 @@ enqueue:
                goto fail;
        }
 
-       new_sk = nfc_llcp_sock_alloc(NULL, parent->sk_type,
-                                    GFP_ATOMIC);
+       new_sk = nfc_llcp_sock_alloc(NULL, parent->sk_type, GFP_ATOMIC);
        if (new_sk == NULL) {
                reason = LLCP_DM_REJ;
                release_sock(&sock->sk);
@@ -616,8 +632,39 @@ fail:
 
 }
 
+int nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock)
+{
+       int nr_frames = 0;
+       struct nfc_llcp_local *local = sock->local;
+
+       pr_debug("Remote ready %d tx queue len %d remote rw %d",
+                sock->remote_ready, skb_queue_len(&sock->tx_pending_queue),
+                local->remote_rw);
+
+       /* Try to queue some I frames for transmission */
+       while (sock->remote_ready &&
+              skb_queue_len(&sock->tx_pending_queue) < local->remote_rw) {
+               struct sk_buff *pdu, *pending_pdu;
+
+               pdu = skb_dequeue(&sock->tx_queue);
+               if (pdu == NULL)
+                       break;
+
+               /* Update N(S)/N(R) */
+               nfc_llcp_set_nrns(sock, pdu);
+
+               pending_pdu = skb_clone(pdu, GFP_KERNEL);
+
+               skb_queue_tail(&local->tx_queue, pdu);
+               skb_queue_tail(&sock->tx_pending_queue, pending_pdu);
+               nr_frames++;
+       }
+
+       return nr_frames;
+}
+
 static void nfc_llcp_recv_hdlc(struct nfc_llcp_local *local,
-                               struct sk_buff *skb)
+                              struct sk_buff *skb)
 {
        struct nfc_llcp_sock *llcp_sock;
        struct sock *sk;
@@ -644,15 +691,15 @@ static void nfc_llcp_recv_hdlc(struct nfc_llcp_local *local,
                nfc_llcp_sock_put(llcp_sock);
        }
 
-       if (ns == llcp_sock->recv_n)
-               llcp_sock->recv_n = (llcp_sock->recv_n + 1) % 16;
-       else
-               pr_err("Received out of sequence I PDU\n");
-
        /* Pass the payload upstream */
        if (ptype == LLCP_PDU_I) {
                pr_debug("I frame, queueing on %p\n", &llcp_sock->sk);
 
+               if (ns == llcp_sock->recv_n)
+                       llcp_sock->recv_n = (llcp_sock->recv_n + 1) % 16;
+               else
+                       pr_err("Received out of sequence I PDU\n");
+
                skb_pull(skb, LLCP_HEADER_SIZE + LLCP_SEQUENCE_SIZE);
                if (sock_queue_rcv_skb(&llcp_sock->sk, skb)) {
                        pr_err("receive queue is full\n");
@@ -673,30 +720,20 @@ static void nfc_llcp_recv_hdlc(struct nfc_llcp_local *local,
                        }
        }
 
-       /* Queue some I frames for transmission */
-       while (llcp_sock->remote_ready &&
-               skb_queue_len(&llcp_sock->tx_pending_queue) <= local->remote_rw) {
-               struct sk_buff *pdu, *pending_pdu;
-
-               pdu = skb_dequeue(&llcp_sock->tx_queue);
-               if (pdu == NULL)
-                       break;
-
-               /* Update N(S)/N(R) */
-               nfc_llcp_set_nrns(llcp_sock, pdu);
+       if (ptype == LLCP_PDU_RR)
+               llcp_sock->remote_ready = true;
+       else if (ptype == LLCP_PDU_RNR)
+               llcp_sock->remote_ready = false;
 
-               pending_pdu = skb_clone(pdu, GFP_KERNEL);
-
-               skb_queue_tail(&local->tx_queue, pdu);
-               skb_queue_tail(&llcp_sock->tx_pending_queue, pending_pdu);
-       }
+       if (nfc_llcp_queue_i_frames(llcp_sock) == 0)
+               nfc_llcp_send_rr(llcp_sock);
 
        release_sock(sk);
        nfc_llcp_sock_put(llcp_sock);
 }
 
 static void nfc_llcp_recv_disc(struct nfc_llcp_local *local,
-                               struct sk_buff *skb)
+                              struct sk_buff *skb)
 {
        struct nfc_llcp_sock *llcp_sock;
        struct sock *sk;
@@ -718,7 +755,6 @@ static void nfc_llcp_recv_disc(struct nfc_llcp_local *local,
                nfc_llcp_sock_put(llcp_sock);
        }
 
-
        if (sk->sk_state == LLCP_CONNECTED) {
                nfc_put_device(local->dev);
                sk->sk_state = LLCP_CLOSED;
@@ -731,13 +767,11 @@ static void nfc_llcp_recv_disc(struct nfc_llcp_local *local,
        nfc_llcp_sock_put(llcp_sock);
 }
 
-static void nfc_llcp_recv_cc(struct nfc_llcp_local *local,
-                               struct sk_buff *skb)
+static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, struct sk_buff *skb)
 {
        struct nfc_llcp_sock *llcp_sock;
        u8 dsap, ssap;
 
-
        dsap = nfc_llcp_dsap(skb);
        ssap = nfc_llcp_ssap(skb);
 
@@ -756,7 +790,7 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local,
        llcp_sock->dsap = ssap;
 
        nfc_llcp_parse_tlv(local, &skb->data[LLCP_HEADER_SIZE],
-                               skb->len - LLCP_HEADER_SIZE);
+                          skb->len - LLCP_HEADER_SIZE);
 
        nfc_llcp_sock_put(llcp_sock);
 }
@@ -764,7 +798,7 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local,
 static void nfc_llcp_rx_work(struct work_struct *work)
 {
        struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local,
-                                                               rx_work);
+                                                   rx_work);
        u8 dsap, ssap, ptype;
        struct sk_buff *skb;
 
@@ -802,6 +836,7 @@ static void nfc_llcp_rx_work(struct work_struct *work)
 
        case LLCP_PDU_I:
        case LLCP_PDU_RR:
+       case LLCP_PDU_RNR:
                pr_debug("I frame\n");
                nfc_llcp_recv_hdlc(local, skb);
                break;
@@ -821,7 +856,7 @@ void nfc_llcp_recv(void *data, struct sk_buff *skb, int err)
 
        pr_debug("Received an LLCP PDU\n");
        if (err < 0) {
-               pr_err("err %d", err);
+               pr_err("err %d\n", err);
                return;
        }
 
@@ -840,6 +875,8 @@ void nfc_llcp_mac_is_down(struct nfc_dev *dev)
        if (local == NULL)
                return;
 
+       nfc_llcp_clear_sdp(local);
+
        /* Close and purge all existing sockets */
        nfc_llcp_socket_release(local);
 }
@@ -865,7 +902,7 @@ void nfc_llcp_mac_is_up(struct nfc_dev *dev, u32 target_idx,
                queue_work(local->tx_wq, &local->tx_work);
        } else {
                mod_timer(&local->link_timer,
-                       jiffies + msecs_to_jiffies(local->remote_lto));
+                         jiffies + msecs_to_jiffies(local->remote_lto));
        }
 }
 
@@ -891,8 +928,10 @@ int nfc_llcp_register_device(struct nfc_dev *ndev)
        skb_queue_head_init(&local->tx_queue);
        INIT_WORK(&local->tx_work, nfc_llcp_tx_work);
        snprintf(name, sizeof(name), "%s_llcp_tx_wq", dev_name(dev));
-       local->tx_wq = alloc_workqueue(name,
-                       WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
+       local->tx_wq =
+               alloc_workqueue(name,
+                               WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM,
+                               1);
        if (local->tx_wq == NULL) {
                err = -ENOMEM;
                goto err_local;
@@ -901,8 +940,10 @@ int nfc_llcp_register_device(struct nfc_dev *ndev)
        local->rx_pending = NULL;
        INIT_WORK(&local->rx_work, nfc_llcp_rx_work);
        snprintf(name, sizeof(name), "%s_llcp_rx_wq", dev_name(dev));
-       local->rx_wq = alloc_workqueue(name,
-                       WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
+       local->rx_wq =
+               alloc_workqueue(name,
+                               WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM,
+                               1);
        if (local->rx_wq == NULL) {
                err = -ENOMEM;
                goto err_tx_wq;
@@ -910,8 +951,10 @@ int nfc_llcp_register_device(struct nfc_dev *ndev)
 
        INIT_WORK(&local->timeout_work, nfc_llcp_timeout_work);
        snprintf(name, sizeof(name), "%s_llcp_timeout_wq", dev_name(dev));
-       local->timeout_wq = alloc_workqueue(name,
-                       WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
+       local->timeout_wq =
+               alloc_workqueue(name,
+                               WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM,
+                               1);
        if (local->timeout_wq == NULL) {
                err = -ENOMEM;
                goto err_rx_wq;
index 0ad2e3361584a074ab2c0a09b489d1056889f247..50680ce5ae4396435552936f22cf3a8d17e26a25 100644 (file)
@@ -28,6 +28,10 @@ enum llcp_state {
 #define LLCP_DEFAULT_RW  1
 #define LLCP_DEFAULT_MIU 128
 
+#define LLCP_MAX_LTO  0xff
+#define LLCP_MAX_RW   15
+#define LLCP_MAX_MIUX 0x7ff
+
 #define LLCP_WKS_NUM_SAP   16
 #define LLCP_SDP_NUM_SAP   16
 #define LLCP_LOCAL_NUM_SAP 32
@@ -162,9 +166,10 @@ struct nfc_llcp_sock {
 
 struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev);
 u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local,
-                               struct nfc_llcp_sock *sock);
+                        struct nfc_llcp_sock *sock);
 u8 nfc_llcp_get_local_ssap(struct nfc_llcp_local *local);
 void nfc_llcp_put_ssap(struct nfc_llcp_local *local, u8 ssap);
+int nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock);
 
 /* Sock API */
 struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp);
@@ -175,7 +180,7 @@ struct sock *nfc_llcp_accept_dequeue(struct sock *sk, struct socket *newsock);
 
 /* TLV API */
 int nfc_llcp_parse_tlv(struct nfc_llcp_local *local,
-                       u8 *tlv_array, u16 tlv_array_len);
+                      u8 *tlv_array, u16 tlv_array_len);
 
 /* Commands API */
 void nfc_llcp_recv(void *data, struct sk_buff *skb, int err);
@@ -187,6 +192,9 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock);
 int nfc_llcp_send_cc(struct nfc_llcp_sock *sock);
 int nfc_llcp_send_dm(struct nfc_llcp_local *local, u8 ssap, u8 dsap, u8 reason);
 int nfc_llcp_send_disconnect(struct nfc_llcp_sock *sock);
+int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
+                         struct msghdr *msg, size_t len);
+int nfc_llcp_send_rr(struct nfc_llcp_sock *sock);
 
 /* Socket API */
 int __init nfc_llcp_sock_init(void);
index f738ccd535f1c984f3a741ac32c43acc6bc3c7c5..c13e02ebdef9b08e5c995f5cbb5a671db42d8e3c 100644 (file)
@@ -78,9 +78,11 @@ static int llcp_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
        llcp_sock->local = local;
        llcp_sock->nfc_protocol = llcp_addr.nfc_protocol;
        llcp_sock->service_name_len = min_t(unsigned int,
-                       llcp_addr.service_name_len, NFC_LLCP_MAX_SERVICE_NAME);
+                                           llcp_addr.service_name_len,
+                                           NFC_LLCP_MAX_SERVICE_NAME);
        llcp_sock->service_name = kmemdup(llcp_addr.service_name,
-                               llcp_sock->service_name_len, GFP_KERNEL);
+                                         llcp_sock->service_name_len,
+                                         GFP_KERNEL);
 
        llcp_sock->ssap = nfc_llcp_get_sdp_ssap(local, llcp_sock);
        if (llcp_sock->ssap == LLCP_MAX_SAP)
@@ -110,7 +112,7 @@ static int llcp_sock_listen(struct socket *sock, int backlog)
        lock_sock(sk);
 
        if ((sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM)
-                       || sk->sk_state != LLCP_BOUND) {
+           || sk->sk_state != LLCP_BOUND) {
                ret = -EBADFD;
                goto error;
        }
@@ -149,13 +151,13 @@ void nfc_llcp_accept_enqueue(struct sock *parent, struct sock *sk)
        sock_hold(sk);
 
        list_add_tail(&llcp_sock->accept_queue,
-                       &llcp_sock_parent->accept_queue);
+                     &llcp_sock_parent->accept_queue);
        llcp_sock->parent = parent;
        sk_acceptq_added(parent);
 }
 
 struct sock *nfc_llcp_accept_dequeue(struct sock *parent,
-                                       struct socket *newsock)
+                                    struct socket *newsock)
 {
        struct nfc_llcp_sock *lsk, *n, *llcp_parent;
        struct sock *sk;
@@ -163,7 +165,7 @@ struct sock *nfc_llcp_accept_dequeue(struct sock *parent,
        llcp_parent = nfc_llcp_sock(parent);
 
        list_for_each_entry_safe(lsk, n, &llcp_parent->accept_queue,
-                                                       accept_queue) {
+                                accept_queue) {
                sk = &lsk->sk;
                lock_sock(sk);
 
@@ -192,7 +194,7 @@ struct sock *nfc_llcp_accept_dequeue(struct sock *parent,
 }
 
 static int llcp_sock_accept(struct socket *sock, struct socket *newsock,
-                                                               int flags)
+                           int flags)
 {
        DECLARE_WAITQUEUE(wait, current);
        struct sock *sk = sock->sk, *new_sk;
@@ -248,7 +250,7 @@ error:
 static int llcp_sock_getname(struct socket *sock, struct sockaddr *addr,
                             int *len, int peer)
 {
-       struct sockaddr_nfc_llcp *llcp_addr = (struct sockaddr_nfc_llcp *) addr;
+       struct sockaddr_nfc_llcp *llcp_addr = (struct sockaddr_nfc_llcp *)addr;
        struct sock *sk = sock->sk;
        struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
 
@@ -262,7 +264,7 @@ static int llcp_sock_getname(struct socket *sock, struct sockaddr *addr,
        llcp_addr->ssap = llcp_sock->ssap;
        llcp_addr->service_name_len = llcp_sock->service_name_len;
        memcpy(llcp_addr->service_name, llcp_sock->service_name,
-                                       llcp_addr->service_name_len);
+              llcp_addr->service_name_len);
 
        return 0;
 }
@@ -275,7 +277,7 @@ static inline unsigned int llcp_accept_poll(struct sock *parent)
        parent_sock = nfc_llcp_sock(parent);
 
        list_for_each_entry_safe(llcp_sock, n, &parent_sock->accept_queue,
-                                                               accept_queue) {
+                                accept_queue) {
                sk = &llcp_sock->sk;
 
                if (sk->sk_state == LLCP_CONNECTED)
@@ -286,7 +288,7 @@ static inline unsigned int llcp_accept_poll(struct sock *parent)
 }
 
 static unsigned int llcp_sock_poll(struct file *file, struct socket *sock,
-                                                       poll_table *wait)
+                                  poll_table *wait)
 {
        struct sock *sk = sock->sk;
        unsigned int mask = 0;
@@ -315,6 +317,7 @@ static int llcp_sock_release(struct socket *sock)
        struct sock *sk = sock->sk;
        struct nfc_llcp_local *local;
        struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
+       int err = 0;
 
        if (!sk)
                return 0;
@@ -322,25 +325,17 @@ static int llcp_sock_release(struct socket *sock)
        pr_debug("%p\n", sk);
 
        local = llcp_sock->local;
-       if (local == NULL)
-               return -ENODEV;
+       if (local == NULL) {
+               err = -ENODEV;
+               goto out;
+       }
 
        mutex_lock(&local->socket_lock);
 
-       if (llcp_sock == local->sockets[llcp_sock->ssap]) {
+       if (llcp_sock == local->sockets[llcp_sock->ssap])
                local->sockets[llcp_sock->ssap] = NULL;
-       } else {
-               struct nfc_llcp_sock *parent, *s, *n;
-
-               parent = local->sockets[llcp_sock->ssap];
-
-               list_for_each_entry_safe(s, n, &parent->list, list)
-                       if (llcp_sock == s) {
-                               list_del(&s->list);
-                               break;
-                       }
-
-       }
+       else
+               list_del_init(&llcp_sock->list);
 
        mutex_unlock(&local->socket_lock);
 
@@ -355,7 +350,7 @@ static int llcp_sock_release(struct socket *sock)
                struct sock *accept_sk;
 
                list_for_each_entry_safe(lsk, n, &llcp_sock->accept_queue,
-                                                               accept_queue) {
+                                        accept_queue) {
                        accept_sk = &lsk->sk;
                        lock_sock(accept_sk);
 
@@ -364,31 +359,27 @@ static int llcp_sock_release(struct socket *sock)
 
                        release_sock(accept_sk);
 
-                       sock_set_flag(sk, SOCK_DEAD);
                        sock_orphan(accept_sk);
-                       sock_put(accept_sk);
                }
        }
 
        /* Freeing the SAP */
        if ((sk->sk_state == LLCP_CONNECTED
-                       && llcp_sock->ssap > LLCP_LOCAL_SAP_OFFSET) ||
-           sk->sk_state == LLCP_BOUND ||
-           sk->sk_state == LLCP_LISTEN)
+            && llcp_sock->ssap > LLCP_LOCAL_SAP_OFFSET) ||
+           sk->sk_state == LLCP_BOUND || sk->sk_state == LLCP_LISTEN)
                nfc_llcp_put_ssap(llcp_sock->local, llcp_sock->ssap);
 
-       sock_set_flag(sk, SOCK_DEAD);
-
        release_sock(sk);
 
+out:
        sock_orphan(sk);
        sock_put(sk);
 
-       return 0;
+       return err;
 }
 
 static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr,
-                                                       int len, int flags)
+                            int len, int flags)
 {
        struct sock *sk = sock->sk;
        struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
@@ -400,7 +391,7 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr,
        pr_debug("sock %p sk %p flags 0x%x\n", sock, sk, flags);
 
        if (!addr || len < sizeof(struct sockaddr_nfc) ||
-                       addr->sa_family != AF_NFC) {
+           addr->sa_family != AF_NFC) {
                pr_err("Invalid socket\n");
                return -EINVAL;
        }
@@ -411,7 +402,7 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr,
        }
 
        pr_debug("addr dev_idx=%u target_idx=%u protocol=%u\n", addr->dev_idx,
-                                       addr->target_idx, addr->nfc_protocol);
+                addr->target_idx, addr->nfc_protocol);
 
        lock_sock(sk);
 
@@ -441,7 +432,7 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr,
        device_unlock(&dev->dev);
 
        if (local->rf_mode == NFC_RF_INITIATOR &&
-                       addr->target_idx != local->target_idx) {
+           addr->target_idx != local->target_idx) {
                ret = -ENOLINK;
                goto put_dev;
        }
@@ -459,9 +450,11 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr,
                llcp_sock->dsap = LLCP_SAP_SDP;
        llcp_sock->nfc_protocol = addr->nfc_protocol;
        llcp_sock->service_name_len = min_t(unsigned int,
-                       addr->service_name_len, NFC_LLCP_MAX_SERVICE_NAME);
+                                           addr->service_name_len,
+                                           NFC_LLCP_MAX_SERVICE_NAME);
        llcp_sock->service_name = kmemdup(addr->service_name,
-                                llcp_sock->service_name_len, GFP_KERNEL);
+                                         llcp_sock->service_name_len,
+                                         GFP_KERNEL);
 
        local->sockets[llcp_sock->ssap] = llcp_sock;
 
@@ -482,6 +475,34 @@ error:
        return ret;
 }
 
+static int llcp_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
+                            struct msghdr *msg, size_t len)
+{
+       struct sock *sk = sock->sk;
+       struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
+       int ret;
+
+       pr_debug("sock %p sk %p", sock, sk);
+
+       ret = sock_error(sk);
+       if (ret)
+               return ret;
+
+       if (msg->msg_flags & MSG_OOB)
+               return -EOPNOTSUPP;
+
+       lock_sock(sk);
+
+       if (sk->sk_state != LLCP_CONNECTED) {
+               release_sock(sk);
+               return -ENOTCONN;
+       }
+
+       release_sock(sk);
+
+       return nfc_llcp_send_i_frame(llcp_sock, msg, len);
+}
+
 static int llcp_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
                             struct msghdr *msg, size_t len, int flags)
 {
@@ -496,7 +517,7 @@ static int llcp_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
        lock_sock(sk);
 
        if (sk->sk_state == LLCP_CLOSED &&
-                       skb_queue_empty(&sk->sk_receive_queue)) {
+           skb_queue_empty(&sk->sk_receive_queue)) {
                release_sock(sk);
                return 0;
        }
@@ -509,7 +530,7 @@ static int llcp_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
        skb = skb_recv_datagram(sk, flags, noblock, &err);
        if (!skb) {
                pr_err("Recv datagram failed state %d %d %d",
-                               sk->sk_state, err, sock_error(sk));
+                      sk->sk_state, err, sock_error(sk));
 
                if (sk->sk_shutdown & RCV_SHUTDOWN)
                        return 0;
@@ -517,7 +538,7 @@ static int llcp_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
                return err;
        }
 
-       rlen   = skb->len;              /* real length of skb */
+       rlen = skb->len;                /* real length of skb */
        copied = min_t(unsigned int, rlen, len);
 
        cskb = skb;
@@ -567,7 +588,7 @@ static const struct proto_ops llcp_sock_ops = {
        .shutdown       = sock_no_shutdown,
        .setsockopt     = sock_no_setsockopt,
        .getsockopt     = sock_no_getsockopt,
-       .sendmsg        = sock_no_sendmsg,
+       .sendmsg        = llcp_sock_sendmsg,
        .recvmsg        = llcp_sock_recvmsg,
        .mmap           = sock_no_mmap,
 };
@@ -627,6 +648,8 @@ struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp)
 
 void nfc_llcp_sock_free(struct nfc_llcp_sock *sock)
 {
+       struct nfc_llcp_local *local = sock->local;
+
        kfree(sock->service_name);
 
        skb_queue_purge(&sock->tx_queue);
@@ -635,11 +658,16 @@ void nfc_llcp_sock_free(struct nfc_llcp_sock *sock)
 
        list_del_init(&sock->accept_queue);
 
+       if (local != NULL && sock == local->sockets[sock->ssap])
+               local->sockets[sock->ssap] = NULL;
+       else
+               list_del_init(&sock->list);
+
        sock->parent = NULL;
 }
 
 static int llcp_sock_create(struct net *net, struct socket *sock,
-                               const struct nfc_protocol *nfc_proto)
+                           const struct nfc_protocol *nfc_proto)
 {
        struct sock *sk;
 
index a47e90c7d9d139067439ecbc117e29a9a1a837ba..9ec065bb9ee1e78b96321a8f2f1e5c6827dd15bc 100644 (file)
@@ -66,9 +66,8 @@ static void nci_req_cancel(struct nci_dev *ndev, int err)
 
 /* Execute request and wait for completion. */
 static int __nci_request(struct nci_dev *ndev,
-       void (*req)(struct nci_dev *ndev, unsigned long opt),
-       unsigned long opt,
-       __u32 timeout)
+                        void (*req)(struct nci_dev *ndev, unsigned long opt),
+                        unsigned long opt, __u32 timeout)
 {
        int rc = 0;
        long completion_rc;
@@ -77,9 +76,9 @@ static int __nci_request(struct nci_dev *ndev,
 
        init_completion(&ndev->req_completion);
        req(ndev, opt);
-       completion_rc = wait_for_completion_interruptible_timeout(
-                                                       &ndev->req_completion,
-                                                       timeout);
+       completion_rc =
+               wait_for_completion_interruptible_timeout(&ndev->req_completion,
+                                                         timeout);
 
        pr_debug("wait_for_completion return %ld\n", completion_rc);
 
@@ -110,8 +109,9 @@ static int __nci_request(struct nci_dev *ndev,
 }
 
 static inline int nci_request(struct nci_dev *ndev,
-               void (*req)(struct nci_dev *ndev, unsigned long opt),
-               unsigned long opt, __u32 timeout)
+                             void (*req)(struct nci_dev *ndev,
+                                         unsigned long opt),
+                             unsigned long opt, __u32 timeout)
 {
        int rc;
 
@@ -152,14 +152,14 @@ static void nci_init_complete_req(struct nci_dev *ndev, unsigned long opt)
        /* by default mapping is set to NCI_RF_INTERFACE_FRAME */
        for (i = 0; i < ndev->num_supported_rf_interfaces; i++) {
                if (ndev->supported_rf_interfaces[i] ==
-                       NCI_RF_INTERFACE_ISO_DEP) {
+                   NCI_RF_INTERFACE_ISO_DEP) {
                        cfg[*num].rf_protocol = NCI_RF_PROTOCOL_ISO_DEP;
                        cfg[*num].mode = NCI_DISC_MAP_MODE_POLL |
                                NCI_DISC_MAP_MODE_LISTEN;
                        cfg[*num].rf_interface = NCI_RF_INTERFACE_ISO_DEP;
                        (*num)++;
                } else if (ndev->supported_rf_interfaces[i] ==
-                       NCI_RF_INTERFACE_NFC_DEP) {
+                          NCI_RF_INTERFACE_NFC_DEP) {
                        cfg[*num].rf_protocol = NCI_RF_PROTOCOL_NFC_DEP;
                        cfg[*num].mode = NCI_DISC_MAP_MODE_POLL |
                                NCI_DISC_MAP_MODE_LISTEN;
@@ -172,8 +172,7 @@ static void nci_init_complete_req(struct nci_dev *ndev, unsigned long opt)
        }
 
        nci_send_cmd(ndev, NCI_OP_RF_DISCOVER_MAP_CMD,
-               (1 + ((*num)*sizeof(struct disc_map_config))),
-               &cmd);
+                    (1 + ((*num) * sizeof(struct disc_map_config))), &cmd);
 }
 
 static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt)
@@ -184,36 +183,36 @@ static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt)
        cmd.num_disc_configs = 0;
 
        if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) &&
-               (protocols & NFC_PROTO_JEWEL_MASK
-               || protocols & NFC_PROTO_MIFARE_MASK
-               || protocols & NFC_PROTO_ISO14443_MASK
-               || protocols & NFC_PROTO_NFC_DEP_MASK)) {
+           (protocols & NFC_PROTO_JEWEL_MASK
+            || protocols & NFC_PROTO_MIFARE_MASK
+            || protocols & NFC_PROTO_ISO14443_MASK
+            || protocols & NFC_PROTO_NFC_DEP_MASK)) {
                cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode =
-               NCI_NFC_A_PASSIVE_POLL_MODE;
+                       NCI_NFC_A_PASSIVE_POLL_MODE;
                cmd.disc_configs[cmd.num_disc_configs].frequency = 1;
                cmd.num_disc_configs++;
        }
 
        if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) &&
-               (protocols & NFC_PROTO_ISO14443_MASK)) {
+           (protocols & NFC_PROTO_ISO14443_MASK)) {
                cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode =
-               NCI_NFC_B_PASSIVE_POLL_MODE;
+                       NCI_NFC_B_PASSIVE_POLL_MODE;
                cmd.disc_configs[cmd.num_disc_configs].frequency = 1;
                cmd.num_disc_configs++;
        }
 
        if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) &&
-               (protocols & NFC_PROTO_FELICA_MASK
-               || protocols & NFC_PROTO_NFC_DEP_MASK)) {
+           (protocols & NFC_PROTO_FELICA_MASK
+            || protocols & NFC_PROTO_NFC_DEP_MASK)) {
                cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode =
-               NCI_NFC_F_PASSIVE_POLL_MODE;
+                       NCI_NFC_F_PASSIVE_POLL_MODE;
                cmd.disc_configs[cmd.num_disc_configs].frequency = 1;
                cmd.num_disc_configs++;
        }
 
        nci_send_cmd(ndev, NCI_OP_RF_DISCOVER_CMD,
-               (1 + (cmd.num_disc_configs*sizeof(struct disc_config))),
-               &cmd);
+                    (1 + (cmd.num_disc_configs * sizeof(struct disc_config))),
+                    &cmd);
 }
 
 struct nci_rf_discover_select_param {
@@ -224,7 +223,7 @@ struct nci_rf_discover_select_param {
 static void nci_rf_discover_select_req(struct nci_dev *ndev, unsigned long opt)
 {
        struct nci_rf_discover_select_param *param =
-                               (struct nci_rf_discover_select_param *)opt;
+               (struct nci_rf_discover_select_param *)opt;
        struct nci_rf_discover_select_cmd cmd;
 
        cmd.rf_discovery_id = param->rf_discovery_id;
@@ -245,8 +244,7 @@ static void nci_rf_discover_select_req(struct nci_dev *ndev, unsigned long opt)
        }
 
        nci_send_cmd(ndev, NCI_OP_RF_DISCOVER_SELECT_CMD,
-                       sizeof(struct nci_rf_discover_select_cmd),
-                       &cmd);
+                    sizeof(struct nci_rf_discover_select_cmd), &cmd);
 }
 
 static void nci_rf_deactivate_req(struct nci_dev *ndev, unsigned long opt)
@@ -256,8 +254,7 @@ static void nci_rf_deactivate_req(struct nci_dev *ndev, unsigned long opt)
        cmd.type = NCI_DEACTIVATE_TYPE_IDLE_MODE;
 
        nci_send_cmd(ndev, NCI_OP_RF_DEACTIVATE_CMD,
-                       sizeof(struct nci_rf_deactivate_cmd),
-                       &cmd);
+                    sizeof(struct nci_rf_deactivate_cmd), &cmd);
 }
 
 static int nci_open_device(struct nci_dev *ndev)
@@ -281,16 +278,16 @@ static int nci_open_device(struct nci_dev *ndev)
        set_bit(NCI_INIT, &ndev->flags);
 
        rc = __nci_request(ndev, nci_reset_req, 0,
-                               msecs_to_jiffies(NCI_RESET_TIMEOUT));
+                          msecs_to_jiffies(NCI_RESET_TIMEOUT));
 
        if (!rc) {
                rc = __nci_request(ndev, nci_init_req, 0,
-                               msecs_to_jiffies(NCI_INIT_TIMEOUT));
+                                  msecs_to_jiffies(NCI_INIT_TIMEOUT));
        }
 
        if (!rc) {
                rc = __nci_request(ndev, nci_init_complete_req, 0,
-                               msecs_to_jiffies(NCI_INIT_TIMEOUT));
+                                  msecs_to_jiffies(NCI_INIT_TIMEOUT));
        }
 
        clear_bit(NCI_INIT, &ndev->flags);
@@ -340,7 +337,7 @@ static int nci_close_device(struct nci_dev *ndev)
 
        set_bit(NCI_INIT, &ndev->flags);
        __nci_request(ndev, nci_reset_req, 0,
-                               msecs_to_jiffies(NCI_RESET_TIMEOUT));
+                     msecs_to_jiffies(NCI_RESET_TIMEOUT));
        clear_bit(NCI_INIT, &ndev->flags);
 
        /* Flush cmd wq */
@@ -396,7 +393,7 @@ static int nci_start_poll(struct nfc_dev *nfc_dev, __u32 protocols)
        int rc;
 
        if ((atomic_read(&ndev->state) == NCI_DISCOVERY) ||
-               (atomic_read(&ndev->state) == NCI_W4_ALL_DISCOVERIES)) {
+           (atomic_read(&ndev->state) == NCI_W4_ALL_DISCOVERIES)) {
                pr_err("unable to start poll, since poll is already active\n");
                return -EBUSY;
        }
@@ -407,17 +404,17 @@ static int nci_start_poll(struct nfc_dev *nfc_dev, __u32 protocols)
        }
 
        if ((atomic_read(&ndev->state) == NCI_W4_HOST_SELECT) ||
-               (atomic_read(&ndev->state) == NCI_POLL_ACTIVE)) {
+           (atomic_read(&ndev->state) == NCI_POLL_ACTIVE)) {
                pr_debug("target active or w4 select, implicitly deactivate\n");
 
                rc = nci_request(ndev, nci_rf_deactivate_req, 0,
-                       msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT));
+                                msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT));
                if (rc)
                        return -EBUSY;
        }
 
        rc = nci_request(ndev, nci_rf_discover_req, protocols,
-               msecs_to_jiffies(NCI_RF_DISC_TIMEOUT));
+                        msecs_to_jiffies(NCI_RF_DISC_TIMEOUT));
 
        if (!rc)
                ndev->poll_prots = protocols;
@@ -430,17 +427,17 @@ static void nci_stop_poll(struct nfc_dev *nfc_dev)
        struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
 
        if ((atomic_read(&ndev->state) != NCI_DISCOVERY) &&
-               (atomic_read(&ndev->state) != NCI_W4_ALL_DISCOVERIES)) {
+           (atomic_read(&ndev->state) != NCI_W4_ALL_DISCOVERIES)) {
                pr_err("unable to stop poll, since poll is not active\n");
                return;
        }
 
        nci_request(ndev, nci_rf_deactivate_req, 0,
-               msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT));
+                   msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT));
 }
 
 static int nci_activate_target(struct nfc_dev *nfc_dev, __u32 target_idx,
-                               __u32 protocol)
+                              __u32 protocol)
 {
        struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
        struct nci_rf_discover_select_param param;
@@ -451,7 +448,7 @@ static int nci_activate_target(struct nfc_dev *nfc_dev, __u32 target_idx,
        pr_debug("target_idx %d, protocol 0x%x\n", target_idx, protocol);
 
        if ((atomic_read(&ndev->state) != NCI_W4_HOST_SELECT) &&
-               (atomic_read(&ndev->state) != NCI_POLL_ACTIVE)) {
+           (atomic_read(&ndev->state) != NCI_POLL_ACTIVE)) {
                pr_err("there is no available target to activate\n");
                return -EINVAL;
        }
@@ -494,8 +491,8 @@ static int nci_activate_target(struct nfc_dev *nfc_dev, __u32 target_idx,
                        param.rf_protocol = NCI_RF_PROTOCOL_NFC_DEP;
 
                rc = nci_request(ndev, nci_rf_discover_select_req,
-                               (unsigned long)&param,
-                               msecs_to_jiffies(NCI_RF_DISC_SELECT_TIMEOUT));
+                                (unsigned long)&param,
+                                msecs_to_jiffies(NCI_RF_DISC_SELECT_TIMEOUT));
        }
 
        if (!rc)
@@ -519,14 +516,13 @@ static void nci_deactivate_target(struct nfc_dev *nfc_dev, __u32 target_idx)
 
        if (atomic_read(&ndev->state) == NCI_POLL_ACTIVE) {
                nci_request(ndev, nci_rf_deactivate_req, 0,
-                       msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT));
+                           msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT));
        }
 }
 
 static int nci_data_exchange(struct nfc_dev *nfc_dev, __u32 target_idx,
-                                               struct sk_buff *skb,
-                                               data_exchange_cb_t cb,
-                                               void *cb_context)
+                            struct sk_buff *skb,
+                            data_exchange_cb_t cb, void *cb_context)
 {
        struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
        int rc;
@@ -571,9 +567,8 @@ static struct nfc_ops nci_nfc_ops = {
  * @supported_protocols: NFC protocols supported by the device
  */
 struct nci_dev *nci_allocate_device(struct nci_ops *ops,
-                                       __u32 supported_protocols,
-                                       int tx_headroom,
-                                       int tx_tailroom)
+                                   __u32 supported_protocols,
+                                   int tx_headroom, int tx_tailroom)
 {
        struct nci_dev *ndev;
 
@@ -594,9 +589,9 @@ struct nci_dev *nci_allocate_device(struct nci_ops *ops,
        ndev->tx_tailroom = tx_tailroom;
 
        ndev->nfc_dev = nfc_allocate_device(&nci_nfc_ops,
-                                               supported_protocols,
-                                               tx_headroom + NCI_DATA_HDR_SIZE,
-                                               tx_tailroom);
+                                           supported_protocols,
+                                           tx_headroom + NCI_DATA_HDR_SIZE,
+                                           tx_tailroom);
        if (!ndev->nfc_dev)
                goto free_exit;
 
@@ -668,9 +663,9 @@ int nci_register_device(struct nci_dev *ndev)
        skb_queue_head_init(&ndev->tx_q);
 
        setup_timer(&ndev->cmd_timer, nci_cmd_timer,
-                       (unsigned long) ndev);
+                   (unsigned long) ndev);
        setup_timer(&ndev->data_timer, nci_data_timer,
-                       (unsigned long) ndev);
+                   (unsigned long) ndev);
 
        mutex_init(&ndev->req_lock);
 
@@ -719,7 +714,7 @@ int nci_recv_frame(struct sk_buff *skb)
        pr_debug("len %d\n", skb->len);
 
        if (!ndev || (!test_bit(NCI_UP, &ndev->flags)
-               && !test_bit(NCI_INIT, &ndev->flags))) {
+                     && !test_bit(NCI_INIT, &ndev->flags))) {
                kfree_skb(skb);
                return -ENXIO;
        }
@@ -799,7 +794,7 @@ static void nci_tx_work(struct work_struct *work)
 
                /* Check if data flow control is used */
                if (atomic_read(&ndev->credits_cnt) !=
-                               NCI_DATA_FLOW_CONTROL_NOT_USED)
+                   NCI_DATA_FLOW_CONTROL_NOT_USED)
                        atomic_dec(&ndev->credits_cnt);
 
                pr_debug("NCI TX: MT=data, PBF=%d, conn_id=%d, plen=%d\n",
@@ -810,7 +805,7 @@ static void nci_tx_work(struct work_struct *work)
                nci_send_frame(skb);
 
                mod_timer(&ndev->data_timer,
-                       jiffies + msecs_to_jiffies(NCI_DATA_TIMEOUT));
+                         jiffies + msecs_to_jiffies(NCI_DATA_TIMEOUT));
        }
 }
 
@@ -879,6 +874,6 @@ static void nci_cmd_work(struct work_struct *work)
                nci_send_frame(skb);
 
                mod_timer(&ndev->cmd_timer,
-                       jiffies + msecs_to_jiffies(NCI_CMD_TIMEOUT));
+                         jiffies + msecs_to_jiffies(NCI_CMD_TIMEOUT));
        }
 }
index 7880ae924d5e623db609df4feaf260ad2406535a..a0bc326308a56911c4f3b26358971df21ad65399 100644 (file)
@@ -35,8 +35,7 @@
 #include <linux/nfc.h>
 
 /* Complete data exchange transaction and forward skb to nfc core */
-void nci_data_exchange_complete(struct nci_dev *ndev,
-                               struct sk_buff *skb,
+void nci_data_exchange_complete(struct nci_dev *ndev, struct sk_buff *skb,
                                int err)
 {
        data_exchange_cb_t cb = ndev->data_exchange_cb;
@@ -67,9 +66,9 @@ void nci_data_exchange_complete(struct nci_dev *ndev,
 /* ----------------- NCI TX Data ----------------- */
 
 static inline void nci_push_data_hdr(struct nci_dev *ndev,
-                                       __u8 conn_id,
-                                       struct sk_buff *skb,
-                                       __u8 pbf)
+                                    __u8 conn_id,
+                                    struct sk_buff *skb,
+                                    __u8 pbf)
 {
        struct nci_data_hdr *hdr;
        int plen = skb->len;
@@ -86,8 +85,8 @@ static inline void nci_push_data_hdr(struct nci_dev *ndev,
 }
 
 static int nci_queue_tx_data_frags(struct nci_dev *ndev,
-                                       __u8 conn_id,
-                                       struct sk_buff *skb) {
+                                  __u8 conn_id,
+                                  struct sk_buff *skb) {
        int total_len = skb->len;
        unsigned char *data = skb->data;
        unsigned long flags;
@@ -105,8 +104,8 @@ static int nci_queue_tx_data_frags(struct nci_dev *ndev,
                        min_t(int, total_len, ndev->max_data_pkt_payload_size);
 
                skb_frag = nci_skb_alloc(ndev,
-                                       (NCI_DATA_HDR_SIZE + frag_len),
-                                       GFP_KERNEL);
+                                        (NCI_DATA_HDR_SIZE + frag_len),
+                                        GFP_KERNEL);
                if (skb_frag == NULL) {
                        rc = -ENOMEM;
                        goto free_exit;
@@ -118,7 +117,8 @@ static int nci_queue_tx_data_frags(struct nci_dev *ndev,
 
                /* second, set the header */
                nci_push_data_hdr(ndev, conn_id, skb_frag,
-               ((total_len == frag_len) ? (NCI_PBF_LAST) : (NCI_PBF_CONT)));
+                                 ((total_len == frag_len) ?
+                                  (NCI_PBF_LAST) : (NCI_PBF_CONT)));
 
                __skb_queue_tail(&frags_q, skb_frag);
 
@@ -186,8 +186,8 @@ exit:
 /* ----------------- NCI RX Data ----------------- */
 
 static void nci_add_rx_data_frag(struct nci_dev *ndev,
-                               struct sk_buff *skb,
-                               __u8 pbf)
+                                struct sk_buff *skb,
+                                __u8 pbf)
 {
        int reassembly_len;
        int err = 0;
@@ -211,8 +211,8 @@ static void nci_add_rx_data_frag(struct nci_dev *ndev,
 
                /* second, combine the two fragments */
                memcpy(skb_push(skb, reassembly_len),
-                               ndev->rx_data_reassembly->data,
-                               reassembly_len);
+                      ndev->rx_data_reassembly->data,
+                      reassembly_len);
 
                /* third, free old reassembly */
                kfree_skb(ndev->rx_data_reassembly);
index 03e7b4626a3e05772b3b13405ffe9ebc4fde54a8..2e3dee42196d064d0fdcf5ad7c6e4fe50945d57b 100644 (file)
@@ -40,7 +40,7 @@
 /* Handle NCI Notification packets */
 
 static void nci_core_conn_credits_ntf_packet(struct nci_dev *ndev,
-                                               struct sk_buff *skb)
+                                            struct sk_buff *skb)
 {
        struct nci_core_conn_credit_ntf *ntf = (void *) skb->data;
        int i;
@@ -62,7 +62,7 @@ static void nci_core_conn_credits_ntf_packet(struct nci_dev *ndev,
                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);
+                                  &ndev->credits_cnt);
                }
        }
 
@@ -72,7 +72,7 @@ static void nci_core_conn_credits_ntf_packet(struct nci_dev *ndev,
 }
 
 static void nci_core_generic_error_ntf_packet(struct nci_dev *ndev,
-                                               struct sk_buff *skb)
+                                             struct sk_buff *skb)
 {
        __u8 status = skb->data[0];
 
@@ -80,7 +80,7 @@ static void nci_core_generic_error_ntf_packet(struct nci_dev *ndev,
 
        if (atomic_read(&ndev->state) == NCI_W4_HOST_SELECT) {
                /* Activation failed, so complete the request
-               (the state remains the same) */
+                  (the state remains the same) */
                nci_req_complete(ndev, status);
        }
 }
@@ -101,7 +101,7 @@ static void nci_core_conn_intf_error_ntf_packet(struct nci_dev *ndev,
 
 static __u8 *nci_extract_rf_params_nfca_passive_poll(struct nci_dev *ndev,
                        struct rf_tech_specific_params_nfca_poll *nfca_poll,
-                       __u8 *data)
+                                                    __u8 *data)
 {
        nfca_poll->sens_res = __le16_to_cpu(*((__u16 *)data));
        data += 2;
@@ -128,7 +128,7 @@ static __u8 *nci_extract_rf_params_nfca_passive_poll(struct nci_dev *ndev,
 
 static __u8 *nci_extract_rf_params_nfcb_passive_poll(struct nci_dev *ndev,
                        struct rf_tech_specific_params_nfcb_poll *nfcb_poll,
-                       __u8 *data)
+                                                    __u8 *data)
 {
        nfcb_poll->sensb_res_len = *data++;
 
@@ -142,13 +142,13 @@ static __u8 *nci_extract_rf_params_nfcb_passive_poll(struct nci_dev *ndev,
 
 static __u8 *nci_extract_rf_params_nfcf_passive_poll(struct nci_dev *ndev,
                        struct rf_tech_specific_params_nfcf_poll *nfcf_poll,
-                       __u8 *data)
+                                                    __u8 *data)
 {
        nfcf_poll->bit_rate = *data++;
        nfcf_poll->sensf_res_len = *data++;
 
        pr_debug("bit_rate %d, sensf_res_len %d\n",
-               nfcf_poll->bit_rate, nfcf_poll->sensf_res_len);
+                nfcf_poll->bit_rate, nfcf_poll->sensf_res_len);
 
        memcpy(nfcf_poll->sensf_res, data, nfcf_poll->sensf_res_len);
        data += nfcf_poll->sensf_res_len;
@@ -189,7 +189,7 @@ static int nci_add_new_protocol(struct nci_dev *ndev,
                target->nfcid1_len = nfca_poll->nfcid1_len;
                if (target->nfcid1_len > 0) {
                        memcpy(target->nfcid1, nfca_poll->nfcid1,
-                               target->nfcid1_len);
+                              target->nfcid1_len);
                }
        } else if (rf_tech_and_mode == NCI_NFC_B_PASSIVE_POLL_MODE) {
                nfcb_poll = (struct rf_tech_specific_params_nfcb_poll *)params;
@@ -197,7 +197,7 @@ static int nci_add_new_protocol(struct nci_dev *ndev,
                target->sensb_res_len = nfcb_poll->sensb_res_len;
                if (target->sensb_res_len > 0) {
                        memcpy(target->sensb_res, nfcb_poll->sensb_res,
-                               target->sensb_res_len);
+                              target->sensb_res_len);
                }
        } else if (rf_tech_and_mode == NCI_NFC_F_PASSIVE_POLL_MODE) {
                nfcf_poll = (struct rf_tech_specific_params_nfcf_poll *)params;
@@ -205,7 +205,7 @@ static int nci_add_new_protocol(struct nci_dev *ndev,
                target->sensf_res_len = nfcf_poll->sensf_res_len;
                if (target->sensf_res_len > 0) {
                        memcpy(target->sensf_res, nfcf_poll->sensf_res,
-                               target->sensf_res_len);
+                              target->sensf_res_len);
                }
        } else {
                pr_err("unsupported rf_tech_and_mode 0x%x\n", rf_tech_and_mode);
@@ -220,7 +220,7 @@ static int nci_add_new_protocol(struct nci_dev *ndev,
 }
 
 static void nci_add_new_target(struct nci_dev *ndev,
-                               struct nci_rf_discover_ntf *ntf)
+                              struct nci_rf_discover_ntf *ntf)
 {
        struct nfc_target *target;
        int i, rc;
@@ -230,8 +230,8 @@ static void nci_add_new_target(struct nci_dev *ndev,
                if (target->idx == ntf->rf_discovery_id) {
                        /* This target already exists, add the new protocol */
                        nci_add_new_protocol(ndev, target, ntf->rf_protocol,
-                                               ntf->rf_tech_and_mode,
-                                               &ntf->rf_tech_specific_params);
+                                            ntf->rf_tech_and_mode,
+                                            &ntf->rf_tech_specific_params);
                        return;
                }
        }
@@ -245,27 +245,27 @@ static void nci_add_new_target(struct nci_dev *ndev,
        target = &ndev->targets[ndev->n_targets];
 
        rc = nci_add_new_protocol(ndev, target, ntf->rf_protocol,
-                                       ntf->rf_tech_and_mode,
-                                       &ntf->rf_tech_specific_params);
+                                 ntf->rf_tech_and_mode,
+                                 &ntf->rf_tech_specific_params);
        if (!rc) {
                target->idx = ntf->rf_discovery_id;
                ndev->n_targets++;
 
                pr_debug("target_idx %d, n_targets %d\n", target->idx,
-                               ndev->n_targets);
+                        ndev->n_targets);
        }
 }
 
 void nci_clear_target_list(struct nci_dev *ndev)
 {
        memset(ndev->targets, 0,
-               (sizeof(struct nfc_target)*NCI_MAX_DISCOVERED_TARGETS));
+              (sizeof(struct nfc_target)*NCI_MAX_DISCOVERED_TARGETS));
 
        ndev->n_targets = 0;
 }
 
 static void nci_rf_discover_ntf_packet(struct nci_dev *ndev,
-                                       struct sk_buff *skb)
+                                      struct sk_buff *skb)
 {
        struct nci_rf_discover_ntf ntf;
        __u8 *data = skb->data;
@@ -280,7 +280,7 @@ static void nci_rf_discover_ntf_packet(struct nci_dev *ndev,
        pr_debug("rf_protocol 0x%x\n", ntf.rf_protocol);
        pr_debug("rf_tech_and_mode 0x%x\n", ntf.rf_tech_and_mode);
        pr_debug("rf_tech_specific_params_len %d\n",
-                       ntf.rf_tech_specific_params_len);
+                ntf.rf_tech_specific_params_len);
 
        if (ntf.rf_tech_specific_params_len > 0) {
                switch (ntf.rf_tech_and_mode) {
@@ -318,7 +318,7 @@ static void nci_rf_discover_ntf_packet(struct nci_dev *ndev,
        } else {
                atomic_set(&ndev->state, NCI_W4_HOST_SELECT);
                nfc_targets_found(ndev->nfc_dev, ndev->targets,
-                                       ndev->n_targets);
+                                 ndev->n_targets);
        }
 }
 
@@ -335,20 +335,17 @@ static int nci_extract_activation_params_iso_dep(struct nci_dev *ndev,
                pr_debug("rats_res_len %d\n", nfca_poll->rats_res_len);
                if (nfca_poll->rats_res_len > 0) {
                        memcpy(nfca_poll->rats_res,
-                               data,
-                               nfca_poll->rats_res_len);
+                              data, nfca_poll->rats_res_len);
                }
                break;
 
        case NCI_NFC_B_PASSIVE_POLL_MODE:
                nfcb_poll = &ntf->activation_params.nfcb_poll_iso_dep;
                nfcb_poll->attrib_res_len = *data++;
-               pr_debug("attrib_res_len %d\n",
-                       nfcb_poll->attrib_res_len);
+               pr_debug("attrib_res_len %d\n", nfcb_poll->attrib_res_len);
                if (nfcb_poll->attrib_res_len > 0) {
                        memcpy(nfcb_poll->attrib_res,
-                               data,
-                               nfcb_poll->attrib_res_len);
+                              data, nfcb_poll->attrib_res_len);
                }
                break;
 
@@ -362,7 +359,7 @@ static int nci_extract_activation_params_iso_dep(struct nci_dev *ndev,
 }
 
 static void nci_target_auto_activated(struct nci_dev *ndev,
-                                       struct nci_rf_intf_activated_ntf *ntf)
+                                     struct nci_rf_intf_activated_ntf *ntf)
 {
        struct nfc_target *target;
        int rc;
@@ -370,8 +367,8 @@ static void nci_target_auto_activated(struct nci_dev *ndev,
        target = &ndev->targets[ndev->n_targets];
 
        rc = nci_add_new_protocol(ndev, target, ntf->rf_protocol,
-                                       ntf->activation_rf_tech_and_mode,
-                                       &ntf->rf_tech_specific_params);
+                                 ntf->activation_rf_tech_and_mode,
+                                 &ntf->rf_tech_specific_params);
        if (rc)
                return;
 
@@ -384,7 +381,7 @@ static void nci_target_auto_activated(struct nci_dev *ndev,
 }
 
 static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
-                                               struct sk_buff *skb)
+                                            struct sk_buff *skb)
 {
        struct nci_rf_intf_activated_ntf ntf;
        __u8 *data = skb->data;
@@ -405,7 +402,8 @@ static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
                 ntf.activation_rf_tech_and_mode);
        pr_debug("max_data_pkt_payload_size 0x%x\n",
                 ntf.max_data_pkt_payload_size);
-       pr_debug("initial_num_credits 0x%x\n", ntf.initial_num_credits);
+       pr_debug("initial_num_credits 0x%x\n",
+                ntf.initial_num_credits);
        pr_debug("rf_tech_specific_params_len %d\n",
                 ntf.rf_tech_specific_params_len);
 
@@ -441,18 +439,15 @@ static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
 
        pr_debug("data_exch_rf_tech_and_mode 0x%x\n",
                 ntf.data_exch_rf_tech_and_mode);
-       pr_debug("data_exch_tx_bit_rate 0x%x\n",
-                ntf.data_exch_tx_bit_rate);
-       pr_debug("data_exch_rx_bit_rate 0x%x\n",
-                ntf.data_exch_rx_bit_rate);
-       pr_debug("activation_params_len %d\n",
-                ntf.activation_params_len);
+       pr_debug("data_exch_tx_bit_rate 0x%x\n", ntf.data_exch_tx_bit_rate);
+       pr_debug("data_exch_rx_bit_rate 0x%x\n", ntf.data_exch_rx_bit_rate);
+       pr_debug("activation_params_len %d\n", ntf.activation_params_len);
 
        if (ntf.activation_params_len > 0) {
                switch (ntf.rf_interface) {
                case NCI_RF_INTERFACE_ISO_DEP:
                        err = nci_extract_activation_params_iso_dep(ndev,
-                               &ntf, data);
+                                                                   &ntf, data);
                        break;
 
                case NCI_RF_INTERFACE_FRAME:
@@ -489,7 +484,7 @@ exit:
 }
 
 static void nci_rf_deactivate_ntf_packet(struct nci_dev *ndev,
-                                       struct sk_buff *skb)
+                                        struct sk_buff *skb)
 {
        struct nci_rf_deactivate_ntf *ntf = (void *) skb->data;
 
index aa63b1e99188672e799c428c814ac26a289118ad..3003c3390e492c18907cc7f5076949439dd7273d 100644 (file)
@@ -67,19 +67,18 @@ static void nci_core_init_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
        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;
        }
 
        memcpy(ndev->supported_rf_interfaces,
-               rsp_1->supported_rf_interfaces,
-               ndev->num_supported_rf_interfaces);
+              rsp_1->supported_rf_interfaces,
+              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_logical_connections = rsp_2->max_logical_connections;
        ndev->max_routing_table_size =
                __le16_to_cpu(rsp_2->max_routing_table_size);
        ndev->max_ctrl_pkt_payload_len =
@@ -121,7 +120,7 @@ exit:
 }
 
 static void nci_rf_disc_map_rsp_packet(struct nci_dev *ndev,
-                                       struct sk_buff *skb)
+                                      struct sk_buff *skb)
 {
        __u8 status = skb->data[0];
 
@@ -143,7 +142,7 @@ static void nci_rf_disc_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
 }
 
 static void nci_rf_disc_select_rsp_packet(struct nci_dev *ndev,
-                                               struct sk_buff *skb)
+                                         struct sk_buff *skb)
 {
        __u8 status = skb->data[0];
 
@@ -155,7 +154,7 @@ static void nci_rf_disc_select_rsp_packet(struct nci_dev *ndev,
 }
 
 static void nci_rf_deactivate_rsp_packet(struct nci_dev *ndev,
-                                       struct sk_buff *skb)
+                                        struct sk_buff *skb)
 {
        __u8 status = skb->data[0];
 
@@ -163,7 +162,7 @@ static void nci_rf_deactivate_rsp_packet(struct nci_dev *ndev,
 
        /* If target was active, complete the request only in deactivate_ntf */
        if ((status != NCI_STATUS_OK) ||
-               (atomic_read(&ndev->state) != NCI_POLL_ACTIVE)) {
+           (atomic_read(&ndev->state) != NCI_POLL_ACTIVE)) {
                nci_clear_target_list(ndev);
                atomic_set(&ndev->state, NCI_IDLE);
                nci_req_complete(ndev, status);
index 07f0348aabf564789b2c9a1cae2be7e07a3478c9..6404052d6c070ccf8f54c4827408d5f9291d6b67 100644 (file)
@@ -48,34 +48,34 @@ static const struct nla_policy nfc_genl_policy[NFC_ATTR_MAX + 1] = {
        [NFC_ATTR_PROTOCOLS] = { .type = NLA_U32 },
        [NFC_ATTR_COMM_MODE] = { .type = NLA_U8 },
        [NFC_ATTR_RF_MODE] = { .type = NLA_U8 },
+       [NFC_ATTR_DEVICE_POWERED] = { .type = NLA_U8 },
 };
 
 static int nfc_genl_send_target(struct sk_buff *msg, struct nfc_target *target,
-                                       struct netlink_callback *cb, int flags)
+                               struct netlink_callback *cb, int flags)
 {
        void *hdr;
 
        hdr = genlmsg_put(msg, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq,
-                               &nfc_genl_family, flags, NFC_CMD_GET_TARGET);
+                         &nfc_genl_family, flags, NFC_CMD_GET_TARGET);
        if (!hdr)
                return -EMSGSIZE;
 
        genl_dump_check_consistent(cb, hdr, &nfc_genl_family);
 
        NLA_PUT_U32(msg, NFC_ATTR_TARGET_INDEX, target->idx);
-       NLA_PUT_U32(msg, NFC_ATTR_PROTOCOLS,
-                               target->supported_protocols);
+       NLA_PUT_U32(msg, NFC_ATTR_PROTOCOLS, target->supported_protocols);
        NLA_PUT_U16(msg, NFC_ATTR_TARGET_SENS_RES, target->sens_res);
        NLA_PUT_U8(msg, NFC_ATTR_TARGET_SEL_RES, target->sel_res);
        if (target->nfcid1_len > 0)
                NLA_PUT(msg, NFC_ATTR_TARGET_NFCID1, target->nfcid1_len,
-                               target->nfcid1);
+                       target->nfcid1);
        if (target->sensb_res_len > 0)
                NLA_PUT(msg, NFC_ATTR_TARGET_SENSB_RES, target->sensb_res_len,
-                               target->sensb_res);
+                       target->sensb_res);
        if (target->sensf_res_len > 0)
                NLA_PUT(msg, NFC_ATTR_TARGET_SENSF_RES, target->sensf_res_len,
-                               target->sensf_res);
+                       target->sensf_res);
 
        return genlmsg_end(msg, hdr);
 
@@ -91,9 +91,9 @@ static struct nfc_dev *__get_device_from_cb(struct netlink_callback *cb)
        u32 idx;
 
        rc = nlmsg_parse(cb->nlh, GENL_HDRLEN + nfc_genl_family.hdrsize,
-                                               nfc_genl_family.attrbuf,
-                                               nfc_genl_family.maxattr,
-                                               nfc_genl_policy);
+                        nfc_genl_family.attrbuf,
+                        nfc_genl_family.maxattr,
+                        nfc_genl_policy);
        if (rc < 0)
                return ERR_PTR(rc);
 
@@ -110,7 +110,7 @@ static struct nfc_dev *__get_device_from_cb(struct netlink_callback *cb)
 }
 
 static int nfc_genl_dump_targets(struct sk_buff *skb,
-                               struct netlink_callback *cb)
+                                struct netlink_callback *cb)
 {
        int i = cb->args[0];
        struct nfc_dev *dev = (struct nfc_dev *) cb->args[1];
@@ -130,7 +130,7 @@ static int nfc_genl_dump_targets(struct sk_buff *skb,
 
        while (i < dev->n_targets) {
                rc = nfc_genl_send_target(skb, &dev->targets[i], cb,
-                                                               NLM_F_MULTI);
+                                         NLM_F_MULTI);
                if (rc < 0)
                        break;
 
@@ -166,7 +166,7 @@ int nfc_genl_targets_found(struct nfc_dev *dev)
                return -ENOMEM;
 
        hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
-                               NFC_EVENT_TARGETS_FOUND);
+                         NFC_EVENT_TARGETS_FOUND);
        if (!hdr)
                goto free_msg;
 
@@ -193,13 +193,14 @@ int nfc_genl_device_added(struct nfc_dev *dev)
                return -ENOMEM;
 
        hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
-                               NFC_EVENT_DEVICE_ADDED);
+                         NFC_EVENT_DEVICE_ADDED);
        if (!hdr)
                goto free_msg;
 
        NLA_PUT_STRING(msg, NFC_ATTR_DEVICE_NAME, nfc_device_name(dev));
        NLA_PUT_U32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx);
        NLA_PUT_U32(msg, NFC_ATTR_PROTOCOLS, dev->supported_protocols);
+       NLA_PUT_U8(msg, NFC_ATTR_DEVICE_POWERED, dev->dev_up);
 
        genlmsg_end(msg, hdr);
 
@@ -224,7 +225,7 @@ int nfc_genl_device_removed(struct nfc_dev *dev)
                return -ENOMEM;
 
        hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
-                               NFC_EVENT_DEVICE_REMOVED);
+                         NFC_EVENT_DEVICE_REMOVED);
        if (!hdr)
                goto free_msg;
 
@@ -244,14 +245,14 @@ free_msg:
 }
 
 static int nfc_genl_send_device(struct sk_buff *msg, struct nfc_dev *dev,
-                                               u32 pid, u32 seq,
-                                               struct netlink_callback *cb,
-                                               int flags)
+                               u32 pid, u32 seq,
+                               struct netlink_callback *cb,
+                               int flags)
 {
        void *hdr;
 
        hdr = genlmsg_put(msg, pid, seq, &nfc_genl_family, flags,
-                                                       NFC_CMD_GET_DEVICE);
+                         NFC_CMD_GET_DEVICE);
        if (!hdr)
                return -EMSGSIZE;
 
@@ -261,6 +262,7 @@ static int nfc_genl_send_device(struct sk_buff *msg, struct nfc_dev *dev,
        NLA_PUT_STRING(msg, NFC_ATTR_DEVICE_NAME, nfc_device_name(dev));
        NLA_PUT_U32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx);
        NLA_PUT_U32(msg, NFC_ATTR_PROTOCOLS, dev->supported_protocols);
+       NLA_PUT_U8(msg, NFC_ATTR_DEVICE_POWERED, dev->dev_up);
 
        return genlmsg_end(msg, hdr);
 
@@ -270,7 +272,7 @@ nla_put_failure:
 }
 
 static int nfc_genl_dump_devices(struct sk_buff *skb,
-                               struct netlink_callback *cb)
+                                struct netlink_callback *cb)
 {
        struct class_dev_iter *iter = (struct class_dev_iter *) cb->args[0];
        struct nfc_dev *dev = (struct nfc_dev *) cb->args[1];
@@ -297,8 +299,7 @@ static int nfc_genl_dump_devices(struct sk_buff *skb,
                int rc;
 
                rc = nfc_genl_send_device(skb, dev, NETLINK_CB(cb->skb).pid,
-                                                       cb->nlh->nlmsg_seq,
-                                                       cb, NLM_F_MULTI);
+                                         cb->nlh->nlmsg_seq, cb, NLM_F_MULTI);
                if (rc < 0)
                        break;
 
@@ -323,7 +324,7 @@ static int nfc_genl_dump_devices_done(struct netlink_callback *cb)
 }
 
 int nfc_genl_dep_link_up_event(struct nfc_dev *dev, u32 target_idx,
-                                               u8 comm_mode, u8 rf_mode)
+                              u8 comm_mode, u8 rf_mode)
 {
        struct sk_buff *msg;
        void *hdr;
@@ -334,8 +335,7 @@ int nfc_genl_dep_link_up_event(struct nfc_dev *dev, u32 target_idx,
        if (!msg)
                return -ENOMEM;
 
-       hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
-                               NFC_CMD_DEP_LINK_UP);
+       hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, NFC_CMD_DEP_LINK_UP);
        if (!hdr)
                goto free_msg;
 
@@ -372,7 +372,7 @@ int nfc_genl_dep_link_down_event(struct nfc_dev *dev)
                return -ENOMEM;
 
        hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
-                               NFC_CMD_DEP_LINK_DOWN);
+                         NFC_CMD_DEP_LINK_DOWN);
        if (!hdr)
                goto free_msg;
 
@@ -414,7 +414,7 @@ static int nfc_genl_get_device(struct sk_buff *skb, struct genl_info *info)
        }
 
        rc = nfc_genl_send_device(msg, dev, info->snd_pid, info->snd_seq,
-                                                               NULL, 0);
+                                 NULL, 0);
        if (rc < 0)
                goto out_free;
 
@@ -481,7 +481,7 @@ static int nfc_genl_start_poll(struct sk_buff *skb, struct genl_info *info)
        pr_debug("Poll start\n");
 
        if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
-               !info->attrs[NFC_ATTR_PROTOCOLS])
+           !info->attrs[NFC_ATTR_PROTOCOLS])
                return -EINVAL;
 
        idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
@@ -539,13 +539,12 @@ static int nfc_genl_dep_link_up(struct sk_buff *skb, struct genl_info *info)
        struct nfc_dev *dev;
        int rc, tgt_idx;
        u32 idx;
-       u8 comm, rf;
+       u8 comm;
 
        pr_debug("DEP link up\n");
 
        if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
-                       !info->attrs[NFC_ATTR_COMM_MODE] ||
-                       !info->attrs[NFC_ATTR_RF_MODE])
+           !info->attrs[NFC_ATTR_COMM_MODE])
                return -EINVAL;
 
        idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
@@ -555,19 +554,15 @@ static int nfc_genl_dep_link_up(struct sk_buff *skb, struct genl_info *info)
                tgt_idx = nla_get_u32(info->attrs[NFC_ATTR_TARGET_INDEX]);
 
        comm = nla_get_u8(info->attrs[NFC_ATTR_COMM_MODE]);
-       rf = nla_get_u8(info->attrs[NFC_ATTR_RF_MODE]);
 
        if (comm != NFC_COMM_ACTIVE && comm != NFC_COMM_PASSIVE)
                return -EINVAL;
 
-       if (rf != NFC_RF_INITIATOR && comm != NFC_RF_TARGET)
-               return -EINVAL;
-
        dev = nfc_get_device(idx);
        if (!dev)
                return -ENODEV;
 
-       rc = nfc_dep_link_up(dev, tgt_idx, comm, rf);
+       rc = nfc_dep_link_up(dev, tgt_idx, comm);
 
        nfc_put_device(dev);
 
@@ -642,7 +637,7 @@ static struct genl_ops nfc_genl_ops[] = {
 };
 
 static int nfc_genl_rcv_nl_event(struct notifier_block *this,
-                                               unsigned long event, void *ptr)
+                                unsigned long event, void *ptr)
 {
        struct netlink_notify *n = ptr;
        struct class_dev_iter iter;
@@ -695,7 +690,7 @@ int __init nfc_genl_init(void)
        int rc;
 
        rc = genl_register_family_with_ops(&nfc_genl_family, nfc_genl_ops,
-                                       ARRAY_SIZE(nfc_genl_ops));
+                                          ARRAY_SIZE(nfc_genl_ops));
        if (rc)
                return rc;
 
index 6d28d75995b036e2da23410836313716efd9318f..ec8794c1099c9c2961446f101d9f0846caa96aca 100644 (file)
@@ -32,7 +32,7 @@ struct nfc_protocol {
        struct proto *proto;
        struct module *owner;
        int (*create)(struct net *net, struct socket *sock,
-                       const struct nfc_protocol *nfc_proto);
+                     const struct nfc_protocol *nfc_proto);
 };
 
 struct nfc_rawsock {
@@ -54,7 +54,7 @@ void nfc_llcp_mac_is_up(struct nfc_dev *dev, u32 target_idx,
 int nfc_llcp_register_device(struct nfc_dev *dev);
 void nfc_llcp_unregister_device(struct nfc_dev *dev);
 int nfc_llcp_set_remote_gb(struct nfc_dev *dev, u8 *gb, u8 gb_len);
-u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, u8 *general_bytes_len);
+u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *general_bytes_len);
 int __init nfc_llcp_init(void);
 void nfc_llcp_exit(void);
 
@@ -65,7 +65,7 @@ static inline void nfc_llcp_mac_is_down(struct nfc_dev *dev)
 }
 
 static inline void nfc_llcp_mac_is_up(struct nfc_dev *dev, u32 target_idx,
-                       u8 comm_mode, u8 rf_mode)
+                                     u8 comm_mode, u8 rf_mode)
 {
 }
 
@@ -78,7 +78,8 @@ static inline void nfc_llcp_unregister_device(struct nfc_dev *dev)
 {
 }
 
-static inline int nfc_llcp_set_remote_gb(struct nfc_dev *dev, u8 *gb, u8 gb_len)
+static inline int nfc_llcp_set_remote_gb(struct nfc_dev *dev,
+                                        u8 *gb, u8 gb_len)
 {
        return 0;
 }
@@ -160,8 +161,7 @@ int nfc_start_poll(struct nfc_dev *dev, u32 protocols);
 
 int nfc_stop_poll(struct nfc_dev *dev);
 
-int nfc_dep_link_up(struct nfc_dev *dev, int target_idx,
-                               u8 comm_mode, u8 rf_mode);
+int nfc_dep_link_up(struct nfc_dev *dev, int target_idx, u8 comm_mode);
 
 int nfc_dep_link_down(struct nfc_dev *dev);
 
@@ -169,9 +169,7 @@ int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol);
 
 int nfc_deactivate_target(struct nfc_dev *dev, u32 target_idx);
 
-int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx,
-                                       struct sk_buff *skb,
-                                       data_exchange_cb_t cb,
-                                       void *cb_context);
+int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, struct sk_buff *skb,
+                     data_exchange_cb_t cb, void *cb_context);
 
 #endif /* __LOCAL_NFC_H */
index 5325439b0c60872d4bd003074e2fbb8713f21157..5a839ceb2e82f1f23e45595ae836526b9589fefd 100644 (file)
@@ -63,7 +63,7 @@ static int rawsock_release(struct socket *sock)
 }
 
 static int rawsock_connect(struct socket *sock, struct sockaddr *_addr,
-                                                       int len, int flags)
+                          int len, int flags)
 {
        struct sock *sk = sock->sk;
        struct sockaddr_nfc *addr = (struct sockaddr_nfc *)_addr;
@@ -73,7 +73,7 @@ static int rawsock_connect(struct socket *sock, struct sockaddr *_addr,
        pr_debug("sock=%p sk=%p flags=%d\n", sock, sk, flags);
 
        if (!addr || len < sizeof(struct sockaddr_nfc) ||
-               addr->sa_family != AF_NFC)
+           addr->sa_family != AF_NFC)
                return -EINVAL;
 
        pr_debug("addr dev_idx=%u target_idx=%u protocol=%u\n",
@@ -120,7 +120,7 @@ static int rawsock_add_header(struct sk_buff *skb)
 }
 
 static void rawsock_data_exchange_complete(void *context, struct sk_buff *skb,
-                                                               int err)
+                                          int err)
 {
        struct sock *sk = (struct sock *) context;
 
@@ -173,7 +173,7 @@ static void rawsock_tx_work(struct work_struct *work)
 
        sock_hold(sk);
        rc = nfc_data_exchange(dev, target_idx, skb,
-                               rawsock_data_exchange_complete, sk);
+                              rawsock_data_exchange_complete, sk);
        if (rc) {
                rawsock_report_error(sk, rc);
                sock_put(sk);
@@ -181,7 +181,7 @@ static void rawsock_tx_work(struct work_struct *work)
 }
 
 static int rawsock_sendmsg(struct kiocb *iocb, struct socket *sock,
-                                       struct msghdr *msg, size_t len)
+                          struct msghdr *msg, size_t len)
 {
        struct sock *sk = sock->sk;
        struct nfc_dev *dev = nfc_rawsock(sk)->dev;
@@ -218,7 +218,7 @@ static int rawsock_sendmsg(struct kiocb *iocb, struct socket *sock,
 }
 
 static int rawsock_recvmsg(struct kiocb *iocb, struct socket *sock,
-                               struct msghdr *msg, size_t len, int flags)
+                          struct msghdr *msg, size_t len, int flags)
 {
        int noblock = flags & MSG_DONTWAIT;
        struct sock *sk = sock->sk;
@@ -274,7 +274,7 @@ static void rawsock_destruct(struct sock *sk)
 
        if (sk->sk_state == TCP_ESTABLISHED) {
                nfc_deactivate_target(nfc_rawsock(sk)->dev,
-                                       nfc_rawsock(sk)->target_idx);
+                                     nfc_rawsock(sk)->target_idx);
                nfc_put_device(nfc_rawsock(sk)->dev);
        }
 
@@ -287,7 +287,7 @@ static void rawsock_destruct(struct sock *sk)
 }
 
 static int rawsock_create(struct net *net, struct socket *sock,
-                               const struct nfc_protocol *nfc_proto)
+                         const struct nfc_protocol *nfc_proto)
 {
        struct sock *sk;
 
index 2725d1bdf2916b1b0545dbb9d400d931d7abd974..48badffaafc1a2c0ce0b8d8ec7a0729c2d2cbb42 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007-2011 Nicira Networks.
+ * Copyright (c) 2007-2012 Nicira Networks.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of version 2 of the GNU General Public
@@ -145,9 +145,16 @@ static void set_ip_addr(struct sk_buff *skb, struct iphdr *nh,
                        inet_proto_csum_replace4(&tcp_hdr(skb)->check, skb,
                                                 *addr, new_addr, 1);
        } else if (nh->protocol == IPPROTO_UDP) {
-               if (likely(transport_len >= sizeof(struct udphdr)))
-                       inet_proto_csum_replace4(&udp_hdr(skb)->check, skb,
-                                                *addr, new_addr, 1);
+               if (likely(transport_len >= sizeof(struct udphdr))) {
+                       struct udphdr *uh = udp_hdr(skb);
+
+                       if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) {
+                               inet_proto_csum_replace4(&uh->check, skb,
+                                                        *addr, new_addr, 1);
+                               if (!uh->check)
+                                       uh->check = CSUM_MANGLED_0;
+                       }
+               }
        }
 
        csum_replace4(&nh->check, *addr, new_addr);
@@ -197,8 +204,22 @@ static void set_tp_port(struct sk_buff *skb, __be16 *port,
        skb->rxhash = 0;
 }
 
-static int set_udp_port(struct sk_buff *skb,
-                       const struct ovs_key_udp *udp_port_key)
+static void set_udp_port(struct sk_buff *skb, __be16 *port, __be16 new_port)
+{
+       struct udphdr *uh = udp_hdr(skb);
+
+       if (uh->check && skb->ip_summed != CHECKSUM_PARTIAL) {
+               set_tp_port(skb, port, new_port, &uh->check);
+
+               if (!uh->check)
+                       uh->check = CSUM_MANGLED_0;
+       } else {
+               *port = new_port;
+               skb->rxhash = 0;
+       }
+}
+
+static int set_udp(struct sk_buff *skb, const struct ovs_key_udp *udp_port_key)
 {
        struct udphdr *uh;
        int err;
@@ -210,16 +231,15 @@ static int set_udp_port(struct sk_buff *skb,
 
        uh = udp_hdr(skb);
        if (udp_port_key->udp_src != uh->source)
-               set_tp_port(skb, &uh->source, udp_port_key->udp_src, &uh->check);
+               set_udp_port(skb, &uh->source, udp_port_key->udp_src);
 
        if (udp_port_key->udp_dst != uh->dest)
-               set_tp_port(skb, &uh->dest, udp_port_key->udp_dst, &uh->check);
+               set_udp_port(skb, &uh->dest, udp_port_key->udp_dst);
 
        return 0;
 }
 
-static int set_tcp_port(struct sk_buff *skb,
-                       const struct ovs_key_tcp *tcp_port_key)
+static int set_tcp(struct sk_buff *skb, const struct ovs_key_tcp *tcp_port_key)
 {
        struct tcphdr *th;
        int err;
@@ -328,11 +348,11 @@ static int execute_set_action(struct sk_buff *skb,
                break;
 
        case OVS_KEY_ATTR_TCP:
-               err = set_tcp_port(skb, nla_data(nested_attr));
+               err = set_tcp(skb, nla_data(nested_attr));
                break;
 
        case OVS_KEY_ATTR_UDP:
-               err = set_udp_port(skb, nla_data(nested_attr));
+               err = set_udp(skb, nla_data(nested_attr));
                break;
        }
 
index ce64c18b8c79a99ef4251e7c9d2a752105207725..2c030505b335fd3ef9ab971fb9abd664548d8c38 100644 (file)
@@ -1521,6 +1521,9 @@ static struct vport *lookup_vport(struct ovs_header *ovs_header,
                vport = ovs_vport_locate(nla_data(a[OVS_VPORT_ATTR_NAME]));
                if (!vport)
                        return ERR_PTR(-ENODEV);
+               if (ovs_header->dp_ifindex &&
+                   ovs_header->dp_ifindex != get_dpifindex(vport->dp))
+                       return ERR_PTR(-ENODEV);
                return vport;
        } else if (a[OVS_VPORT_ATTR_PORT_NO]) {
                u32 port_no = nla_get_u32(a[OVS_VPORT_ATTR_PORT_NO]);
index 408ebd0e73305b56b76dc139af29611742c8e82c..06b42b7f5a0237c054403c3b695aea26dcae036b 100644 (file)
@@ -4170,14 +4170,16 @@ static int sctp_getsockopt_autoclose(struct sock *sk, int len, char __user *optv
 }
 
 /* Helper routine to branch off an association to a new socket.  */
-SCTP_STATIC int sctp_do_peeloff(struct sctp_association *asoc,
-                               struct socket **sockp)
+int sctp_do_peeloff(struct sock *sk, sctp_assoc_t id, struct socket **sockp)
 {
-       struct sock *sk = asoc->base.sk;
+       struct sctp_association *asoc = sctp_id2assoc(sk, id);
        struct socket *sock;
        struct sctp_af *af;
        int err = 0;
 
+       if (!asoc)
+               return -EINVAL;
+
        /* An association cannot be branched off from an already peeled-off
         * socket, nor is this supported for tcp style sockets.
         */
@@ -4206,13 +4208,13 @@ SCTP_STATIC int sctp_do_peeloff(struct sctp_association *asoc,
 
        return err;
 }
+EXPORT_SYMBOL(sctp_do_peeloff);
 
 static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval, int __user *optlen)
 {
        sctp_peeloff_arg_t peeloff;
        struct socket *newsock;
        int retval = 0;
-       struct sctp_association *asoc;
 
        if (len < sizeof(sctp_peeloff_arg_t))
                return -EINVAL;
@@ -4220,15 +4222,7 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval
        if (copy_from_user(&peeloff, optval, len))
                return -EFAULT;
 
-       asoc = sctp_id2assoc(sk, peeloff.associd);
-       if (!asoc) {
-               retval = -EINVAL;
-               goto out;
-       }
-
-       SCTP_DEBUG_PRINTK("%s: sk: %p asoc: %p\n", __func__, sk, asoc);
-
-       retval = sctp_do_peeloff(asoc, &newsock);
+       retval = sctp_do_peeloff(sk, peeloff.associd, &newsock);
        if (retval < 0)
                goto out;
 
@@ -4239,8 +4233,8 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval
                goto out;
        }
 
-       SCTP_DEBUG_PRINTK("%s: sk: %p asoc: %p newsk: %p sd: %d\n",
-                         __func__, sk, asoc, newsock->sk, retval);
+       SCTP_DEBUG_PRINTK("%s: sk: %p newsk: %p sd: %d\n",
+                         __func__, sk, newsock->sk, retval);
 
        /* Return the fd mapped to the new socket.  */
        peeloff.sd = retval;
index 9d3e3b6bfcf4c20f6a0e484dd097319a3a63eefa..ba21ab22187bef366394743d9d94d6ee33d72b6a 100644 (file)
@@ -23,6 +23,8 @@
 #define MESH_PERR_MIN_INT      100
 #define MESH_DIAM_TRAVERSAL_TIME 50
 
+#define MESH_RSSI_THRESHOLD    0
+
 /*
  * A path will be refreshed if it is used PATH_REFRESH_TIME milliseconds
  * before timing out.  This way it will remain ACTIVE and no data frames
@@ -56,6 +58,7 @@ const struct mesh_config default_mesh_config = {
        .dot11MeshHWMPRannInterval = MESH_RANN_INTERVAL,
        .dot11MeshGateAnnouncementProtocol = false,
        .dot11MeshForwarding = true,
+       .rssi_threshold = MESH_RSSI_THRESHOLD,
 };
 
 const struct mesh_setup default_mesh_setup = {
index d553d365e7512aa1796926e6ab7e88f9b4950574..f5a7ac3a0939ab0e782bf31bc538c0fa2a22cb3d 100644 (file)
@@ -455,7 +455,7 @@ int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
                return 0;
        }
 
-       return rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
+       return rdev->ops->deauth(&rdev->wiphy, dev, &req);
 }
 
 int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
@@ -500,7 +500,7 @@ static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
        else
                return -ENOTCONN;
 
-       return rdev->ops->disassoc(&rdev->wiphy, dev, &req, wdev);
+       return rdev->ops->disassoc(&rdev->wiphy, dev, &req);
 }
 
 int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
@@ -541,7 +541,7 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
 
        memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN);
        req.bssid = bssid;
-       rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
+       rdev->ops->deauth(&rdev->wiphy, dev, &req);
 
        if (wdev->current_bss) {
                cfg80211_unhold_bss(wdev->current_bss);
@@ -814,8 +814,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
                                  cookie);
 }
 
-bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf,
-                     size_t len, gfp_t gfp)
+bool cfg80211_rx_mgmt(struct net_device *dev, int freq, int sig_mbm,
+                     const u8 *buf, size_t len, gfp_t gfp)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct wiphy *wiphy = wdev->wiphy;
@@ -854,7 +854,8 @@ bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf,
                /* found match! */
 
                /* Indicate the received Action frame to user space */
-               if (nl80211_send_mgmt(rdev, dev, reg->nlpid, freq,
+               if (nl80211_send_mgmt(rdev, dev, reg->nlpid,
+                                     freq, sig_mbm,
                                      buf, len, gfp))
                        continue;
 
index fe2747653564b6e63133f057cd9d9ec2712c900e..39dbdf2adb12969b100e91a5e87dc3507bd3f110 100644 (file)
@@ -204,6 +204,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
                .len = NL80211_HT_CAPABILITY_LEN
        },
        [NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 },
+       [NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 },
 };
 
 /* policy for the key attributes */
@@ -871,7 +872,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
        CMD(add_virtual_intf, NEW_INTERFACE);
        CMD(change_virtual_intf, SET_INTERFACE);
        CMD(add_key, NEW_KEY);
-       CMD(add_beacon, NEW_BEACON);
+       CMD(start_ap, START_AP);
        CMD(add_station, NEW_STATION);
        CMD(add_mpath, NEW_MPATH);
        CMD(update_mesh_config, SET_MESH_CONFIG);
@@ -2075,15 +2076,10 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
        return err;
 }
 
-static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
+static int nl80211_parse_beacon(struct genl_info *info,
+                               struct cfg80211_beacon_data *bcn)
 {
-        int (*call)(struct wiphy *wiphy, struct net_device *dev,
-                   struct beacon_parameters *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 beacon_parameters params;
-       int haveinfo = 0, err;
+       bool haveinfo = false;
 
        if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL]) ||
            !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]) ||
@@ -2091,149 +2087,190 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
            !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]))
                return -EINVAL;
 
-       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
-           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
-               return -EOPNOTSUPP;
-
-       memset(&params, 0, sizeof(params));
-
-       switch (info->genlhdr->cmd) {
-       case NL80211_CMD_NEW_BEACON:
-               /* these are required for NEW_BEACON */
-               if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
-                   !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
-                   !info->attrs[NL80211_ATTR_BEACON_HEAD])
-                       return -EINVAL;
-
-               params.interval =
-                       nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
-               params.dtim_period =
-                       nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
-
-               err = cfg80211_validate_beacon_int(rdev, params.interval);
-               if (err)
-                       return err;
-
-               /*
-                * In theory, some of these attributes could be required for
-                * NEW_BEACON, but since they were not used when the command was
-                * originally added, keep them optional for old user space
-                * programs to work with drivers that do not need the additional
-                * information.
-                */
-               if (info->attrs[NL80211_ATTR_SSID]) {
-                       params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
-                       params.ssid_len =
-                               nla_len(info->attrs[NL80211_ATTR_SSID]);
-                       if (params.ssid_len == 0 ||
-                           params.ssid_len > IEEE80211_MAX_SSID_LEN)
-                               return -EINVAL;
-               }
-
-               if (info->attrs[NL80211_ATTR_HIDDEN_SSID]) {
-                       params.hidden_ssid = nla_get_u32(
-                               info->attrs[NL80211_ATTR_HIDDEN_SSID]);
-                       if (params.hidden_ssid !=
-                           NL80211_HIDDEN_SSID_NOT_IN_USE &&
-                           params.hidden_ssid !=
-                           NL80211_HIDDEN_SSID_ZERO_LEN &&
-                           params.hidden_ssid !=
-                           NL80211_HIDDEN_SSID_ZERO_CONTENTS)
-                               return -EINVAL;
-               }
-
-               params.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
-
-               if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
-                       params.auth_type = nla_get_u32(
-                               info->attrs[NL80211_ATTR_AUTH_TYPE]);
-                       if (!nl80211_valid_auth_type(params.auth_type))
-                               return -EINVAL;
-               } else
-                       params.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
-
-               err = nl80211_crypto_settings(rdev, info, &params.crypto,
-                                             NL80211_MAX_NR_CIPHER_SUITES);
-               if (err)
-                       return err;
-
-               call = rdev->ops->add_beacon;
-               break;
-       case NL80211_CMD_SET_BEACON:
-               call = rdev->ops->set_beacon;
-               break;
-       default:
-               WARN_ON(1);
-               return -EOPNOTSUPP;
-       }
-
-       if (!call)
-               return -EOPNOTSUPP;
+       memset(bcn, 0, sizeof(*bcn));
 
        if (info->attrs[NL80211_ATTR_BEACON_HEAD]) {
-               params.head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]);
-               params.head_len =
-                   nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]);
-               haveinfo = 1;
+               bcn->head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]);
+               bcn->head_len = nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]);
+               if (!bcn->head_len)
+                       return -EINVAL;
+               haveinfo = true;
        }
 
        if (info->attrs[NL80211_ATTR_BEACON_TAIL]) {
-               params.tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]);
-               params.tail_len =
+               bcn->tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]);
+               bcn->tail_len =
                    nla_len(info->attrs[NL80211_ATTR_BEACON_TAIL]);
-               haveinfo = 1;
+               haveinfo = true;
        }
 
        if (!haveinfo)
                return -EINVAL;
 
        if (info->attrs[NL80211_ATTR_IE]) {
-               params.beacon_ies = nla_data(info->attrs[NL80211_ATTR_IE]);
-               params.beacon_ies_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+               bcn->beacon_ies = nla_data(info->attrs[NL80211_ATTR_IE]);
+               bcn->beacon_ies_len = nla_len(info->attrs[NL80211_ATTR_IE]);
        }
 
        if (info->attrs[NL80211_ATTR_IE_PROBE_RESP]) {
-               params.proberesp_ies =
+               bcn->proberesp_ies =
                        nla_data(info->attrs[NL80211_ATTR_IE_PROBE_RESP]);
-               params.proberesp_ies_len =
+               bcn->proberesp_ies_len =
                        nla_len(info->attrs[NL80211_ATTR_IE_PROBE_RESP]);
        }
 
        if (info->attrs[NL80211_ATTR_IE_ASSOC_RESP]) {
-               params.assocresp_ies =
+               bcn->assocresp_ies =
                        nla_data(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]);
-               params.assocresp_ies_len =
+               bcn->assocresp_ies_len =
                        nla_len(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]);
        }
 
        if (info->attrs[NL80211_ATTR_PROBE_RESP]) {
-               params.probe_resp =
+               bcn->probe_resp =
                        nla_data(info->attrs[NL80211_ATTR_PROBE_RESP]);
-               params.probe_resp_len =
+               bcn->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;
+       return 0;
+}
+
+static int nl80211_start_ap(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 cfg80211_ap_settings params;
+       int err;
+
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+               return -EOPNOTSUPP;
+
+       if (!rdev->ops->start_ap)
+               return -EOPNOTSUPP;
+
+       if (wdev->beacon_interval)
+               return -EALREADY;
+
+       memset(&params, 0, sizeof(params));
+
+       /* these are required for START_AP */
+       if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
+           !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
+           !info->attrs[NL80211_ATTR_BEACON_HEAD])
+               return -EINVAL;
+
+       err = nl80211_parse_beacon(info, &params.beacon);
+       if (err)
+               return err;
+
+       params.beacon_interval =
+               nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
+       params.dtim_period =
+               nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
+
+       err = cfg80211_validate_beacon_int(rdev, params.beacon_interval);
+       if (err)
+               return err;
+
+       /*
+        * In theory, some of these attributes should be required here
+        * but since they were not used when the command was originally
+        * added, keep them optional for old user space programs to let
+        * them continue to work with drivers that do not need the
+        * additional information -- drivers must check!
+        */
+       if (info->attrs[NL80211_ATTR_SSID]) {
+               params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
+               params.ssid_len =
+                       nla_len(info->attrs[NL80211_ATTR_SSID]);
+               if (params.ssid_len == 0 ||
+                   params.ssid_len > IEEE80211_MAX_SSID_LEN)
+                       return -EINVAL;
+       }
+
+       if (info->attrs[NL80211_ATTR_HIDDEN_SSID]) {
+               params.hidden_ssid = nla_get_u32(
+                       info->attrs[NL80211_ATTR_HIDDEN_SSID]);
+               if (params.hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE &&
+                   params.hidden_ssid != NL80211_HIDDEN_SSID_ZERO_LEN &&
+                   params.hidden_ssid != NL80211_HIDDEN_SSID_ZERO_CONTENTS)
+                       return -EINVAL;
+       }
+
+       params.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
+
+       if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
+               params.auth_type = nla_get_u32(
+                       info->attrs[NL80211_ATTR_AUTH_TYPE]);
+               if (!nl80211_valid_auth_type(params.auth_type))
+                       return -EINVAL;
+       } else
+               params.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
+
+       err = nl80211_crypto_settings(rdev, info, &params.crypto,
+                                     NL80211_MAX_NR_CIPHER_SUITES);
+       if (err)
+               return err;
+
+       if (info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]) {
+               if (!(rdev->wiphy.features & NL80211_FEATURE_INACTIVITY_TIMER))
+                       return -EOPNOTSUPP;
+               params.inactivity_timeout = nla_get_u16(
+                       info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]);
+       }
+
+       err = rdev->ops->start_ap(&rdev->wiphy, dev, &params);
+       if (!err)
+               wdev->beacon_interval = params.beacon_interval;
        return err;
 }
 
-static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info)
+static int nl80211_set_beacon(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 cfg80211_beacon_data params;
        int err;
 
-       if (!rdev->ops->del_beacon)
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+               return -EOPNOTSUPP;
+
+       if (!rdev->ops->change_beacon)
+               return -EOPNOTSUPP;
+
+       if (!wdev->beacon_interval)
+               return -EINVAL;
+
+       err = nl80211_parse_beacon(info, &params);
+       if (err)
+               return err;
+
+       return rdev->ops->change_beacon(&rdev->wiphy, dev, &params);
+}
+
+static int nl80211_stop_ap(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;
+       int err;
+
+       if (!rdev->ops->stop_ap)
                return -EOPNOTSUPP;
 
        if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
            dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
                return -EOPNOTSUPP;
 
-       err = rdev->ops->del_beacon(&rdev->wiphy, dev);
+       if (!wdev->beacon_interval)
+               return -ENOENT;
+
+       err = rdev->ops->stop_ap(&rdev->wiphy, dev);
        if (!err)
                wdev->beacon_interval = 0;
        return err;
@@ -3261,6 +3298,8 @@ static int nl80211_get_mesh_config(struct sk_buff *skb,
                        cur_params.dot11MeshGateAnnouncementProtocol);
        NLA_PUT_U8(msg, NL80211_MESHCONF_FORWARDING,
                        cur_params.dot11MeshForwarding);
+       NLA_PUT_U32(msg, NL80211_MESHCONF_RSSI_THRESHOLD,
+                       cur_params.rssi_threshold);
        nla_nest_end(msg, pinfoattr);
        genlmsg_end(msg, hdr);
        return genlmsg_reply(msg, info);
@@ -3293,6 +3332,7 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A
        [NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 },
        [NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = { .type = NLA_U8 },
        [NL80211_MESHCONF_FORWARDING] = { .type = NLA_U8 },
+       [NL80211_MESHCONF_RSSI_THRESHOLD] = { .type = NLA_U32},
 };
 
 static const struct nla_policy
@@ -3384,6 +3424,8 @@ do {\
                        nla_get_u8);
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding,
                        mask, NL80211_MESHCONF_FORWARDING, nla_get_u8);
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold,
+                       mask, NL80211_MESHCONF_RSSI_THRESHOLD, nla_get_u32);
        if (mask_out)
                *mask_out = mask;
 
@@ -6357,23 +6399,23 @@ static struct genl_ops nl80211_ops[] = {
                .cmd = NL80211_CMD_SET_BEACON,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
-               .doit = nl80211_addset_beacon,
+               .doit = nl80211_set_beacon,
                .internal_flags = NL80211_FLAG_NEED_NETDEV |
                                  NL80211_FLAG_NEED_RTNL,
        },
        {
-               .cmd = NL80211_CMD_NEW_BEACON,
+               .cmd = NL80211_CMD_START_AP,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
-               .doit = nl80211_addset_beacon,
+               .doit = nl80211_start_ap,
                .internal_flags = NL80211_FLAG_NEED_NETDEV |
                                  NL80211_FLAG_NEED_RTNL,
        },
        {
-               .cmd = NL80211_CMD_DEL_BEACON,
+               .cmd = NL80211_CMD_STOP_AP,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
-               .doit = nl80211_del_beacon,
+               .doit = nl80211_stop_ap,
                .internal_flags = NL80211_FLAG_NEED_NETDEV |
                                  NL80211_FLAG_NEED_RTNL,
        },
@@ -7644,7 +7686,8 @@ bool nl80211_unexpected_4addr_frame(struct net_device *dev,
 
 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)
+                     int freq, int sig_dbm,
+                     const u8 *buf, size_t len, gfp_t gfp)
 {
        struct sk_buff *msg;
        void *hdr;
@@ -7662,6 +7705,8 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
+       if (sig_dbm)
+               NLA_PUT_U32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm);
        NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf);
 
        genlmsg_end(msg, hdr);
@@ -7923,7 +7968,7 @@ EXPORT_SYMBOL(cfg80211_probe_status);
 
 void cfg80211_report_obss_beacon(struct wiphy *wiphy,
                                 const u8 *frame, size_t len,
-                                int freq, gfp_t gfp)
+                                int freq, int sig_dbm, gfp_t gfp)
 {
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
        struct sk_buff *msg;
@@ -7946,6 +7991,8 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy,
        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
        if (freq)
                NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
+       if (sig_dbm)
+               NLA_PUT_U32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm);
        NLA_PUT(msg, NL80211_ATTR_FRAME, len, frame);
 
        genlmsg_end(msg, hdr);
index 12bf4d185abe7dd1f0e89494261c3441faab3680..4ffe50df9f31461e84c426aeb54e46fb1cd8c897 100644 (file)
@@ -92,7 +92,8 @@ void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev,
                                gfp_t gfp);
 
 int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
-                     struct net_device *netdev, u32 nlpid, int freq,
+                     struct net_device *netdev, u32 nlpid,
+                     int freq, int sig_dbm,
                      const u8 *buf, size_t len, gfp_t gfp);
 void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev,
                                 struct net_device *netdev, u64 cookie,
index 9aa9db6c81411ddfcd77c34de8128fcd57e2e5d2..1b7a08df933c79bf4ffe62455747464468c84bdb 100644 (file)
@@ -904,6 +904,7 @@ u16 cfg80211_calculate_bitrate(struct rate_info *rate)
        /* do NOT round down here */
        return (bitrate + 50000) / 100000;
 }
+EXPORT_SYMBOL(cfg80211_calculate_bitrate);
 
 int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
                                 u32 beacon_int)
index d0de2a2c3a2de00cacf74ba796f5b02fa5b56a5d..b89efe6e4c85adc59bc9f1c54e49fb1814778901 100644 (file)
@@ -46,11 +46,37 @@ struct devtable {
        void *function;
 };
 
+#define ___cat(a,b) a ## b
+#define __cat(a,b) ___cat(a,b)
+
+/* we need some special handling for this host tool running eventually on
+ * Darwin. The Mach-O section handling is a bit different than ELF section
+ * handling. The differnces in detail are:
+ *  a) we have segments which have sections
+ *  b) we need a API call to get the respective section symbols */
+#if defined(__MACH__)
+#include <mach-o/getsect.h>
+
+#define INIT_SECTION(name)  do {                                       \
+               unsigned long name ## _len;                             \
+               char *__cat(pstart_,name) = getsectdata("__TEXT",       \
+                       #name, &__cat(name,_len));                      \
+               char *__cat(pstop_,name) = __cat(pstart_,name) +        \
+                       __cat(name, _len);                              \
+               __cat(__start_,name) = (void *)__cat(pstart_,name);     \
+               __cat(__stop_,name) = (void *)__cat(pstop_,name);       \
+       } while (0)
+#define SECTION(name)   __attribute__((section("__TEXT, " #name)))
+
+struct devtable **__start___devtable, **__stop___devtable;
+#else
+#define INIT_SECTION(name) /* no-op for ELF */
+#define SECTION(name)   __attribute__((section(#name)))
+
 /* We construct a table of pointers in an ELF section (pointers generally
  * go unpadded by gcc).  ld creates boundary syms for us. */
 extern struct devtable *__start___devtable[], *__stop___devtable[];
-#define ___cat(a,b) a ## b
-#define __cat(a,b) ___cat(a,b)
+#endif /* __MACH__ */
 
 #if __GNUC__ == 3 && __GNUC_MINOR__ < 3
 # define __used                        __attribute__((__unused__))
@@ -65,8 +91,8 @@ extern struct devtable *__start___devtable[], *__stop___devtable[];
                                                (type *)NULL,           \
                                                (char *)NULL)),         \
                sizeof(type), (function) };                             \
-       static struct devtable *__attribute__((section("__devtable"))) \
-               __used __cat(devtable_ptr,__LINE__) = &__cat(devtable,__LINE__)
+       static struct devtable *SECTION(__devtable) __used \
+               __cat(devtable_ptr,__LINE__) = &__cat(devtable,__LINE__)
 
 #define ADD(str, sep, cond, field)                              \
 do {                                                            \
@@ -1080,6 +1106,7 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
                do_pnp_card_entries(symval, sym->st_size, mod);
        else {
                struct devtable **p;
+               INIT_SECTION(__devtable);
 
                for (p = __start___devtable; p < __stop___devtable; p++) {
                        if (sym_is(name, namelen, (*p)->device_id)) {
index 95ffa6a9db6e7412e3cca49ab6eb175d55b0983d..496f14c1a731e78071d30c814f6f0e08c143d85e 100644 (file)
@@ -2684,10 +2684,9 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
                err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
                if (err < 0)
                        goto out_err;
+               opl3->private_data = chip;
        }
 
-       opl3->private_data = chip;
-
        sprintf(card->longname, "%s at 0x%lx, irq %i",
                card->shortname, chip->ctrl_io, chip->irq);
 
index c2c65f63bf068a0d39fbfd271be81d74c22d0459..684307372d73e87535323ecc2e250a2ffab21f8e 100644 (file)
@@ -1759,7 +1759,11 @@ static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info,
        parm = ch ? AC_AMP_SET_RIGHT : AC_AMP_SET_LEFT;
        parm |= direction == HDA_OUTPUT ? AC_AMP_SET_OUTPUT : AC_AMP_SET_INPUT;
        parm |= index << AC_AMP_SET_INDEX_SHIFT;
-       parm |= val;
+       if ((val & HDA_AMP_MUTE) && !(info->amp_caps & AC_AMPCAP_MUTE) &&
+           (info->amp_caps & AC_AMPCAP_MIN_MUTE))
+               ; /* set the zero value as a fake mute */
+       else
+               parm |= val;
        snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, parm);
        info->vol[ch] = val;
 }
@@ -2026,7 +2030,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag,
        val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT);
        val1 += ofs;
        val1 = ((int)val1) * ((int)val2);
-       if (min_mute)
+       if (min_mute || (caps & AC_AMPCAP_MIN_MUTE))
                val2 |= TLV_DB_SCALE_MUTE;
        if (put_user(SNDRV_CTL_TLVT_DB_SCALE, _tlv))
                return -EFAULT;
@@ -5114,7 +5118,7 @@ static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid,
        const char *pfx = "", *sfx = "";
 
        /* handle as a speaker if it's a fixed line-out */
-       if (!strcmp(name, "Line-Out") && attr == INPUT_PIN_ATTR_INT)
+       if (!strcmp(name, "Line Out") && attr == INPUT_PIN_ATTR_INT)
                name = "Speaker";
        /* check the location */
        switch (attr) {
@@ -5173,7 +5177,7 @@ int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
 
        switch (get_defcfg_device(def_conf)) {
        case AC_JACK_LINE_OUT:
-               return fill_audio_out_name(codec, nid, cfg, "Line-Out",
+               return fill_audio_out_name(codec, nid, cfg, "Line Out",
                                           label, maxlen, indexp);
        case AC_JACK_SPEAKER:
                return fill_audio_out_name(codec, nid, cfg, "Speaker",
index e9f71dc0d46415587f7461678d5ae6051aa9b289..f0f1943a4b2c890ce4affe17425de6210e53ea89 100644 (file)
@@ -298,6 +298,9 @@ enum {
 #define AC_AMPCAP_MUTE                 (1<<31)    /* mute capable */
 #define AC_AMPCAP_MUTE_SHIFT           31
 
+/* driver-specific amp-caps: using bits 24-30 */
+#define AC_AMPCAP_MIN_MUTE             (1 << 30) /* min-volume = mute */
+
 /* Connection list */
 #define AC_CLIST_LENGTH                        (0x7f<<0)
 #define AC_CLIST_LONG                  (1<<7)
index bc5a993d11461868a2115d5b81efec25114a9996..c83ccdba1e5afc1dca9715a870eedf68a8961ee8 100644 (file)
@@ -609,7 +609,7 @@ static int add_output(struct hda_codec *codec, hda_nid_t dac, int idx,
                "Front Speaker", "Surround Speaker", "Bass Speaker"
        };
        static const char * const line_outs[] = {
-               "Front Line-Out", "Surround Line-Out", "Bass Line-Out"
+               "Front Line Out", "Surround Line Out", "Bass Line Out"
        };
 
        fix_volume_caps(codec, dac);
@@ -635,7 +635,7 @@ static int add_output(struct hda_codec *codec, hda_nid_t dac, int idx,
                if (num_ctls > 1)
                        name = line_outs[idx];
                else
-                       name = "Line-Out";
+                       name = "Line Out";
                break;
        }
 
index a7a5733aa4d20d2ea25edf104e4568b4e42cab3d..d29d6d37790425924ce818acff4f6402f0fa8e82 100644 (file)
@@ -3482,7 +3482,7 @@ static int cx_automute_mode_info(struct snd_kcontrol *kcontrol,
                "Disabled", "Enabled"
        };
        static const char * const texts3[] = {
-               "Disabled", "Speaker Only", "Line-Out+Speaker"
+               "Disabled", "Speaker Only", "Line Out+Speaker"
        };
        const char * const *texts;
 
@@ -4079,7 +4079,8 @@ static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename,
                err = snd_hda_ctl_add(codec, nid, kctl);
                if (err < 0)
                        return err;
-               if (!(query_amp_caps(codec, nid, hda_dir) & AC_AMPCAP_MUTE))
+               if (!(query_amp_caps(codec, nid, hda_dir) &
+                     (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE)))
                        break;
        }
        return 0;
@@ -4379,6 +4380,22 @@ static const struct snd_pci_quirk cxt_fixups[] = {
        {}
 };
 
+/* add "fake" mute amp-caps to DACs on cx5051 so that mixer mute switches
+ * can be created (bko#42825)
+ */
+static void add_cx5051_fake_mutes(struct hda_codec *codec)
+{
+       static hda_nid_t out_nids[] = {
+               0x10, 0x11, 0
+       };
+       hda_nid_t *p;
+
+       for (p = out_nids; *p; p++)
+               snd_hda_override_amp_caps(codec, *p, HDA_OUTPUT,
+                                         AC_AMPCAP_MIN_MUTE |
+                                         query_amp_caps(codec, *p, HDA_OUTPUT));
+}
+
 static int patch_conexant_auto(struct hda_codec *codec)
 {
        struct conexant_spec *spec;
@@ -4397,6 +4414,9 @@ static int patch_conexant_auto(struct hda_codec *codec)
        case 0x14f15045:
                spec->single_adc_amp = 1;
                break;
+       case 0x14f15051:
+               add_cx5051_fake_mutes(codec);
+               break;
        }
 
        apply_pin_fixup(codec, cxt_fixups, cxt_pincfg_tbl);
index 3647baa9bfed302b63e6fcaf8f9726da7d050389..22c73b78ac6f193b635ef362c026bf51b8fe1da8 100644 (file)
@@ -802,7 +802,7 @@ static int alc_automute_mode_info(struct snd_kcontrol *kcontrol,
                "Disabled", "Enabled"
        };
        static const char * const texts3[] = {
-               "Disabled", "Speaker Only", "Line-Out+Speaker"
+               "Disabled", "Speaker Only", "Line Out+Speaker"
        };
        const char * const *texts;
 
@@ -1856,7 +1856,7 @@ static const char * const alc_slave_vols[] = {
        "Headphone Playback Volume",
        "Speaker Playback Volume",
        "Mono Playback Volume",
-       "Line-Out Playback Volume",
+       "Line Out Playback Volume",
        "CLFE Playback Volume",
        "Bass Speaker Playback Volume",
        "PCM Playback Volume",
@@ -1873,7 +1873,7 @@ static const char * const alc_slave_sws[] = {
        "Speaker Playback Switch",
        "Mono Playback Switch",
        "IEC958 Playback Switch",
-       "Line-Out Playback Switch",
+       "Line Out Playback Switch",
        "CLFE Playback Switch",
        "Bass Speaker Playback Switch",
        "PCM Playback Switch",
@@ -2068,12 +2068,16 @@ static int alc_build_controls(struct hda_codec *codec)
  */
 
 static void alc_init_special_input_src(struct hda_codec *codec);
+static int alc269_fill_coef(struct hda_codec *codec);
 
 static int alc_init(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
        unsigned int i;
 
+       if (codec->vendor_id == 0x10ec0269)
+               alc269_fill_coef(codec);
+
        alc_fix_pll(codec);
        alc_auto_init_amp(codec, spec->init_amp);
 
@@ -3797,7 +3801,7 @@ static void alc_auto_init_input_src(struct hda_codec *codec)
        else
                nums = spec->num_adc_nids;
        for (c = 0; c < nums; c++)
-               alc_mux_select(codec, 0, spec->cur_mux[c], true);
+               alc_mux_select(codec, c, spec->cur_mux[c], true);
 }
 
 /* add mic boosts if needed */
@@ -4367,6 +4371,7 @@ enum {
        ALC882_FIXUP_PB_M5210,
        ALC882_FIXUP_ACER_ASPIRE_7736,
        ALC882_FIXUP_ASUS_W90V,
+       ALC889_FIXUP_CD,
        ALC889_FIXUP_VAIO_TT,
        ALC888_FIXUP_EEE1601,
        ALC882_FIXUP_EAPD,
@@ -4494,6 +4499,13 @@ static const struct alc_fixup alc882_fixups[] = {
                        { }
                }
        },
+       [ALC889_FIXUP_CD] = {
+               .type = ALC_FIXUP_PINS,
+               .v.pins = (const struct alc_pincfg[]) {
+                       { 0x1c, 0x993301f0 }, /* CD */
+                       { }
+               }
+       },
        [ALC889_FIXUP_VAIO_TT] = {
                .type = ALC_FIXUP_PINS,
                .v.pins = (const struct alc_pincfg[]) {
@@ -4650,6 +4662,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
 
        SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC882_FIXUP_EAPD),
        SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3),
+       SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3", ALC889_FIXUP_CD),
        SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX),
        SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD),
        SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD),
@@ -5467,8 +5480,12 @@ static const struct alc_model_fixup alc269_fixup_models[] = {
 
 static int alc269_fill_coef(struct hda_codec *codec)
 {
+       struct alc_spec *spec = codec->spec;
        int val;
 
+       if (spec->codec_variant != ALC269_TYPE_ALC269VB)
+               return 0;
+
        if ((alc_get_coef0(codec) & 0x00ff) < 0x015) {
                alc_write_coef_idx(codec, 0xf, 0x960b);
                alc_write_coef_idx(codec, 0xe, 0x8817);
index 6345df131a005a7202b696ccea02fb5dbfeb0898..9dbb5735d778692c81f0010311b2958309a9fa43 100644 (file)
@@ -4629,7 +4629,7 @@ static void stac92xx_hp_detect(struct hda_codec *codec)
                unsigned int val = AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN;
                if (no_hp_sensing(spec, i))
                        continue;
-               if (presence)
+               if (1 /*presence*/)
                        stac92xx_set_pinctl(codec, cfg->hp_pins[i], val);
 #if 0 /* FIXME */
 /* Resetting the pinctl like below may lead to (a sort of) regressions
index cc9f6c83d661c93ba35926d475f11f3b85a3d354..bc030a2088da7928d0b9ebc5830fbeb743c59a37 100644 (file)
@@ -6333,6 +6333,7 @@ static int __devinit snd_hdspm_create_hwdep(struct snd_card *card,
 
        hw->ops.open = snd_hdspm_hwdep_dummy_op;
        hw->ops.ioctl = snd_hdspm_hwdep_ioctl;
+       hw->ops.ioctl_compat = snd_hdspm_hwdep_ioctl;
        hw->ops.release = snd_hdspm_hwdep_dummy_op;
 
        return 0;
index 01d1f749cf021908ead5cb27e30966a17f144ca6..b6adbed6e506c1585503dff1355b46d4afbaa4cf 100644 (file)
@@ -112,7 +112,7 @@ static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
                break;
        case SND_SOC_DAIFMT_DSP_A:
                /* data on rising edge of bclk, frame high 1clk before data */
-               strcr |= SSI_STCR_TFSL | SSI_STCR_TEFS;
+               strcr |= SSI_STCR_TFSL | SSI_STCR_TXBIT0 | SSI_STCR_TEFS;
                break;
        }
 
index c6012ff5bd3ea977cd18f5bb98e4e7e6ded82d1e..d23b19a59d8383f4b6f5aa2036699831793a762e 100644 (file)
@@ -367,7 +367,7 @@ static struct snd_soc_dai_link neo1973_dai[] = {
        .platform_name = "samsung-audio",
        .cpu_dai_name = "s3c24xx-iis",
        .codec_dai_name = "wm8753-hifi",
-       .codec_name = "wm8753-codec.0-001a",
+       .codec_name = "wm8753.0-001a",
        .init = neo1973_wm8753_init,
        .ops = &neo1973_hifi_ops,
 },
@@ -376,7 +376,7 @@ static struct snd_soc_dai_link neo1973_dai[] = {
        .stream_name = "Voice",
        .cpu_dai_name = "dfbmcs320-pcm",
        .codec_dai_name = "wm8753-voice",
-       .codec_name = "wm8753-codec.0-001a",
+       .codec_name = "wm8753.0-001a",
        .ops = &neo1973_voice_ops,
 },
 };
index 1f55ded4047f03b9a538af971c01018f0fb5df10..1315663c1c0990787f226c8358700bce5e0d7963 100644 (file)
@@ -3068,9 +3068,13 @@ static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm)
         * standby.
         */
        if (powerdown) {
-               snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_PREPARE);
+               if (dapm->bias_level == SND_SOC_BIAS_ON)
+                       snd_soc_dapm_set_bias_level(dapm,
+                                                   SND_SOC_BIAS_PREPARE);
                dapm_seq_run(dapm, &down_list, 0, false);
-               snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_STANDBY);
+               if (dapm->bias_level == SND_SOC_BIAS_PREPARE)
+                       snd_soc_dapm_set_bias_level(dapm,
+                                                   SND_SOC_BIAS_STANDBY);
        }
 }
 
@@ -3083,7 +3087,9 @@ void snd_soc_dapm_shutdown(struct snd_soc_card *card)
 
        list_for_each_entry(codec, &card->codec_dev_list, list) {
                soc_dapm_shutdown_codec(&codec->dapm);
-               snd_soc_dapm_set_bias_level(&codec->dapm, SND_SOC_BIAS_OFF);
+               if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY)
+                       snd_soc_dapm_set_bias_level(&codec->dapm,
+                                                   SND_SOC_BIAS_OFF);
        }
 }
 
index 0abfb18b911fb93f022f0e6ac1e7b4dda4fb1e4d..227b6ae99785118066a7184cc4cb66f27d38c841 100644 (file)
@@ -204,6 +204,9 @@ static void perf_record__open(struct perf_record *rec)
 
                if (opts->group && pos != first)
                        group_fd = first->fd;
+fallback_missing_features:
+               if (opts->exclude_guest_missing)
+                       attr->exclude_guest = attr->exclude_host = 0;
 retry_sample_id:
                attr->sample_id_all = opts->sample_id_all_avail ? 1 : 0;
 try_again:
@@ -217,15 +220,23 @@ try_again:
                        } else if (err ==  ENODEV && opts->cpu_list) {
                                die("No such device - did you specify"
                                        " an out-of-range profile CPU?\n");
-                       } else if (err == EINVAL && opts->sample_id_all_avail) {
-                               /*
-                                * Old kernel, no attr->sample_id_type_all field
-                                */
-                               opts->sample_id_all_avail = false;
-                               if (!opts->sample_time && !opts->raw_samples && !time_needed)
-                                       attr->sample_type &= ~PERF_SAMPLE_TIME;
-
-                               goto retry_sample_id;
+                       } else if (err == EINVAL) {
+                               if (!opts->exclude_guest_missing &&
+                                   (attr->exclude_guest || attr->exclude_host)) {
+                                       pr_debug("Old kernel, cannot exclude "
+                                                "guest or host samples.\n");
+                                       opts->exclude_guest_missing = true;
+                                       goto fallback_missing_features;
+                               } else if (opts->sample_id_all_avail) {
+                                       /*
+                                        * Old kernel, no attr->sample_id_type_all field
+                                        */
+                                       opts->sample_id_all_avail = false;
+                                       if (!opts->sample_time && !opts->raw_samples && !time_needed)
+                                               attr->sample_type &= ~PERF_SAMPLE_TIME;
+
+                                       goto retry_sample_id;
+                               }
                        }
 
                        /*
@@ -503,9 +514,9 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
                        return err;
        }
 
-       if (!!rec->no_buildid
+       if (!rec->no_buildid
            && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
-               pr_err("Couldn't generating buildids. "
+               pr_err("Couldn't generate buildids. "
                       "Use --no-buildid to profile anyway.\n");
                return -1;
        }
index dd162aa24baad2f44c5cbb1b4176fb2b2cc7b26d..ecff31257eb3771cf9db12acc49065e40e2c4d18 100644 (file)
@@ -857,6 +857,9 @@ static void perf_top__start_counters(struct perf_top *top)
                attr->mmap = 1;
                attr->comm = 1;
                attr->inherit = top->inherit;
+fallback_missing_features:
+               if (top->exclude_guest_missing)
+                       attr->exclude_guest = attr->exclude_host = 0;
 retry_sample_id:
                attr->sample_id_all = top->sample_id_all_avail ? 1 : 0;
 try_again:
@@ -868,12 +871,20 @@ try_again:
                        if (err == EPERM || err == EACCES) {
                                ui__error_paranoid();
                                goto out_err;
-                       } else if (err == EINVAL && top->sample_id_all_avail) {
-                               /*
-                                * Old kernel, no attr->sample_id_type_all field
-                                */
-                               top->sample_id_all_avail = false;
-                               goto retry_sample_id;
+                       } else if (err == EINVAL) {
+                               if (!top->exclude_guest_missing &&
+                                   (attr->exclude_guest || attr->exclude_host)) {
+                                       pr_debug("Old kernel, cannot exclude "
+                                                "guest or host samples.\n");
+                                       top->exclude_guest_missing = true;
+                                       goto fallback_missing_features;
+                               } else if (top->sample_id_all_avail) {
+                                       /*
+                                        * Old kernel, no attr->sample_id_type_all field
+                                        */
+                                       top->sample_id_all_avail = false;
+                                       goto retry_sample_id;
+                               }
                        }
                        /*
                         * If it's cycles then fall back to hrtimer
index 64f8bee31ced8d7eb3586788e4a69f872c33e57a..16e7d20eee8321110797f9f77c928c1e15e013ea 100644 (file)
@@ -199,6 +199,7 @@ struct perf_record_opts {
        bool         sample_address;
        bool         sample_time;
        bool         sample_id_all_avail;
+       bool         exclude_guest_missing;
        bool         system_wide;
        bool         period;
        unsigned int freq;
index 2044324b755a51bc9b41536957dce8b35a11a6fd..2a6f33cd888ca7d7e9dbe7d27f6999a552dec7f1 100644 (file)
@@ -74,6 +74,7 @@ static pid_t perf_event__get_comm_tgid(pid_t pid, char *comm, size_t len)
                        if (size >= len)
                                size = len - 1;
                        memcpy(comm, name, size);
+                       comm[size] = '\0';
 
                } else if (memcmp(bf, "Tgid:", 5) == 0) {
                        char *tgids = bf + 5;
index 3f16e08a5c8de740a3149879274dd69af720c97e..ea32a061f1c88e9ee4cf63d9019dc50451a43e0a 100644 (file)
@@ -349,6 +349,10 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
        hlist_for_each_entry(sid, pos, head, node)
                if (sid->id == id)
                        return sid->evsel;
+
+       if (!perf_evlist__sample_id_all(evlist))
+               return list_entry(evlist->entries.next, struct perf_evsel, node);
+
        return NULL;
 }
 
index 29cb654598113a66729a17b9bd00ff21da8c52d8..e33554a562b36fb59c95d935258d525a0e810dac 100644 (file)
@@ -1867,6 +1867,12 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
                           tev->point.symbol);
                ret = -ENOENT;
                goto error;
+       } else if (tev->point.offset > sym->end - sym->start) {
+               pr_warning("Offset specified is greater than size of %s\n",
+                          tev->point.symbol);
+               ret = -ENOENT;
+               goto error;
+
        }
 
        return 1;
index 5d732621a462f31a57d9aa966fe80e23edacf4b8..74bd2e63c4b4a7458989a08cc731c15edfb99c98 100644 (file)
@@ -672,7 +672,7 @@ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf)
 static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr,
                                  bool retprobe, struct probe_trace_point *tp)
 {
-       Dwarf_Addr eaddr;
+       Dwarf_Addr eaddr, highaddr;
        const char *name;
 
        /* Copy the name of probe point */
@@ -683,6 +683,16 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr,
                                   dwarf_diename(sp_die));
                        return -ENOENT;
                }
+               if (dwarf_highpc(sp_die, &highaddr) != 0) {
+                       pr_warning("Failed to get end address of %s\n",
+                                  dwarf_diename(sp_die));
+                       return -ENOENT;
+               }
+               if (paddr > highaddr) {
+                       pr_warning("Offset specified is greater than size of %s\n",
+                                  dwarf_diename(sp_die));
+                       return -EINVAL;
+               }
                tp->symbol = strdup(name);
                if (tp->symbol == NULL)
                        return -ENOMEM;
index a248f3c2c60d9bb730f5603e1b87fcb04160cb6a..f2eab81435ae1b4bf3ffaaedb3734e7e953b492b 100644 (file)
@@ -34,6 +34,7 @@ struct perf_top {
        bool               inherit;
        bool               group;
        bool               sample_id_all_avail;
+       bool               exclude_guest_missing;
        bool               dump_symtab;
        const char         *cpu_list;
        struct hist_entry  *sym_filter_entry;
index 813141047fc22fcfd61ae377444f7ff2a97f06eb..fb25d132921882c3b432ece1bc07bd2700800bc2 100644 (file)
@@ -6,7 +6,7 @@
  * XXX We need to find a better place for these things...
  */
 bool perf_host  = true;
-bool perf_guest = true;
+bool perf_guest = false;
 
 void event_attr_init(struct perf_event_attr *attr)
 {
index 62a134dc421ae37d14307a44f09abc9c0d0c197a..9507c4b251a8e370ae5419ff38f51b9f6ea8d5a0 100755 (executable)
@@ -3244,9 +3244,11 @@ sub make_min_config {
        $in_bisect = 1;
 
        my $failed = 0;
-       build "oldconfig";
-       start_monitor_and_boot or $failed = 1;
-       end_monitor;
+       build "oldconfig" or $failed = 1;
+       if (!$failed) {
+               start_monitor_and_boot or $failed = 1;
+               end_monitor;
+       }
 
        $in_bisect = 0;